Re #1474: Merged all changes from 1.12 - HEAD (from the 1.x branch)

git-svn-id: https://svn.pjsip.org/repos/pjproject/trunk@3999 74dad513-b988-da41-8d7b-12977e46ad98
This commit is contained in:
Benny Prijono 2012-03-30 07:10:13 +00:00
parent fb28b6a7ac
commit 28d3c56283
56 changed files with 4777 additions and 10557 deletions

13246
aconfigure

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
AC_INIT(pjproject,1.x)
AC_INIT(pjproject,2.x)
host_orig="$host"
@ -92,6 +92,19 @@ case $host in
;;
esac
AC_SUBST(ac_shlib_suffix)
case $target in
*mingw* | *cygw* | *win32* | *w32* )
ac_shlib_suffix=dll
;;
*darwin*)
ac_shlib_suffix=dylib
;;
*)
ac_shlib_suffix=so
;;
esac
AC_CHECK_LIB(pthread,pthread_create)
AC_CHECK_LIB(wsock32,puts)
AC_CHECK_LIB(ws2_32,puts)
@ -774,6 +787,18 @@ AC_ARG_ENABLE(libsamplerate,
AC_MSG_RESULT([Skipping libsamplerate detection])
)
dnl # Include libsamplerate
AC_SUBST(ac_resample_dll)
AC_ARG_ENABLE(resample_dll,
AC_HELP_STRING([--enable-resample-dll],
[Build libresample as shared library]),
[if test "$enable_resample_dll" = "yes"; then
[ac_resample_dll=1]
AC_MSG_RESULT([Building libresample as shared library... yes])
fi],
AC_MSG_RESULT([Building libresample as shared library... no])
)
dnl # SDL alt prefix
AC_ARG_WITH(sdl,
AC_HELP_STRING([--with-sdl=DIR],
@ -1216,7 +1241,6 @@ AC_ARG_ENABLE(opencore_amrnb,
fi
])
dnl ##########################################
dnl #
dnl # MANUAL CONFIG

View File

@ -1,3 +1,7 @@
export PJDIR := @ac_pjdir@
include $(PJDIR)/version.mak
export PJ_DIR := $(PJDIR)
# @configure_input@
export MACHINE_NAME := auto
export OS_NAME := auto
@ -6,15 +10,25 @@ export CC_NAME := gcc
export TARGET_NAME := @target@
export CROSS_COMPILE := @ac_cross_compile@
export LINUX_POLL := @ac_linux_poll@
export SHLIB_SUFFIX := @ac_shlib_suffix@
export ac_prefix := @prefix@
LIB_SUFFIX = $(TARGET_NAME).a
# Determine which party libraries to use
export APP_THIRD_PARTY_LIBS := -lresample-$(TARGET_NAME) -lmilenage-$(TARGET_NAME) -lsrtp-$(TARGET_NAME)
export APP_THIRD_PARTY_LIBS := -lmilenage-$(TARGET_NAME) -lsrtp-$(TARGET_NAME)
export APP_THIRD_PARTY_EXT :=
export APP_THIRD_PARTY_LIB_FILES = $(PJ_DIR)/third_party/lib/libresample-$(LIB_SUFFIX) $(PJ_DIR)/third_party/lib/libmilenage-$(LIB_SUFFIX) $(PJ_DIR)/third_party/lib/libsrtp-$(LIB_SUFFIX)
export APP_THIRD_PARTY_LIB_FILES := $(PJ_DIR)/third_party/lib/libmilenage-$(LIB_SUFFIX) $(PJ_DIR)/third_party/lib/libsrtp-$(LIB_SUFFIX)
ifeq (@ac_resample_dll@,1)
export PJ_RESAMPLE_DLL := 1
export APP_THIRD_PARTY_LIBS := -lresample $(APP_THIRD_PARTY_LIBS)
export APP_THIRD_PARTY_LIB_FILES := $(PJ_DIR)/third_party/lib/libresample.$(SHLIB_SUFFIX).$(PJ_VERSION_MAJOR) $(PJ_DIR)/third_party/lib/libresample.$(SHLIB_SUFFIX) $(APP_THIRD_PARTY_LIB_FILES)
else
export APP_THIRD_PARTY_LIBS := -lresample-$(TARGET_NAME) $(APP_THIRD_PARTY_LIBS)
export APP_THIRD_PARTY_LIB_FILES := $(PJ_DIR)/third_party/lib/libresample-$(LIB_SUFFIX) $(APP_THIRD_PARTY_LIB_FILES)
endif
ifneq (@ac_no_gsm_codec@,1)
ifeq (@ac_external_gsm@,1)
@ -89,7 +103,6 @@ PJ_VIDEO_LDFLAGS += $(SDL_LDFLAGS) $(FFMPEG_LDFLAGS) $(V4L2_LDFLAGS)
# CFLAGS, LDFLAGS, and LIBS to be used by applications
export PJDIR := @ac_pjdir@
export APP_CC := @CC@
export APP_CXX := @CXX@
export APP_CFLAGS := -DPJ_AUTOCONF=1\
@ -138,7 +151,6 @@ export APP_LIB_FILES = $(PJ_DIR)/pjsip/lib/libpjsua-$(LIB_SUFFIX) \
# Here are the variabels to use if application is using the library
# from within the source distribution
export PJ_DIR := $(PJDIR)
export PJ_CC := $(APP_CC)
export PJ_CXX := $(APP_CXX)
export PJ_CFLAGS := $(APP_CFLAGS)

View File

@ -10,6 +10,11 @@ endif
#
LIB = $($(APP)_LIB)
#
# The full path of output lib file (e.g. ../lib/libapp.a).
#
SHLIB = $($(APP)_SHLIB)
#
# The full path of output executable file (e.g. ../bin/app.exe).
#
@ -82,6 +87,11 @@ $(LIB): $(OBJDIRS) $(OBJS) $($(APP)_EXTRA_DEP)
$(AR) $(LIB) $(OBJS)
$(RANLIB) $(LIB)
$(SHLIB): $(OBJDIRS) $(OBJS) $($(APP)_EXTRA_DEP)
if test ! -d $(LIBDIR); then $(subst @@,$(subst /,$(HOST_PSEP),$(LIBDIR)),$(HOST_MKDIR)); fi
$(LD) $(LDOUT)$(subst /,$(HOST_PSEP),$(SHLIB)) \
$(subst /,$(HOST_PSEP),$(OBJS)) $($(APP)_LDFLAGS)
$(EXE): $(OBJDIRS) $(OBJS) $($(APP)_EXTRA_DEP)
if test ! -d $(BINDIR); then $(subst @@,$(subst /,$(HOST_PSEP),$(BINDIR)),$(HOST_MKDIR)); fi
$(LD) $(LDOUT)$(subst /,$(HOST_PSEP),$(EXE)) \

View File

@ -25,7 +25,10 @@ fi
# Set the main iPhone developer directory, if not set
if test "x${DEVPATH}" = "x"; then
DEVPATH=/Developer/Platforms/iPhoneOS.platform/Developer
DEVPATH=/Applications/XCode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer
if test ! -d $DEVPATH; then
DEVPATH=/Developer/Platforms/iPhoneOS.platform/Developer
fi
echo "$F: DEVPATH is not specified, using ${DEVPATH}"
fi

View File

@ -44,7 +44,7 @@ PJ_DEF(pj_status_t) pjstun_get_mapped_addr( pj_pool_factory *pf,
{
unsigned srv_cnt;
pj_sockaddr_in srv_addr[2];
int i, send_cnt = 0;
int i, send_cnt = 0, nfds;
pj_pool_t *pool;
struct query_rec {
struct {
@ -113,6 +113,17 @@ PJ_DEF(pj_status_t) pjstun_get_mapped_addr( pj_pool_factory *pf,
TRACE_((THIS_FILE, " Done initialization."));
#if defined(PJ_SELECT_NEEDS_NFDS) && PJ_SELECT_NEEDS_NFDS!=0
nfds = -1;
for (i=0; i<sock_cnt; ++i) {
if (sock[i] > nfds) {
nfds = sock[i];
}
}
#else
nfds = PJ_IOQUEUE_MAX_HANDLES-1;
#endif
/* Main retransmission loop. */
for (send_cnt=0; send_cnt<MAX_REQUEST; ++send_cnt) {
pj_time_val next_tx, now;
@ -170,7 +181,7 @@ PJ_DEF(pj_status_t) pjstun_get_mapped_addr( pj_pool_factory *pf,
PJ_FD_SET(sock[i], &r);
}
select_rc = pj_sock_select(PJ_IOQUEUE_MAX_HANDLES, &r, NULL, NULL, &timeout);
select_rc = pj_sock_select(nfds+1, &r, NULL, NULL, &timeout);
TRACE_((THIS_FILE, " select() rc=%d", select_rc));
if (select_rc < 1)
continue;

View File

@ -100,13 +100,13 @@ static pj_xml_node *xml_parse_node( pj_pool_t *pool, pj_scanner *scanner)
pj_scan_get_char(scanner);
/* Get node name. */
pj_scan_get_until_chr( scanner, " />\t", &node->name);
pj_scan_get_until_chr( scanner, " />\t\r\n", &node->name);
/* Get attributes. */
while (*scanner->curptr != '>' && *scanner->curptr != '/') {
pj_xml_attr *attr = alloc_attr(pool);
pj_scan_get_until_chr( scanner, "=> \t", &attr->name);
pj_scan_get_until_chr( scanner, "=> \t\r\n", &attr->name);
if (*scanner->curptr == '=') {
pj_scan_get_char( scanner );
pj_scan_get_quotes(scanner, "\"'", "\"'", 2, &attr->value);

View File

@ -331,16 +331,38 @@ PJ_DECL(pj_status_t) pj_ssl_cipher_get_availables(pj_ssl_cipher ciphers[],
unsigned *cipher_num);
/**
* Check if the specified cipher is supported by SSL/TLS backend.
*
* @param cipher The cipher.
*
* @return PJ_TRUE when supported.
*/
PJ_DECL(pj_bool_t) pj_ssl_cipher_is_supported(pj_ssl_cipher cipher);
/**
* Get cipher name string.
*
* @param cipher The cipher.
*
* @return The cipher name or NULL if cipher is not recognized.
* @return The cipher name or NULL if cipher is not recognized/
* supported.
*/
PJ_DECL(const char*) pj_ssl_cipher_name(pj_ssl_cipher cipher);
/**
* Get cipher ID from cipher name string.
*
* @param cipher_name The cipher name string.
*
* @return The cipher ID or PJ_TLS_UNKNOWN_CIPHER if the cipher
* name string is not recognized/supported.
*/
PJ_DECL(pj_ssl_cipher) pj_ssl_cipher_id(const char *cipher_name);
/**
* This structure contains the callbacks to be called by the secure socket.
*/

View File

@ -290,6 +290,9 @@ typedef int pj_exception_id_t;
* in random string generation, and to initialize operating system dependent
* functionality (such as WSAStartup() in Windows).
*
* Apart from calling pj_init(), application typically should also initialize
* the random seed by calling pj_srand().
*
* @return PJ_SUCCESS on success.
*/
PJ_DECL(pj_status_t) pj_init(void);

View File

@ -75,6 +75,9 @@ struct pj_sem_t
int max;
};
/* Flag and reference counter for PJLIB instance */
static int initialized;
/* Flags to indicate which TLS variables have been used */
static int tls_vars[PJ_MAX_TLS];
@ -83,8 +86,6 @@ static unsigned atexit_count;
static void (*atexit_func[32])(void);
/////////////////////////////////////////////////////////////////////////////
//
// CPjTimeoutTimer implementation
@ -335,6 +336,12 @@ PJ_DEF(pj_status_t) pj_init(void)
char stack_ptr;
pj_status_t status;
/* Check if PJLIB have been initialized */
if (initialized) {
++initialized;
return PJ_SUCCESS;
}
pj_ansi_strcpy(main_thread.obj_name, "pjthread");
// Init main thread
@ -368,6 +375,10 @@ PJ_DEF(pj_status_t) pj_init(void)
stack_ptr = '\0';
#endif
/* Flag PJLIB as initialized */
++initialized;
pj_assert(initialized == 1);
PJ_LOG(5,(THIS_FILE, "PJLIB initialized."));
return PJ_SUCCESS;
@ -390,6 +401,11 @@ PJ_DEF(pj_status_t) pj_atexit(pj_exit_callback func)
PJ_DEF(void) pj_shutdown(void)
{
/* Only perform shutdown operation when 'initialized' reaches zero */
pj_assert(initialized > 0);
if (--initialized != 0)
return;
/* Call atexit() functions */
while (atexit_count > 0) {
(*atexit_func[atexit_count-1])();

View File

@ -102,6 +102,11 @@ struct pj_event_t
#endif /* PJ_HAS_EVENT_OBJ */
/*
* Flag and reference counter for PJLIB instance.
*/
static int initialized;
#if PJ_HAS_THREADS
static pj_thread_t main_thread;
static long thread_tls_id;
@ -127,6 +132,12 @@ PJ_DEF(pj_status_t) pj_init(void)
pj_str_t guid;
pj_status_t rc;
/* Check if PJLIB have been initialized */
if (initialized) {
++initialized;
return PJ_SUCCESS;
}
#if PJ_HAS_THREADS
/* Init this thread's TLS. */
if ((rc=pj_thread_init()) != 0) {
@ -167,6 +178,10 @@ PJ_DEF(pj_status_t) pj_init(void)
}
#endif
/* Flag PJLIB as initialized */
++initialized;
pj_assert(initialized == 1);
PJ_LOG(4,(THIS_FILE, "pjlib %s for POSIX initialized",
PJ_VERSION));
@ -192,6 +207,11 @@ PJ_DEF(void) pj_shutdown()
{
int i;
/* Only perform shutdown operation when 'initialized' reaches zero */
pj_assert(initialized > 0);
if (--initialized != 0)
return;
/* Call atexit() functions */
for (i=atexit_count-1; i>=0; --i) {
(*atexit_func[i])();

View File

@ -116,6 +116,11 @@ struct pj_atomic_t
long value;
};
/*
* Flag and reference counter for PJLIB instance.
*/
static int initialized;
/*
* Static global variables.
*/
@ -142,6 +147,12 @@ PJ_DEF(pj_status_t) pj_init(void)
pj_str_t guid;
pj_status_t rc;
/* Check if PJLIB have been initialized */
if (initialized) {
++initialized;
return PJ_SUCCESS;
}
/* Init Winsock.. */
if (WSAStartup(MAKEWORD(2,0), &wsa) != 0) {
return PJ_RETURN_OS_ERROR(WSAGetLastError());
@ -187,6 +198,10 @@ PJ_DEF(pj_status_t) pj_init(void)
}
#endif
/* Flag PJLIB as initialized */
++initialized;
pj_assert(initialized == 1);
PJ_LOG(4,(THIS_FILE, "pjlib %s for win32 initialized",
PJ_VERSION));
@ -213,6 +228,11 @@ PJ_DEF(void) pj_shutdown()
{
int i;
/* Only perform shutdown operation when 'initialized' reaches zero */
pj_assert(initialized > 0);
if (--initialized != 0)
return;
/* Display stack usage */
#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
{

View File

@ -21,89 +21,6 @@
#include <pj/errno.h>
#include <pj/string.h>
/* Cipher name structure */
typedef struct cipher_name_t {
pj_ssl_cipher cipher;
const char *name;
} cipher_name_t;
/* Cipher name constants */
static cipher_name_t cipher_names[] =
{
{PJ_TLS_NULL_WITH_NULL_NULL, "NULL"},
/* TLS/SSLv3 */
{PJ_TLS_RSA_WITH_NULL_MD5, "TLS_RSA_WITH_NULL_MD5"},
{PJ_TLS_RSA_WITH_NULL_SHA, "TLS_RSA_WITH_NULL_SHA"},
{PJ_TLS_RSA_WITH_NULL_SHA256, "TLS_RSA_WITH_NULL_SHA256"},
{PJ_TLS_RSA_WITH_RC4_128_MD5, "TLS_RSA_WITH_RC4_128_MD5"},
{PJ_TLS_RSA_WITH_RC4_128_SHA, "TLS_RSA_WITH_RC4_128_SHA"},
{PJ_TLS_RSA_WITH_3DES_EDE_CBC_SHA, "TLS_RSA_WITH_3DES_EDE_CBC_SHA"},
{PJ_TLS_RSA_WITH_AES_128_CBC_SHA, "TLS_RSA_WITH_AES_128_CBC_SHA"},
{PJ_TLS_RSA_WITH_AES_256_CBC_SHA, "TLS_RSA_WITH_AES_256_CBC_SHA"},
{PJ_TLS_RSA_WITH_AES_128_CBC_SHA256, "TLS_RSA_WITH_AES_128_CBC_SHA256"},
{PJ_TLS_RSA_WITH_AES_256_CBC_SHA256, "TLS_RSA_WITH_AES_256_CBC_SHA256"},
{PJ_TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA, "TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA"},
{PJ_TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA, "TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA"},
{PJ_TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA, "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA"},
{PJ_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA"},
{PJ_TLS_DH_DSS_WITH_AES_128_CBC_SHA, "TLS_DH_DSS_WITH_AES_128_CBC_SHA"},
{PJ_TLS_DH_RSA_WITH_AES_128_CBC_SHA, "TLS_DH_RSA_WITH_AES_128_CBC_SHA"},
{PJ_TLS_DHE_DSS_WITH_AES_128_CBC_SHA, "TLS_DHE_DSS_WITH_AES_128_CBC_SHA"},
{PJ_TLS_DHE_RSA_WITH_AES_128_CBC_SHA, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA"},
{PJ_TLS_DH_DSS_WITH_AES_256_CBC_SHA, "TLS_DH_DSS_WITH_AES_256_CBC_SHA"},
{PJ_TLS_DH_RSA_WITH_AES_256_CBC_SHA, "TLS_DH_RSA_WITH_AES_256_CBC_SHA"},
{PJ_TLS_DHE_DSS_WITH_AES_256_CBC_SHA, "TLS_DHE_DSS_WITH_AES_256_CBC_SHA"},
{PJ_TLS_DHE_RSA_WITH_AES_256_CBC_SHA, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA"},
{PJ_TLS_DH_DSS_WITH_AES_128_CBC_SHA256, "TLS_DH_DSS_WITH_AES_128_CBC_SHA256"},
{PJ_TLS_DH_RSA_WITH_AES_128_CBC_SHA256, "TLS_DH_RSA_WITH_AES_128_CBC_SHA256"},
{PJ_TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256"},
{PJ_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256"},
{PJ_TLS_DH_DSS_WITH_AES_256_CBC_SHA256, "TLS_DH_DSS_WITH_AES_256_CBC_SHA256"},
{PJ_TLS_DH_RSA_WITH_AES_256_CBC_SHA256, "TLS_DH_RSA_WITH_AES_256_CBC_SHA256"},
{PJ_TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256"},
{PJ_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256"},
{PJ_TLS_DH_anon_WITH_RC4_128_MD5, "TLS_DH_anon_WITH_RC4_128_MD5"},
{PJ_TLS_DH_anon_WITH_3DES_EDE_CBC_SHA, "TLS_DH_anon_WITH_3DES_EDE_CBC_SHA"},
{PJ_TLS_DH_anon_WITH_AES_128_CBC_SHA, "TLS_DH_anon_WITH_AES_128_CBC_SHA"},
{PJ_TLS_DH_anon_WITH_AES_256_CBC_SHA, "TLS_DH_anon_WITH_AES_256_CBC_SHA"},
{PJ_TLS_DH_anon_WITH_AES_128_CBC_SHA256, "TLS_DH_anon_WITH_AES_128_CBC_SHA256"},
{PJ_TLS_DH_anon_WITH_AES_256_CBC_SHA256, "TLS_DH_anon_WITH_AES_256_CBC_SHA256"},
/* TLS (deprecated) */
{PJ_TLS_RSA_EXPORT_WITH_RC4_40_MD5, "TLS_RSA_EXPORT_WITH_RC4_40_MD5"},
{PJ_TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5, "TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5"},
{PJ_TLS_RSA_WITH_IDEA_CBC_SHA, "TLS_RSA_WITH_IDEA_CBC_SHA"},
{PJ_TLS_RSA_EXPORT_WITH_DES40_CBC_SHA, "TLS_RSA_EXPORT_WITH_DES40_CBC_SHA"},
{PJ_TLS_RSA_WITH_DES_CBC_SHA, "TLS_RSA_WITH_DES_CBC_SHA"},
{PJ_TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA, "TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA"},
{PJ_TLS_DH_DSS_WITH_DES_CBC_SHA, "TLS_DH_DSS_WITH_DES_CBC_SHA"},
{PJ_TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA, "TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA"},
{PJ_TLS_DH_RSA_WITH_DES_CBC_SHA, "TLS_DH_RSA_WITH_DES_CBC_SHA"},
{PJ_TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA, "TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA"},
{PJ_TLS_DHE_DSS_WITH_DES_CBC_SHA, "TLS_DHE_DSS_WITH_DES_CBC_SHA"},
{PJ_TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA, "TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA"},
{PJ_TLS_DHE_RSA_WITH_DES_CBC_SHA, "TLS_DHE_RSA_WITH_DES_CBC_SHA"},
{PJ_TLS_DH_anon_EXPORT_WITH_RC4_40_MD5, "TLS_DH_anon_EXPORT_WITH_RC4_40_MD5"},
{PJ_TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA, "TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA"},
{PJ_TLS_DH_anon_WITH_DES_CBC_SHA, "TLS_DH_anon_WITH_DES_CBC_SHA"},
/* SSLv3 */
{PJ_SSL_FORTEZZA_KEA_WITH_NULL_SHA, "SSL_FORTEZZA_KEA_WITH_NULL_SHA"},
{PJ_SSL_FORTEZZA_KEA_WITH_FORTEZZA_CBC_SHA,"SSL_FORTEZZA_KEA_WITH_FORTEZZA_CBC_SHA"},
{PJ_SSL_FORTEZZA_KEA_WITH_RC4_128_SHA, "SSL_FORTEZZA_KEA_WITH_RC4_128_SHA"},
/* SSLv2 */
{PJ_SSL_CK_RC4_128_WITH_MD5, "SSL_CK_RC4_128_WITH_MD5"},
{PJ_SSL_CK_RC4_128_EXPORT40_WITH_MD5, "SSL_CK_RC4_128_EXPORT40_WITH_MD5"},
{PJ_SSL_CK_RC2_128_CBC_WITH_MD5, "SSL_CK_RC2_128_CBC_WITH_MD5"},
{PJ_SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5, "SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5"},
{PJ_SSL_CK_IDEA_128_CBC_WITH_MD5, "SSL_CK_IDEA_128_CBC_WITH_MD5"},
{PJ_SSL_CK_DES_64_CBC_WITH_MD5, "SSL_CK_DES_64_CBC_WITH_MD5"},
{PJ_SSL_CK_DES_192_EDE3_CBC_WITH_MD5, "SSL_CK_DES_192_EDE3_CBC_WITH_MD5"}
};
/*
* Initialize the SSL socket configuration with the default values.
*/
@ -129,23 +46,6 @@ PJ_DEF(void) pj_ssl_sock_param_default(pj_ssl_sock_param *param)
}
/* Get cipher name string */
PJ_DEF(const char*) pj_ssl_cipher_name(pj_ssl_cipher cipher)
{
unsigned i, n;
n = PJ_ARRAY_SIZE(cipher_names);
for (i = 0; i < n; ++i) {
if (cipher == cipher_names[i].cipher)
return cipher_names[i].name;
}
return NULL;
}
PJ_DEF(pj_status_t) pj_ssl_cert_get_verify_status_strings(
pj_uint32_t verify_status,
const char *error_strings[],

View File

@ -39,6 +39,9 @@
/* Workaround for ticket #985 */
#define DELAYED_CLOSE_TIMEOUT 200
/* Maximum ciphers */
#define MAX_CIPHERS 100
/*
* Include OpenSSL headers
*/
@ -269,8 +272,11 @@ static pj_str_t ssl_strerror(pj_status_t status,
static int openssl_init_count;
/* OpenSSL available ciphers */
static pj_ssl_cipher openssl_ciphers[100];
static unsigned openssl_cipher_num;
static struct openssl_ciphers_t {
pj_ssl_cipher id;
const char *name;
} openssl_ciphers[MAX_CIPHERS];
/* OpenSSL application data index */
static int sslsock_idx;
@ -329,9 +335,9 @@ static pj_status_t init_openssl(void)
for (i = 0; i < n; ++i) {
SSL_CIPHER *c;
c = sk_SSL_CIPHER_value(sk_cipher,i);
openssl_ciphers[i] = (pj_ssl_cipher)
(pj_uint32_t)c->id & 0x00FFFFFF;
//printf("%3u: %08x=%s\n", i+1, c->id, SSL_CIPHER_get_name(c));
openssl_ciphers[i].id = (pj_ssl_cipher)
(pj_uint32_t)c->id & 0x00FFFFFF;
openssl_ciphers[i].name = SSL_CIPHER_get_name(c);
}
SSL_free(ssl);
@ -1705,18 +1711,57 @@ PJ_DEF(pj_status_t) pj_ssl_cipher_get_availables(pj_ssl_cipher ciphers[],
shutdown_openssl();
}
if (openssl_cipher_num == 0)
if (openssl_cipher_num == 0) {
*cipher_num = 0;
return PJ_ENOTFOUND;
}
*cipher_num = PJ_MIN(*cipher_num, openssl_cipher_num);
for (i = 0; i < *cipher_num; ++i)
ciphers[i] = openssl_ciphers[i];
ciphers[i] = openssl_ciphers[i].id;
return PJ_SUCCESS;
}
/* Get cipher name string */
PJ_DEF(const char*) pj_ssl_cipher_name(pj_ssl_cipher cipher)
{
unsigned i;
if (openssl_cipher_num == 0) {
init_openssl();
shutdown_openssl();
}
for (i = 0; i < openssl_cipher_num; ++i) {
if (cipher == openssl_ciphers[i].id)
return openssl_ciphers[i].name;
}
return NULL;
}
/* Check if the specified cipher is supported by SSL/TLS backend. */
PJ_DEF(pj_bool_t) pj_ssl_cipher_is_supported(pj_ssl_cipher cipher)
{
unsigned i;
if (openssl_cipher_num == 0) {
init_openssl();
shutdown_openssl();
}
for (i = 0; i < openssl_cipher_num; ++i) {
if (cipher == openssl_ciphers[i].id)
return PJ_TRUE;
}
return PJ_FALSE;
}
/*
* Create SSL socket instance.
*/

View File

@ -32,6 +32,104 @@
#define THIS_FILE "ssl_sock_symbian.cpp"
/* Cipher name structure */
typedef struct cipher_name_t {
pj_ssl_cipher cipher;
const char *name;
} cipher_name_t;
/* Cipher name constants */
static cipher_name_t cipher_names[] =
{
{PJ_TLS_NULL_WITH_NULL_NULL, "NULL"},
/* TLS/SSLv3 */
{PJ_TLS_RSA_WITH_NULL_MD5, "TLS_RSA_WITH_NULL_MD5"},
{PJ_TLS_RSA_WITH_NULL_SHA, "TLS_RSA_WITH_NULL_SHA"},
{PJ_TLS_RSA_WITH_NULL_SHA256, "TLS_RSA_WITH_NULL_SHA256"},
{PJ_TLS_RSA_WITH_RC4_128_MD5, "TLS_RSA_WITH_RC4_128_MD5"},
{PJ_TLS_RSA_WITH_RC4_128_SHA, "TLS_RSA_WITH_RC4_128_SHA"},
{PJ_TLS_RSA_WITH_3DES_EDE_CBC_SHA, "TLS_RSA_WITH_3DES_EDE_CBC_SHA"},
{PJ_TLS_RSA_WITH_AES_128_CBC_SHA, "TLS_RSA_WITH_AES_128_CBC_SHA"},
{PJ_TLS_RSA_WITH_AES_256_CBC_SHA, "TLS_RSA_WITH_AES_256_CBC_SHA"},
{PJ_TLS_RSA_WITH_AES_128_CBC_SHA256, "TLS_RSA_WITH_AES_128_CBC_SHA256"},
{PJ_TLS_RSA_WITH_AES_256_CBC_SHA256, "TLS_RSA_WITH_AES_256_CBC_SHA256"},
{PJ_TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA, "TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA"},
{PJ_TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA, "TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA"},
{PJ_TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA, "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA"},
{PJ_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA"},
{PJ_TLS_DH_DSS_WITH_AES_128_CBC_SHA, "TLS_DH_DSS_WITH_AES_128_CBC_SHA"},
{PJ_TLS_DH_RSA_WITH_AES_128_CBC_SHA, "TLS_DH_RSA_WITH_AES_128_CBC_SHA"},
{PJ_TLS_DHE_DSS_WITH_AES_128_CBC_SHA, "TLS_DHE_DSS_WITH_AES_128_CBC_SHA"},
{PJ_TLS_DHE_RSA_WITH_AES_128_CBC_SHA, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA"},
{PJ_TLS_DH_DSS_WITH_AES_256_CBC_SHA, "TLS_DH_DSS_WITH_AES_256_CBC_SHA"},
{PJ_TLS_DH_RSA_WITH_AES_256_CBC_SHA, "TLS_DH_RSA_WITH_AES_256_CBC_SHA"},
{PJ_TLS_DHE_DSS_WITH_AES_256_CBC_SHA, "TLS_DHE_DSS_WITH_AES_256_CBC_SHA"},
{PJ_TLS_DHE_RSA_WITH_AES_256_CBC_SHA, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA"},
{PJ_TLS_DH_DSS_WITH_AES_128_CBC_SHA256, "TLS_DH_DSS_WITH_AES_128_CBC_SHA256"},
{PJ_TLS_DH_RSA_WITH_AES_128_CBC_SHA256, "TLS_DH_RSA_WITH_AES_128_CBC_SHA256"},
{PJ_TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256"},
{PJ_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256"},
{PJ_TLS_DH_DSS_WITH_AES_256_CBC_SHA256, "TLS_DH_DSS_WITH_AES_256_CBC_SHA256"},
{PJ_TLS_DH_RSA_WITH_AES_256_CBC_SHA256, "TLS_DH_RSA_WITH_AES_256_CBC_SHA256"},
{PJ_TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256"},
{PJ_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256"},
{PJ_TLS_DH_anon_WITH_RC4_128_MD5, "TLS_DH_anon_WITH_RC4_128_MD5"},
{PJ_TLS_DH_anon_WITH_3DES_EDE_CBC_SHA, "TLS_DH_anon_WITH_3DES_EDE_CBC_SHA"},
{PJ_TLS_DH_anon_WITH_AES_128_CBC_SHA, "TLS_DH_anon_WITH_AES_128_CBC_SHA"},
{PJ_TLS_DH_anon_WITH_AES_256_CBC_SHA, "TLS_DH_anon_WITH_AES_256_CBC_SHA"},
{PJ_TLS_DH_anon_WITH_AES_128_CBC_SHA256, "TLS_DH_anon_WITH_AES_128_CBC_SHA256"},
{PJ_TLS_DH_anon_WITH_AES_256_CBC_SHA256, "TLS_DH_anon_WITH_AES_256_CBC_SHA256"},
/* TLS (deprecated) */
{PJ_TLS_RSA_EXPORT_WITH_RC4_40_MD5, "TLS_RSA_EXPORT_WITH_RC4_40_MD5"},
{PJ_TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5, "TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5"},
{PJ_TLS_RSA_WITH_IDEA_CBC_SHA, "TLS_RSA_WITH_IDEA_CBC_SHA"},
{PJ_TLS_RSA_EXPORT_WITH_DES40_CBC_SHA, "TLS_RSA_EXPORT_WITH_DES40_CBC_SHA"},
{PJ_TLS_RSA_WITH_DES_CBC_SHA, "TLS_RSA_WITH_DES_CBC_SHA"},
{PJ_TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA, "TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA"},
{PJ_TLS_DH_DSS_WITH_DES_CBC_SHA, "TLS_DH_DSS_WITH_DES_CBC_SHA"},
{PJ_TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA, "TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA"},
{PJ_TLS_DH_RSA_WITH_DES_CBC_SHA, "TLS_DH_RSA_WITH_DES_CBC_SHA"},
{PJ_TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA, "TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA"},
{PJ_TLS_DHE_DSS_WITH_DES_CBC_SHA, "TLS_DHE_DSS_WITH_DES_CBC_SHA"},
{PJ_TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA, "TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA"},
{PJ_TLS_DHE_RSA_WITH_DES_CBC_SHA, "TLS_DHE_RSA_WITH_DES_CBC_SHA"},
{PJ_TLS_DH_anon_EXPORT_WITH_RC4_40_MD5, "TLS_DH_anon_EXPORT_WITH_RC4_40_MD5"},
{PJ_TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA, "TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA"},
{PJ_TLS_DH_anon_WITH_DES_CBC_SHA, "TLS_DH_anon_WITH_DES_CBC_SHA"},
/* SSLv3 */
{PJ_SSL_FORTEZZA_KEA_WITH_NULL_SHA, "SSL_FORTEZZA_KEA_WITH_NULL_SHA"},
{PJ_SSL_FORTEZZA_KEA_WITH_FORTEZZA_CBC_SHA,"SSL_FORTEZZA_KEA_WITH_FORTEZZA_CBC_SHA"},
{PJ_SSL_FORTEZZA_KEA_WITH_RC4_128_SHA, "SSL_FORTEZZA_KEA_WITH_RC4_128_SHA"},
/* SSLv2 */
{PJ_SSL_CK_RC4_128_WITH_MD5, "SSL_CK_RC4_128_WITH_MD5"},
{PJ_SSL_CK_RC4_128_EXPORT40_WITH_MD5, "SSL_CK_RC4_128_EXPORT40_WITH_MD5"},
{PJ_SSL_CK_RC2_128_CBC_WITH_MD5, "SSL_CK_RC2_128_CBC_WITH_MD5"},
{PJ_SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5, "SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5"},
{PJ_SSL_CK_IDEA_128_CBC_WITH_MD5, "SSL_CK_IDEA_128_CBC_WITH_MD5"},
{PJ_SSL_CK_DES_64_CBC_WITH_MD5, "SSL_CK_DES_64_CBC_WITH_MD5"},
{PJ_SSL_CK_DES_192_EDE3_CBC_WITH_MD5, "SSL_CK_DES_192_EDE3_CBC_WITH_MD5"}
};
/* Get cipher name string */
static const char* get_cipher_name(pj_ssl_cipher cipher)
{
unsigned i, n;
n = PJ_ARRAY_SIZE(cipher_names);
for (i = 0; i < n; ++i) {
if (cipher == cipher_names[i].cipher)
return cipher_names[i].name;
}
return "CIPHER_UNKNOWN";
}
typedef void (*CPjSSLSocket_cb)(int err, void *key);
class CPjSSLSocketReader : public CActive
@ -115,7 +213,8 @@ public:
int Connect(CPjSSLSocket_cb cb, void *key, const TInetAddr &local_addr,
const TInetAddr &rem_addr,
const TDesC8 &servername = TPtrC8(NULL,0));
const TDesC8 &servername = TPtrC8(NULL,0),
const TDesC8 &ciphers = TPtrC8(NULL,0));
int Send(CPjSSLSocket_cb cb, void *key, const TDesC8 &aDesc, TUint flags);
int SendSync(const TDesC8 &aDesc, TUint flags);
@ -146,6 +245,7 @@ private:
TBuf<32> ssl_proto_;
TInetAddr rem_addr_;
TPtrC8 servername_;
TPtrC8 ciphers_;
TInetAddr local_addr_;
TSockXfrLength sent_len_;
@ -186,7 +286,8 @@ private:
int CPjSSLSocket::Connect(CPjSSLSocket_cb cb, void *key,
const TInetAddr &local_addr,
const TInetAddr &rem_addr,
const TDesC8 &servername)
const TDesC8 &servername,
const TDesC8 &ciphers)
{
pj_status_t status;
@ -213,7 +314,11 @@ int CPjSSLSocket::Connect(CPjSSLSocket_cb cb, void *key,
cb_ = cb;
key_ = key;
rem_addr_ = rem_addr;
/* Note: the following members only keep the pointer, not the data */
servername_.Set(servername);
ciphers_.Set(ciphers);
rSock.Connect(rem_addr_, iStatus);
SetActive();
state_ = SSL_STATE_CONNECTING;
@ -318,6 +423,8 @@ void CPjSSLSocket::RunL()
if (servername_.Length() > 0)
securesock_->SetOpt(KSoSSLDomainName, KSolInetSSL,
servername_);
if (ciphers_.Length() > 0)
securesock_->SetAvailableCipherSuites(ciphers_);
// FlushSessionCache() seems to also fire signals to all
// completed AOs (something like CActiveScheduler::RunIfReady())
@ -441,9 +548,8 @@ struct pj_ssl_sock_t
pj_ssl_sock_proto proto;
pj_time_val timeout;
unsigned ciphers_num;
pj_ssl_cipher *ciphers;
pj_str_t servername;
pj_str_t ciphers;
pj_ssl_cert_info remote_cert_info;
};
@ -579,15 +685,20 @@ static void update_certs_info(pj_ssl_sock_t *ssock)
}
/* Available ciphers */
static unsigned ciphers_num_ = 0;
static struct ciphers_t
{
pj_ssl_cipher id;
const char *name;
} ciphers_[64];
/*
* Get cipher list supported by SSL/TLS backend.
*/
PJ_DEF(pj_status_t) pj_ssl_cipher_get_availables (pj_ssl_cipher ciphers[],
unsigned *cipher_num)
{
/* Available ciphers */
static pj_ssl_cipher ciphers_[64];
static unsigned ciphers_num_ = 0;
unsigned i;
PJ_ASSERT_RETURN(ciphers && cipher_num, PJ_EINVAL);
@ -605,25 +716,69 @@ PJ_DEF(pj_status_t) pj_ssl_cipher_get_availables (pj_ssl_cipher ciphers[],
ciphers_num_ = ciphers_buf.Length() / 2;
if (ciphers_num_ > PJ_ARRAY_SIZE(ciphers_))
ciphers_num_ = PJ_ARRAY_SIZE(ciphers_);
for (i = 0; i < ciphers_num_; ++i)
ciphers_[i] = (pj_ssl_cipher)(ciphers_buf[i*2]*10 +
ciphers_buf[i*2+1]);
for (i = 0; i < ciphers_num_; ++i) {
ciphers_[i].id = (pj_ssl_cipher)(ciphers_buf[i*2]*10 +
ciphers_buf[i*2+1]);
ciphers_[i].name = get_cipher_name(ciphers_[i].id);
}
}
delete secure_sock;
}
if (ciphers_num_ == 0) {
*cipher_num = 0;
return PJ_ENOTFOUND;
}
*cipher_num = PJ_MIN(*cipher_num, ciphers_num_);
for (i = 0; i < *cipher_num; ++i)
ciphers[i] = ciphers_[i];
ciphers[i] = ciphers_[i].id;
return PJ_SUCCESS;
}
/* Get cipher name string */
PJ_DEF(const char*) pj_ssl_cipher_name(pj_ssl_cipher cipher)
{
unsigned i;
if (ciphers_num_ == 0) {
pj_ssl_cipher c[1];
i = 0;
pj_ssl_cipher_get_availables(c, &i);
}
for (i = 0; i < ciphers_num_; ++i) {
if (cipher == ciphers_[i].id)
return ciphers_[i].name;
}
return NULL;
}
/* Check if the specified cipher is supported by SSL/TLS backend. */
PJ_DEF(pj_bool_t) pj_ssl_cipher_is_supported(pj_ssl_cipher cipher)
{
unsigned i;
if (ciphers_num_ == 0) {
pj_ssl_cipher c[1];
i = 0;
pj_ssl_cipher_get_availables(c, &i);
}
for (i = 0; i < ciphers_num_; ++i) {
if (cipher == ciphers_[i].id)
return PJ_TRUE;
}
return PJ_FALSE;
}
/*
* Create SSL socket instance.
*/
@ -652,14 +807,15 @@ PJ_DEF(pj_status_t) pj_ssl_sock_create (pj_pool_t *pool,
ssock->cb = param->cb;
ssock->user_data = param->user_data;
ssock->timeout = param->timeout;
ssock->ciphers_num = param->ciphers_num;
if (param->ciphers_num > 0) {
unsigned i;
ssock->ciphers = (pj_ssl_cipher*)
pj_pool_calloc(pool, param->ciphers_num,
sizeof(pj_ssl_cipher));
for (i = 0; i < param->ciphers_num; ++i)
ssock->ciphers[i] = param->ciphers[i];
/* Cipher list in Symbian is represented as array of two-octets. */
ssock->ciphers.slen = param->ciphers_num*2;
ssock->ciphers.ptr = (char*)pj_pool_alloc(pool, ssock->ciphers.slen);
pj_uint8_t *c = (pj_uint8_t*)ssock->ciphers.ptr;
for (unsigned i = 0; i < param->ciphers_num; ++i) {
*c++ = (pj_uint8_t)(param->ciphers[i] & 0xFF00) >> 8;
*c++ = (pj_uint8_t)(param->ciphers[i] & 0xFF);
}
}
pj_strdup_with_null(pool, &ssock->servername, &param->server_name);
@ -1246,9 +1402,13 @@ PJ_DEF(pj_status_t) pj_ssl_sock_start_connect (pj_ssl_sock_t *ssock,
TPtrC8 servername_((TUint8*)ssock->servername.ptr,
ssock->servername.slen);
/* Convert cipher list to Symbian descriptor */
TPtrC8 ciphers_((TUint8*)ssock->ciphers.ptr,
ssock->ciphers.slen);
/* Try to connect */
status = sock->Connect(&connect_cb, ssock, localaddr_, remaddr_,
servername_);
servername_, ciphers_);
if (status != PJ_SUCCESS && status != PJ_EPENDING) {
delete sock;
return status;

View File

@ -453,6 +453,19 @@
# define PJMEDIA_RTCP_STAT_HAS_RAW_JITTER 0
#endif
/**
* Specify the factor with wich RTCP RTT statistics should be normalized
* if exceptionally high. For e.g. mobile networks with potentially large
* fluctuations, this might be unwanted.
*
* Use (0) to disable this feature.
*
* Default: 3.
*/
#ifndef PJMEDIA_RTCP_NORMALIZE_FACTOR
# define PJMEDIA_RTCP_NORMALIZE_FACTOR 3
#endif
/**
* Specify whether RTCP statistics includes IP Delay Variation statistics.
@ -476,7 +489,7 @@
* if it is enabled on run-time on per stream basis. See
* PJMEDIA_STREAM_ENABLE_XR setting for more info.
*
* Default: 1 (yes).
* Default: 0 (no).
*/
#ifndef PJMEDIA_HAS_RTCP_XR
# define PJMEDIA_HAS_RTCP_XR 0
@ -494,6 +507,19 @@
# define PJMEDIA_STREAM_ENABLE_XR 0
#endif
/**
* Specify the buffer length for storing any received RTCP SDES text
* in a stream session. Usually RTCP contains only the mandatory SDES
* field, i.e: CNAME.
*
* Default: 64 bytes.
*/
#ifndef PJMEDIA_RTCP_RX_SDES_BUF_LEN
# define PJMEDIA_RTCP_RX_SDES_BUF_LEN 64
#endif
/**
* Specify how long (in miliseconds) the stream should suspend the
* silence detector/voice activity detector (VAD) during the initial

View File

@ -60,6 +60,12 @@ typedef enum pjmedia_endpt_flag
} pjmedia_endpt_flag;
/**
* Type of callback to register to pjmedia_endpt_atexit().
*/
typedef void (*pjmedia_endpt_exit_callback)(pjmedia_endpt *endpt);
/**
* Create an instance of media endpoint.
*
@ -260,6 +266,23 @@ PJ_DECL(pj_status_t) pjmedia_endpt_create_video_sdp(pjmedia_endpt *endpt,
PJ_DECL(pj_status_t) pjmedia_endpt_dump(pjmedia_endpt *endpt);
/**
* Register cleanup function to be called by media endpoint when
* #pjmedia_endpt_destroy() is called. Note that application should not
* use or access any endpoint resource (such as pool, ioqueue) from within
* the callback as such resource may have been released when the callback
* function is invoked.
*
* @param endpt The media endpoint.
* @param func The function to be registered.
*
* @return PJ_SUCCESS on success.
*/
PJ_DECL(pj_status_t) pjmedia_endpt_atexit(pjmedia_endpt *endpt,
pjmedia_endpt_exit_callback func);
PJ_END_DECL

View File

@ -54,29 +54,26 @@ PJ_BEGIN_DECL
* #pjmedia_stream_get_stat() function.
*/
#pragma pack(1)
/**
* RTCP sender report.
*/
struct pjmedia_rtcp_sr
typedef struct pjmedia_rtcp_sr
{
pj_uint32_t ntp_sec; /**< NTP time, seconds part. */
pj_uint32_t ntp_frac; /**< NTP time, fractions part. */
pj_uint32_t rtp_ts; /**< RTP timestamp. */
pj_uint32_t sender_pcount; /**< Sender packet cound. */
pj_uint32_t sender_bcount; /**< Sender octet/bytes count. */
};
} pjmedia_rtcp_sr;
/**
* @see pjmedia_rtcp_sr
*/
typedef struct pjmedia_rtcp_sr pjmedia_rtcp_sr;
/**
* RTCP receiver report.
*/
struct pjmedia_rtcp_rr
typedef struct pjmedia_rtcp_rr
{
pj_uint32_t ssrc; /**< SSRC identification. */
#if defined(PJ_IS_BIG_ENDIAN) && PJ_IS_BIG_ENDIAN!=0
@ -94,18 +91,13 @@ struct pjmedia_rtcp_rr
pj_uint32_t jitter; /**< Jitter. */
pj_uint32_t lsr; /**< Last SR. */
pj_uint32_t dlsr; /**< Delay since last SR. */
};
/**
* @see pjmedia_rtcp_rr
*/
typedef struct pjmedia_rtcp_rr pjmedia_rtcp_rr;
} pjmedia_rtcp_rr;
/**
* RTCP common header.
*/
struct pjmedia_rtcp_common
typedef struct pjmedia_rtcp_common
{
#if defined(PJ_IS_BIG_ENDIAN) && PJ_IS_BIG_ENDIAN!=0
unsigned version:2; /**< packet type */
@ -120,12 +112,8 @@ struct pjmedia_rtcp_common
#endif
unsigned length:16; /**< packet length */
pj_uint32_t ssrc; /**< SSRC identification */
};
} pjmedia_rtcp_common;
/**
* @see pjmedia_rtcp_common
*/
typedef struct pjmedia_rtcp_common pjmedia_rtcp_common;
/**
* This structure declares default RTCP packet (SR) that is sent by pjmedia.
@ -152,26 +140,35 @@ typedef struct pjmedia_rtcp_rr_pkt
#pragma pack()
/**
* RTCP SDES structure.
*/
typedef struct pjmedia_rtcp_sdes
{
pj_str_t cname; /**< RTCP SDES type CNAME. */
pj_str_t name; /**< RTCP SDES type NAME. */
pj_str_t email; /**< RTCP SDES type EMAIL. */
pj_str_t phone; /**< RTCP SDES type PHONE. */
pj_str_t loc; /**< RTCP SDES type LOC. */
pj_str_t tool; /**< RTCP SDES type TOOL. */
pj_str_t note; /**< RTCP SDES type NOTE. */
} pjmedia_rtcp_sdes;
/**
* NTP time representation.
*/
struct pjmedia_rtcp_ntp_rec
typedef struct pjmedia_rtcp_ntp_rec
{
pj_uint32_t hi; /**< High order 32-bit part. */
pj_uint32_t lo; /**< Lo order 32-bit part. */
};
/**
* @see pjmedia_rtcp_ntp_rec
*/
typedef struct pjmedia_rtcp_ntp_rec pjmedia_rtcp_ntp_rec;
} pjmedia_rtcp_ntp_rec;
/**
* Unidirectional RTP stream statistics.
*/
struct pjmedia_rtcp_stream_stat
typedef struct pjmedia_rtcp_stream_stat
{
pj_time_val update; /**< Time of last update. */
unsigned update_cnt; /**< Number of updates (to calculate avg) */
@ -190,20 +187,14 @@ struct pjmedia_rtcp_stream_stat
} loss_type; /**< Types of loss detected. */
pj_math_stat jitter; /**< Jitter statistics (in usec) */
};
/**
* @see pjmedia_rtcp_stream_stat
*/
typedef struct pjmedia_rtcp_stream_stat pjmedia_rtcp_stream_stat;
} pjmedia_rtcp_stream_stat;
/**
* Bidirectional RTP stream statistics.
*/
struct pjmedia_rtcp_stat
typedef struct pjmedia_rtcp_stat
{
pj_time_val start; /**< Time when session was created */
@ -226,20 +217,19 @@ struct pjmedia_rtcp_stat
receiving direction
(in usec). */
#endif
};
pjmedia_rtcp_sdes peer_sdes; /**< Peer SDES. */
char peer_sdes_buf_[PJMEDIA_RTCP_RX_SDES_BUF_LEN];
/**< Peer SDES buffer. */
/**
* @see pjmedia_rtcp_stat
*/
typedef struct pjmedia_rtcp_stat pjmedia_rtcp_stat;
} pjmedia_rtcp_stat;
/**
* RTCP session is used to monitor the RTP session of one endpoint. There
* should only be one RTCP session for a bidirectional RTP streams.
*/
struct pjmedia_rtcp_session
typedef struct pjmedia_rtcp_session
{
char *name; /**< Name identification. */
pjmedia_rtcp_sr_pkt rtcp_sr_pkt;/**< Cached RTCP SR packet. */
@ -278,12 +268,7 @@ struct pjmedia_rtcp_session
*/
pjmedia_rtcp_xr_session xr_session;
#endif
};
/**
* @see pjmedia_rtcp_session
*/
typedef struct pjmedia_rtcp_session pjmedia_rtcp_session;
} pjmedia_rtcp_session;
/**
@ -438,6 +423,46 @@ PJ_DECL(void) pjmedia_rtcp_build_rtcp( pjmedia_rtcp_session *session,
void **rtcp_pkt, int *len);
/**
* Build an RTCP SDES (source description) packet. This packet can be
* appended to other RTCP packets, e.g: RTCP RR/SR, to compose a compound
* RTCP packet.
*
* @param session The RTCP session.
* @param buf The buffer to receive RTCP SDES packet.
* @param length On input, it will contain the buffer length.
* On output, it will contain the generated RTCP SDES
* packet length.
* @param sdes The source description, see #pjmedia_rtcp_sdes.
*
* @return PJ_SUCCESS on success.
*/
PJ_DECL(pj_status_t) pjmedia_rtcp_build_rtcp_sdes(
pjmedia_rtcp_session *session,
void *buf,
pj_size_t *length,
const pjmedia_rtcp_sdes *sdes);
/**
* Build an RTCP BYE packet. This packet can be appended to other RTCP
* packets, e.g: RTCP RR/SR, to compose a compound RTCP packet.
*
* @param session The RTCP session.
* @param buf The buffer to receive RTCP BYE packet.
* @param length On input, it will contain the buffer length.
* On output, it will contain the generated RTCP BYE
* packet length.
* @param reason Optional, the BYE reason.
*
* @return PJ_SUCCESS on success.
*/
PJ_DECL(pj_status_t) pjmedia_rtcp_build_rtcp_bye(
pjmedia_rtcp_session *session,
void *buf,
pj_size_t *length,
const pj_str_t *reason);
/**
* Call this function if RTCP XR needs to be enabled/disabled in the
* RTCP session.

View File

@ -200,6 +200,17 @@ typedef struct pjmedia_rtcp_xr_rb_voip_mtc
jitter buffer */
} pjmedia_rtcp_xr_rb_voip_mtc;
/**
* Constant of RTCP-XR content size.
*/
#define PJMEDIA_RTCP_XR_BUF_SIZE \
sizeof(pjmedia_rtcp_xr_rb_rr_time) + \
sizeof(pjmedia_rtcp_xr_rb_dlrr) + \
sizeof(pjmedia_rtcp_xr_rb_stats) + \
sizeof(pjmedia_rtcp_xr_rb_voip_mtc)
/**
* This structure declares RTCP XR (Extended Report) packet.
*/
@ -221,7 +232,8 @@ typedef struct pjmedia_rtcp_xr_pkt
pj_uint32_t ssrc; /**< SSRC identification */
} common;
pj_int8_t buf[PJMEDIA_MAX_MTU];/**< Content buffer */
pj_int8_t buf[PJMEDIA_RTCP_XR_BUF_SIZE];
/**< Content buffer */
} pjmedia_rtcp_xr_pkt;
#pragma pack()

View File

@ -200,8 +200,12 @@ typedef struct pjmedia_srtp_info
* will also invoke this function. This function will also register SRTP
* library deinitialization to #pj_atexit(), so the deinitialization
* of SRTP library will be performed automatically by PJLIB destructor.
*
* @param endpt The media endpoint instance.
*
* @return PJ_SUCCESS on success.
*/
PJ_DECL(pj_status_t) pjmedia_srtp_init_lib(void);
PJ_DECL(pj_status_t) pjmedia_srtp_init_lib(pjmedia_endpt *endpt);
/**

View File

@ -1086,11 +1086,14 @@ static pj_status_t write_frame(struct conf_port *cport_dst,
while (f_start < f_end) {
unsigned nsamples_to_copy, nsamples_req;
/* Copy frame to listener's TX buffer. */
/* Copy frame to listener's TX buffer.
* Note that if the destination is port 0, just copy the whole
* available samples.
*/
nsamples_to_copy = f_end - f_start;
nsamples_req = cport_dst->samples_per_frame -
(frm_dst->size>>1);
if (nsamples_to_copy > nsamples_req)
if (cport_dst->slot && nsamples_to_copy > nsamples_req)
nsamples_to_copy = nsamples_req;
/* Adjust TX level. */
@ -1123,16 +1126,19 @@ static pj_status_t write_frame(struct conf_port *cport_dst,
/* Check if it's time to deliver the TX buffer to listener,
* i.e: samples count in TX buffer equal to listener's
* samples per frame.
* samples per frame. Note that for destination port 0 this
* function will just populate all samples in the TX buffer.
*/
if ((frm_dst->size >> 1) == cport_dst->samples_per_frame)
if (cport_dst->slot == 0) {
/* Update TX timestamp. */
pj_add_timestamp32(&cport_dst->ts_tx, nsamples_to_copy);
} else if ((frm_dst->size >> 1) ==
cport_dst->samples_per_frame)
{
if (cport_dst->slot) {
pjmedia_port_put_frame(cport_dst->port, frm_dst);
pjmedia_port_put_frame(cport_dst->port, frm_dst);
/* Reset TX buffer. */
frm_dst->size = 0;
}
/* Reset TX buffer. */
frm_dst->size = 0;
/* Update TX timestamp. */
pj_add_timestamp32(&cport_dst->ts_tx,

View File

@ -24,6 +24,7 @@
#include <pjmedia-audiodev/audiodev.h>
#include <pj/assert.h>
#include <pj/ioqueue.h>
#include <pj/lock.h>
#include <pj/log.h>
#include <pj/os.h>
#include <pj/pool.h>
@ -57,6 +58,14 @@ static int PJ_THREAD_FUNC worker_proc(void*);
#define MAX_THREADS 16
/* List of media endpoint exit callback. */
typedef struct exit_cb
{
PJ_DECL_LIST_MEMBER (struct exit_cb);
pjmedia_endpt_exit_callback func;
} exit_cb;
/** Concrete declaration of media endpoint. */
struct pjmedia_endpt
{
@ -86,6 +95,9 @@ struct pjmedia_endpt
/** Is telephone-event enable */
pj_bool_t has_telephone_event;
/** List of exit callback. */
exit_cb exit_cb_list;
};
/**
@ -129,6 +141,9 @@ PJ_DEF(pj_status_t) pjmedia_endpt_create(pj_pool_factory *pf,
if (status != PJ_SUCCESS)
goto on_error;
/* Initialize exit callback list. */
pj_list_init(&endpt->exit_cb_list);
/* Create ioqueue if none is specified. */
if (endpt->ioqueue == NULL) {
@ -189,6 +204,7 @@ PJ_DEF(pjmedia_codec_mgr*) pjmedia_endpt_get_codec_mgr(pjmedia_endpt *endpt)
*/
PJ_DEF(pj_status_t) pjmedia_endpt_destroy (pjmedia_endpt *endpt)
{
exit_cb *ecb;
unsigned i;
PJ_ASSERT_RETURN(endpt, PJ_EINVAL);
@ -214,6 +230,14 @@ PJ_DEF(pj_status_t) pjmedia_endpt_destroy (pjmedia_endpt *endpt)
pjmedia_codec_mgr_destroy(&endpt->codec_mgr);
pjmedia_aud_subsys_shutdown();
/* Call all registered exit callbacks */
ecb = endpt->exit_cb_list.next;
while (ecb != &endpt->exit_cb_list) {
(*ecb->func)(endpt);
ecb = ecb->next;
}
pj_pool_release (endpt->pool);
return PJ_SUCCESS;
@ -434,7 +458,7 @@ PJ_DEF(pj_status_t) pjmedia_endpt_create_audio_sdp(pjmedia_endpt *endpt,
rtpmap.param.slen = 1;
} else {
rtpmap.param.ptr = NULL;
rtpmap.param.ptr = "";
rtpmap.param.slen = 0;
}
@ -896,3 +920,23 @@ PJ_DEF(pj_status_t) pjmedia_endpt_dump(pjmedia_endpt *endpt)
return PJ_SUCCESS;
}
PJ_DEF(pj_status_t) pjmedia_endpt_atexit( pjmedia_endpt *endpt,
pjmedia_endpt_exit_callback func)
{
exit_cb *new_cb;
PJ_ASSERT_RETURN(endpt && func, PJ_EINVAL);
if (endpt->quit_flag)
return PJ_EINVALIDOP;
new_cb = PJ_POOL_ZALLOC_T(endpt->pool, exit_cb);
new_cb->func = func;
pj_enter_critical_section();
pj_list_push_back(&endpt->exit_cb_list, new_cb);
pj_leave_critical_section();
return PJ_SUCCESS;
}

View File

@ -29,8 +29,21 @@
#define RTCP_SR 200
#define RTCP_RR 201
#define RTCP_SDES 202
#define RTCP_BYE 203
#define RTCP_XR 207
enum {
RTCP_SDES_NULL = 0,
RTCP_SDES_CNAME = 1,
RTCP_SDES_NAME = 2,
RTCP_SDES_EMAIL = 3,
RTCP_SDES_PHONE = 4,
RTCP_SDES_LOC = 5,
RTCP_SDES_TOOL = 6,
RTCP_SDES_NOTE = 7
};
#if PJ_HAS_HIGH_RES_TIMER==0
# error "High resolution timer needs to be enabled"
#endif
@ -473,9 +486,9 @@ PJ_DEF(void) pjmedia_rtcp_tx_rtp(pjmedia_rtcp_session *sess,
}
PJ_DEF(void) pjmedia_rtcp_rx_rtcp( pjmedia_rtcp_session *sess,
const void *pkt,
pj_size_t size)
static void parse_rtcp_report( pjmedia_rtcp_session *sess,
const void *pkt,
pj_size_t size)
{
pjmedia_rtcp_common *common = (pjmedia_rtcp_common*) pkt;
const pjmedia_rtcp_rr *rr = NULL;
@ -615,19 +628,21 @@ PJ_DEF(void) pjmedia_rtcp_rx_rtcp( pjmedia_rtcp_session *sess,
goto end_rtt_calc;
}
/* "Normalize" rtt value that is exceptionally high.
* For such values, "normalize" the rtt to be three times
* the average value.
#if defined(PJMEDIA_RTCP_NORMALIZE_FACTOR) && PJMEDIA_RTCP_NORMALIZE_FACTOR!=0
/* "Normalize" rtt value that is exceptionally high. For such
* values, "normalize" the rtt to be PJMEDIA_RTCP_NORMALIZE_FACTOR
* times the average value.
*/
if (rtt > ((unsigned)sess->stat.rtt.mean*3) && sess->stat.rtt.n!=0)
if (rtt > ((unsigned)sess->stat.rtt.mean *
PJMEDIA_RTCP_NORMALIZE_FACTOR) && sess->stat.rtt.n!=0)
{
unsigned orig_rtt = rtt;
rtt = sess->stat.rtt.mean*3;
PJ_LOG(5,(sess->name,
rtt = sess->stat.rtt.mean * PJMEDIA_RTCP_NORMALIZE_FACTOR;
PJ_LOG(5,(sess->name,
"RTT value %d usec is normalized to %d usec",
orig_rtt, rtt));
}
#endif
TRACE_((sess->name, "RTCP RTT is set to %d usec", rtt));
/* Update RTT stat */
@ -650,6 +665,142 @@ end_rtt_calc:
}
static void parse_rtcp_sdes(pjmedia_rtcp_session *sess,
const void *pkt,
pj_size_t size)
{
pjmedia_rtcp_sdes *sdes = &sess->stat.peer_sdes;
char *p, *p_end;
char *b, *b_end;
p = (char*)pkt + 8;
p_end = (char*)pkt + size;
pj_bzero(sdes, sizeof(*sdes));
b = sess->stat.peer_sdes_buf_;
b_end = b + sizeof(sess->stat.peer_sdes_buf_);
while (p < p_end) {
pj_uint8_t sdes_type, sdes_len;
pj_str_t sdes_value = {NULL, 0};
sdes_type = *p++;
/* Check for end of SDES item list */
if (sdes_type == RTCP_SDES_NULL || p == p_end)
break;
sdes_len = *p++;
/* Check for corrupted SDES packet */
if (p + sdes_len > p_end)
break;
/* Get SDES item */
if (b + sdes_len < b_end) {
pj_memcpy(b, p, sdes_len);
sdes_value.ptr = b;
sdes_value.slen = sdes_len;
b += sdes_len;
} else {
/* Insufficient SDES buffer */
PJ_LOG(5, (sess->name,
"Unsufficient buffer to save RTCP SDES type %d:%.*s",
sdes_type, sdes_len, p));
p += sdes_len;
continue;
}
switch (sdes_type) {
case RTCP_SDES_CNAME:
sdes->cname = sdes_value;
break;
case RTCP_SDES_NAME:
sdes->name = sdes_value;
break;
case RTCP_SDES_EMAIL:
sdes->email = sdes_value;
break;
case RTCP_SDES_PHONE:
sdes->phone = sdes_value;
break;
case RTCP_SDES_LOC:
sdes->loc = sdes_value;
break;
case RTCP_SDES_TOOL:
sdes->tool = sdes_value;
break;
case RTCP_SDES_NOTE:
sdes->note = sdes_value;
break;
default:
TRACE_((sess->name, "Received unknown RTCP SDES type %d:%.*s",
sdes_type, sdes_value.slen, sdes_value.ptr));
break;
}
p += sdes_len;
}
}
static void parse_rtcp_bye(pjmedia_rtcp_session *sess,
const void *pkt,
pj_size_t size)
{
pj_str_t reason = {"-", 1};
/* Check and get BYE reason */
if (size > 8) {
reason.slen = *((pj_uint8_t*)pkt+8);
pj_memcpy(sess->stat.peer_sdes_buf_, ((pj_uint8_t*)pkt+9),
reason.slen);
reason.ptr = sess->stat.peer_sdes_buf_;
}
/* Just print RTCP BYE log */
PJ_LOG(5, (sess->name, "Received RTCP BYE, reason: %.*s",
reason.slen, reason.ptr));
}
PJ_DEF(void) pjmedia_rtcp_rx_rtcp( pjmedia_rtcp_session *sess,
const void *pkt,
pj_size_t size)
{
pj_uint8_t *p, *p_end;
p = (pj_uint8_t*)pkt;
p_end = p + size;
while (p < p_end) {
pjmedia_rtcp_common *common = (pjmedia_rtcp_common*)p;
unsigned len;
len = (pj_ntohs((pj_uint16_t)common->length)+1) * 4;
switch(common->pt) {
case RTCP_SR:
case RTCP_RR:
case RTCP_XR:
parse_rtcp_report(sess, p, len);
break;
case RTCP_SDES:
parse_rtcp_sdes(sess, p, len);
break;
case RTCP_BYE:
parse_rtcp_bye(sess, p, len);
break;
default:
/* Ignore unknown RTCP */
TRACE_((sess->name, "Received unknown RTCP packet type=%d",
common->pt));
break;
}
p += len;
}
}
PJ_DEF(void) pjmedia_rtcp_build_rtcp(pjmedia_rtcp_session *sess,
void **ret_p_pkt, int *len)
{
@ -802,6 +953,128 @@ PJ_DEF(void) pjmedia_rtcp_build_rtcp(pjmedia_rtcp_session *sess,
sess->stat.rx.update_cnt++;
}
PJ_DEF(pj_status_t) pjmedia_rtcp_build_rtcp_sdes(
pjmedia_rtcp_session *session,
void *buf,
pj_size_t *length,
const pjmedia_rtcp_sdes *sdes)
{
pjmedia_rtcp_common *hdr;
pj_uint8_t *p;
unsigned len;
PJ_ASSERT_RETURN(session && buf && length && sdes, PJ_EINVAL);
/* Verify SDES item length */
if (sdes->cname.slen > 255 || sdes->name.slen > 255 ||
sdes->email.slen > 255 || sdes->phone.slen > 255 ||
sdes->loc.slen > 255 || sdes->tool.slen > 255 ||
sdes->note.slen > 255)
{
return PJ_EINVAL;
}
/* Verify buffer length */
len = sizeof(*hdr);
if (sdes->cname.slen) len += sdes->cname.slen + 2;
if (sdes->name.slen) len += sdes->name.slen + 2;
if (sdes->email.slen) len += sdes->email.slen + 2;
if (sdes->phone.slen) len += sdes->phone.slen + 2;
if (sdes->loc.slen) len += sdes->loc.slen + 2;
if (sdes->tool.slen) len += sdes->tool.slen + 2;
if (sdes->note.slen) len += sdes->note.slen + 2;
len++; /* null termination */
len = ((len+3)/4) * 4;
if (len > *length)
return PJ_ETOOSMALL;
/* Build RTCP SDES header */
hdr = (pjmedia_rtcp_common*)buf;
pj_memcpy(hdr, &session->rtcp_sr_pkt.common, sizeof(*hdr));
hdr->pt = RTCP_SDES;
hdr->length = pj_htons((pj_uint16_t)(len/4 - 1));
/* Build RTCP SDES items */
p = (pj_uint8_t*)hdr + sizeof(*hdr);
#define BUILD_SDES_ITEM(SDES_NAME, SDES_TYPE) \
if (sdes->SDES_NAME.slen) { \
*p++ = SDES_TYPE; \
*p++ = (pj_uint8_t)sdes->SDES_NAME.slen; \
pj_memcpy(p, sdes->SDES_NAME.ptr, sdes->SDES_NAME.slen); \
p += sdes->SDES_NAME.slen; \
}
BUILD_SDES_ITEM(cname, RTCP_SDES_CNAME);
BUILD_SDES_ITEM(name, RTCP_SDES_NAME);
BUILD_SDES_ITEM(email, RTCP_SDES_EMAIL);
BUILD_SDES_ITEM(phone, RTCP_SDES_PHONE);
BUILD_SDES_ITEM(loc, RTCP_SDES_LOC);
BUILD_SDES_ITEM(tool, RTCP_SDES_TOOL);
BUILD_SDES_ITEM(note, RTCP_SDES_NOTE);
#undef BUILD_SDES_ITEM
/* Null termination */
*p++ = 0;
/* Pad to 32bit */
while ((p-(pj_uint8_t*)buf) % 4)
*p++ = 0;
/* Finally */
pj_assert((int)len == p-(pj_uint8_t*)buf);
*length = len;
return PJ_SUCCESS;
}
PJ_DEF(pj_status_t) pjmedia_rtcp_build_rtcp_bye(pjmedia_rtcp_session *session,
void *buf,
pj_size_t *length,
const pj_str_t *reason)
{
pjmedia_rtcp_common *hdr;
pj_uint8_t *p;
unsigned len;
PJ_ASSERT_RETURN(session && buf && length, PJ_EINVAL);
/* Verify BYE reason length */
if (reason && reason->slen > 255)
return PJ_EINVAL;
/* Verify buffer length */
len = sizeof(*hdr);
if (reason && reason->slen) len += reason->slen + 1;
len = ((len+3)/4) * 4;
if (len > *length)
return PJ_ETOOSMALL;
/* Build RTCP BYE header */
hdr = (pjmedia_rtcp_common*)buf;
pj_memcpy(hdr, &session->rtcp_sr_pkt.common, sizeof(*hdr));
hdr->pt = RTCP_BYE;
hdr->length = pj_htons((pj_uint16_t)(len/4 - 1));
/* Write RTCP BYE reason */
p = (pj_uint8_t*)hdr + sizeof(*hdr);
if (reason && reason->slen) {
*p++ = (pj_uint8_t)reason->slen;
pj_memcpy(p, reason->ptr, reason->slen);
p += reason->slen;
}
/* Pad to 32bit */
while ((p-(pj_uint8_t*)buf) % 4)
*p++ = 0;
pj_assert((int)len == p-(pj_uint8_t*)buf);
*length = len;
return PJ_SUCCESS;
}
PJ_DEF(pj_status_t) pjmedia_rtcp_enable_xr( pjmedia_rtcp_session *sess,
pj_bool_t enable)
{

View File

@ -441,7 +441,6 @@ PJ_DEF(pj_status_t) pjmedia_snd_port_create2(pj_pool_t *pool,
snd_port->dir = prm->base.dir;
snd_port->rec_id = prm->base.rec_id;
snd_port->play_id = prm->base.play_id;
snd_port->dir = PJMEDIA_DIR_CAPTURE_PLAYBACK;
snd_port->clock_rate = prm->base.clock_rate;
snd_port->channel_count = prm->base.channel_count;
snd_port->samples_per_frame = prm->base.samples_per_frame;

View File

@ -155,6 +155,9 @@ struct pjmedia_stream
pj_uint32_t rtcp_interval; /**< Interval, in timestamp. */
pj_bool_t initial_rr; /**< Initial RTCP RR sent */
pj_bool_t rtcp_sdes_bye_disabled;/**< Send RTCP SDES/BYE?*/
void *out_rtcp_pkt; /**< Outgoing RTCP packet. */
unsigned out_rtcp_pkt_size;
/**< Outgoing RTCP packet size. */
/* RFC 2833 DTMF transmission queue: */
int tx_event_pt; /**< Outgoing pt for dtmf. */
@ -245,6 +248,12 @@ static void stream_perror(const char *sender, const char *title,
}
static pj_status_t send_rtcp(pjmedia_stream *stream,
pj_bool_t with_sdes,
pj_bool_t with_bye,
pj_bool_t with_xr);
#if TRACE_JB
PJ_INLINE(int) trace_jb_print_timestamp(char **buf, pj_ssize_t len)
@ -425,8 +434,7 @@ static void send_keep_alive_packet(pjmedia_stream *stream)
pkt_len);
/* Send RTCP */
pjmedia_rtcp_build_rtcp(&stream->rtcp, &pkt, &pkt_len);
pjmedia_transport_send_rtcp(stream->transport, pkt, pkt_len);
send_rtcp(stream, PJ_TRUE, PJ_FALSE, PJ_FALSE);
#elif PJMEDIA_STREAM_ENABLE_KA == PJMEDIA_STREAM_KA_USER
@ -913,6 +921,114 @@ static void create_dtmf_payload(pjmedia_stream *stream,
}
static pj_status_t send_rtcp(pjmedia_stream *stream,
pj_bool_t with_sdes,
pj_bool_t with_bye,
pj_bool_t with_xr)
{
void *sr_rr_pkt;
pj_uint8_t *pkt;
int len, max_len;
pj_status_t status;
/* Build RTCP RR/SR packet */
pjmedia_rtcp_build_rtcp(&stream->rtcp, &sr_rr_pkt, &len);
#if !defined(PJMEDIA_HAS_RTCP_XR) || (PJMEDIA_HAS_RTCP_XR == 0)
with_xr = PJ_FALSE;
#endif
if (with_sdes || with_bye || with_xr) {
pkt = (pj_uint8_t*) stream->out_rtcp_pkt;
pj_memcpy(pkt, sr_rr_pkt, len);
max_len = stream->out_rtcp_pkt_size;
} else {
pkt = sr_rr_pkt;
max_len = len;
}
/* Build RTCP SDES packet */
if (with_sdes) {
pjmedia_rtcp_sdes sdes;
pj_size_t sdes_len;
pj_bzero(&sdes, sizeof(sdes));
sdes.cname = stream->cname;
sdes_len = max_len - len;
status = pjmedia_rtcp_build_rtcp_sdes(&stream->rtcp, pkt+len,
&sdes_len, &sdes);
if (status != PJ_SUCCESS) {
PJ_PERROR(4,(stream->port.info.name.ptr, status,
"Error generating RTCP SDES"));
} else {
len += sdes_len;
}
}
/* Build RTCP XR packet */
#if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0)
if (with_xr) {
int i;
pjmedia_jb_state jb_state;
void *xr_pkt;
int xr_len;
/* Update RTCP XR with current JB states */
pjmedia_jbuf_get_state(stream->jb, &jb_state);
i = jb_state.avg_delay;
status = pjmedia_rtcp_xr_update_info(&stream->rtcp.xr_session,
PJMEDIA_RTCP_XR_INFO_JB_NOM, i);
pj_assert(status == PJ_SUCCESS);
i = jb_state.max_delay;
status = pjmedia_rtcp_xr_update_info(&stream->rtcp.xr_session,
PJMEDIA_RTCP_XR_INFO_JB_MAX, i);
pj_assert(status == PJ_SUCCESS);
pjmedia_rtcp_build_rtcp_xr(&stream->rtcp.xr_session, 0,
&xr_pkt, &xr_len);
if (xr_len + len <= max_len) {
pj_memcpy(pkt+len, xr_pkt, xr_len);
len += xr_len;
/* Send the RTCP XR to third-party destination if specified */
if (stream->rtcp_xr_dest_len) {
pjmedia_transport_send_rtcp2(stream->transport,
&stream->rtcp_xr_dest,
stream->rtcp_xr_dest_len,
xr_pkt, xr_len);
}
} else {
PJ_PERROR(4,(stream->port.info.name.ptr, PJ_ETOOBIG,
"Error generating RTCP-XR"));
}
}
#endif
/* Build RTCP BYE packet */
if (with_bye) {
pj_size_t bye_len;
bye_len = max_len - len;
status = pjmedia_rtcp_build_rtcp_bye(&stream->rtcp, pkt+len,
&bye_len, NULL);
if (status != PJ_SUCCESS) {
PJ_PERROR(4,(stream->port.info.name.ptr, status,
"Error generating RTCP BYE"));
} else {
len += bye_len;
}
}
/* Send! */
status = pjmedia_transport_send_rtcp(stream->transport, pkt, len);
return status;
}
/**
* check_tx_rtcp()
*
@ -926,133 +1042,38 @@ static void check_tx_rtcp(pjmedia_stream *stream, pj_uint32_t timestamp)
* or get_frame().
*/
if (stream->rtcp_last_tx == 0) {
stream->rtcp_last_tx = timestamp;
} else if (timestamp - stream->rtcp_last_tx >= stream->rtcp_interval) {
void *rtcp_pkt;
int len;
pj_bool_t with_xr = PJ_FALSE;
pj_status_t status;
pjmedia_rtcp_build_rtcp(&stream->rtcp, &rtcp_pkt, &len);
#if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0)
if (stream->rtcp.xr_enabled) {
if (stream->rtcp_xr_last_tx == 0) {
stream->rtcp_xr_last_tx = timestamp;
} else if (timestamp - stream->rtcp_xr_last_tx >=
stream->rtcp_xr_interval)
{
with_xr = PJ_TRUE;
pjmedia_transport_send_rtcp(stream->transport, rtcp_pkt, len);
/* Update last tx RTCP XR */
stream->rtcp_xr_last_tx = timestamp;
}
}
#endif
status = send_rtcp(stream, !stream->rtcp_sdes_bye_disabled, PJ_FALSE,
with_xr);
if (status != PJ_SUCCESS) {
PJ_PERROR(4,(stream->port.info.name.ptr, status,
"Error sending RTCP"));
}
stream->rtcp_last_tx = timestamp;
}
#if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0)
if (stream->rtcp.xr_enabled) {
if (stream->rtcp_xr_last_tx == 0) {
stream->rtcp_xr_last_tx = timestamp;
} else if (timestamp - stream->rtcp_xr_last_tx >=
stream->rtcp_xr_interval)
{
int i;
pjmedia_jb_state jb_state;
void *rtcp_pkt;
int len;
/* Update RTCP XR with current JB states */
pjmedia_jbuf_get_state(stream->jb, &jb_state);
i = jb_state.avg_delay;
pjmedia_rtcp_xr_update_info(&stream->rtcp.xr_session,
PJMEDIA_RTCP_XR_INFO_JB_NOM,
i);
i = jb_state.max_delay;
pjmedia_rtcp_xr_update_info(&stream->rtcp.xr_session,
PJMEDIA_RTCP_XR_INFO_JB_MAX,
i);
/* Build RTCP XR packet */
pjmedia_rtcp_build_rtcp_xr(&stream->rtcp.xr_session, 0,
&rtcp_pkt, &len);
/* Send the RTCP XR to remote address */
pjmedia_transport_send_rtcp(stream->transport, rtcp_pkt, len);
/* Send the RTCP XR to third-party destination if specified */
if (stream->rtcp_xr_dest_len) {
pjmedia_transport_send_rtcp2(stream->transport,
&stream->rtcp_xr_dest,
stream->rtcp_xr_dest_len,
rtcp_pkt, len);
}
/* Update last tx RTCP XR */
stream->rtcp_xr_last_tx = timestamp;
}
}
#endif
}
/* Build RTCP SDES packet */
static unsigned create_rtcp_sdes(pjmedia_stream *stream, pj_uint8_t *pkt,
unsigned max_len)
{
pjmedia_rtcp_common hdr;
pj_uint8_t *p = pkt;
/* SDES header */
hdr.version = 2;
hdr.p = 0;
hdr.count = 1;
hdr.pt = 202;
hdr.length = 2 + (4+stream->cname.slen+3)/4 - 1;
if (max_len < (hdr.length << 2)) {
pj_assert(!"Not enough buffer for SDES packet");
return 0;
}
hdr.length = pj_htons((pj_uint16_t)hdr.length);
hdr.ssrc = stream->enc->rtp.out_hdr.ssrc;
pj_memcpy(p, &hdr, sizeof(hdr));
p += sizeof(hdr);
/* CNAME item */
*p++ = 1;
*p++ = (pj_uint8_t)stream->cname.slen;
pj_memcpy(p, stream->cname.ptr, stream->cname.slen);
p += stream->cname.slen;
/* END */
*p++ = '\0';
*p++ = '\0';
/* Pad to 32bit */
while ((p-pkt) % 4)
*p++ = '\0';
return (p - pkt);
}
/* Build RTCP BYE packet */
static unsigned create_rtcp_bye(pjmedia_stream *stream, pj_uint8_t *pkt,
unsigned max_len)
{
pjmedia_rtcp_common hdr;
/* BYE header */
hdr.version = 2;
hdr.p = 0;
hdr.count = 1;
hdr.pt = 203;
hdr.length = 1;
if (max_len < (hdr.length << 2)) {
pj_assert(!"Not enough buffer for SDES packet");
return 0;
}
hdr.length = pj_htons((pj_uint16_t)hdr.length);
hdr.ssrc = stream->enc->rtp.out_hdr.ssrc;
pj_memcpy(pkt, &hdr, sizeof(hdr));
return sizeof(hdr);
}
@ -1348,8 +1369,13 @@ static pj_status_t put_frame_imp( pjmedia_port *port,
stream->is_streaming = PJ_TRUE;
/* Send the RTP packet to the transport. */
pjmedia_transport_send_rtp(stream->transport, channel->out_pkt,
frame_out.size + sizeof(pjmedia_rtp_hdr));
status = pjmedia_transport_send_rtp(stream->transport, channel->out_pkt,
frame_out.size +
sizeof(pjmedia_rtp_hdr));
if (status != PJ_SUCCESS) {
PJ_PERROR(4,(stream->port.info.name.ptr, status,
"Error sending RTP"));
}
/* Update stat */
pjmedia_rtcp_tx_rtp(&stream->rtcp, frame_out.size);
@ -1819,32 +1845,14 @@ on_return:
/* Send RTCP RR and SDES after we receive some RTP packets */
if (stream->rtcp.received >= 10 && !stream->initial_rr) {
void *sr_rr_pkt;
pj_uint8_t *pkt;
int len;
/* Build RR or SR */
pjmedia_rtcp_build_rtcp(&stream->rtcp, &sr_rr_pkt, &len);
if (!stream->rtcp_sdes_bye_disabled) {
pkt = (pj_uint8_t*) stream->enc->out_pkt;
pj_memcpy(pkt, sr_rr_pkt, len);
pkt += len;
/* Append SDES */
len = create_rtcp_sdes(stream, (pj_uint8_t*)pkt,
stream->enc->out_pkt_size - len);
if (len > 0) {
pkt += len;
len = ((pj_uint8_t*)pkt) - ((pj_uint8_t*)stream->enc->out_pkt);
pjmedia_transport_send_rtcp(stream->transport,
stream->enc->out_pkt, len);
}
} else {
pjmedia_transport_send_rtcp(stream->transport, sr_rr_pkt, len);
}
stream->initial_rr = PJ_TRUE;
status = send_rtcp(stream, !stream->rtcp_sdes_bye_disabled,
PJ_FALSE, PJ_FALSE);
if (status != PJ_SUCCESS) {
PJ_PERROR(4,(stream->port.info.name.ptr, status,
"Error sending initial RTCP RR"));
} else {
stream->initial_rr = PJ_TRUE;
}
}
}
@ -1882,7 +1890,6 @@ static pj_status_t create_channel( pj_pool_t *pool,
{
pjmedia_channel *channel;
pj_status_t status;
unsigned min_out_pkt_size;
/* Allocate memory for channel descriptor */
@ -1914,15 +1921,6 @@ static pj_status_t create_channel( pj_pool_t *pool,
return PJ_ENOTSUP;
}
/* It should big enough to hold (minimally) RTCP SR with an SDES. */
min_out_pkt_size = sizeof(pjmedia_rtcp_sr_pkt) +
sizeof(pjmedia_rtcp_common) +
(4 + stream->cname.slen) +
32;
if (channel->out_pkt_size < min_out_pkt_size)
channel->out_pkt_size = min_out_pkt_size;
channel->out_pkt = pj_pool_alloc(pool, channel->out_pkt_size);
PJ_ASSERT_RETURN(channel->out_pkt != NULL, PJ_ENOMEM);
@ -2265,8 +2263,31 @@ PJ_DEF(pj_status_t) pjmedia_stream_create( pjmedia_endpt *endpt,
#endif
pjmedia_rtcp_init2(&stream->rtcp, &rtcp_setting);
if (info->rtp_seq_ts_set) {
stream->rtcp.stat.rtp_tx_last_seq = info->rtp_seq;
stream->rtcp.stat.rtp_tx_last_ts = info->rtp_ts;
}
}
/* Allocate outgoing RTCP buffer, should be enough to hold SR/RR, SDES,
* BYE, and XR.
*/
stream->out_rtcp_pkt_size = sizeof(pjmedia_rtcp_sr_pkt) +
sizeof(pjmedia_rtcp_common) +
(4 + stream->cname.slen) +
32;
#if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0)
if (info->rtcp_xr_enabled) {
stream->out_rtcp_pkt_size += sizeof(pjmedia_rtcp_xr_pkt);
}
#endif
if (stream->out_rtcp_pkt_size > PJMEDIA_MAX_MTU)
stream->out_rtcp_pkt_size = PJMEDIA_MAX_MTU;
stream->out_rtcp_pkt = pj_pool_alloc(pool, stream->out_rtcp_pkt_size);
/* Only attach transport when stream is ready. */
status = pjmedia_transport_attach(tp, stream, &info->rem_addr,
&info->rem_rtcp,
@ -2391,47 +2412,9 @@ PJ_DEF(pj_status_t) pjmedia_stream_destroy( pjmedia_stream *stream )
{
PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL);
#if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0)
/* Send RTCP XR on stream destroy */
if (stream->rtcp.xr_enabled) {
int i;
pjmedia_jb_state jb_state;
void *rtcp_pkt;
int len;
/* Update RTCP XR with current JB states */
pjmedia_jbuf_get_state(stream->jb, &jb_state);
i = jb_state.avg_delay;
pjmedia_rtcp_xr_update_info(&stream->rtcp.xr_session,
PJMEDIA_RTCP_XR_INFO_JB_NOM,
i);
i = jb_state.max_delay;
pjmedia_rtcp_xr_update_info(&stream->rtcp.xr_session,
PJMEDIA_RTCP_XR_INFO_JB_MAX,
i);
/* Build RTCP XR packet */
pjmedia_rtcp_build_rtcp_xr(&stream->rtcp.xr_session, 0,
&rtcp_pkt, &len);
/* Send the RTCP XR to remote address */
pjmedia_transport_send_rtcp(stream->transport, rtcp_pkt, len);
/* Send the RTCP XR to third-party destination if specified */
if (stream->rtcp_xr_dest_len) {
pjmedia_transport_send_rtcp2(stream->transport,
&stream->rtcp_xr_dest,
stream->rtcp_xr_dest_len,
rtcp_pkt, len);
}
}
#endif
/* Send RTCP BYE */
/* Send RTCP BYE (also SDES & XR) */
if (!stream->rtcp_sdes_bye_disabled) {
pjmedia_stream_send_rtcp_bye(stream);
send_rtcp(stream, PJ_TRUE, PJ_TRUE, PJ_TRUE);
}
/* Detach from transport
@ -2799,18 +2782,9 @@ PJ_DEF(pj_status_t) pjmedia_stream_set_dtmf_callback(pjmedia_stream *stream,
PJ_DEF(pj_status_t)
pjmedia_stream_send_rtcp_sdes( pjmedia_stream *stream )
{
unsigned len;
PJ_ASSERT_RETURN(stream, PJ_EINVAL);
len = create_rtcp_sdes(stream, (pj_uint8_t*)stream->enc->out_pkt,
stream->enc->out_pkt_size);
if (len != 0) {
return pjmedia_transport_send_rtcp(stream->transport,
stream->enc->out_pkt, len);
}
return PJ_SUCCESS;
return send_rtcp(stream, PJ_TRUE, PJ_FALSE, PJ_FALSE);
}
/*
@ -2822,14 +2796,7 @@ pjmedia_stream_send_rtcp_bye( pjmedia_stream *stream )
PJ_ASSERT_RETURN(stream, PJ_EINVAL);
if (stream->enc && stream->transport) {
unsigned len;
len = create_rtcp_bye(stream, (pj_uint8_t*)stream->enc->out_pkt,
stream->enc->out_pkt_size);
if (len != 0) {
return pjmedia_transport_send_rtcp(stream->transport,
stream->enc->out_pkt, len);
}
return send_rtcp(stream, PJ_TRUE, PJ_TRUE, PJ_FALSE);
}
return PJ_SUCCESS;

View File

@ -419,7 +419,9 @@ static pj_status_t encode_session_in_sdp(struct transport_ice *tp_ice,
* the session, in this case we will answer with full ICE SDP and
* new ufrag/pwd pair.
*/
if (!restart_session && pj_ice_strans_sess_is_complete(tp_ice->ice_st)) {
if (!restart_session && pj_ice_strans_sess_is_complete(tp_ice->ice_st) &&
pj_ice_strans_get_state(tp_ice->ice_st) != PJ_ICE_STRANS_STATE_FAILED)
{
const pj_ice_sess_check *check;
char *attr_buf;
pjmedia_sdp_conn *conn;
@ -549,7 +551,10 @@ static pj_status_t encode_session_in_sdp(struct transport_ice *tp_ice,
pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr);
}
} else if (pj_ice_strans_has_sess(tp_ice->ice_st)) {
} else if (pj_ice_strans_has_sess(tp_ice->ice_st) &&
pj_ice_strans_get_state(tp_ice->ice_st) !=
PJ_ICE_STRANS_STATE_FAILED)
{
/* Encode all candidates to SDP media */
char *attr_buf;
unsigned comp;

View File

@ -270,9 +270,9 @@ const char* get_libsrtp_errstr(int err)
}
static pj_bool_t libsrtp_initialized;
static void pjmedia_srtp_deinit_lib(void);
static void pjmedia_srtp_deinit_lib(pjmedia_endpt *endpt);
PJ_DEF(pj_status_t) pjmedia_srtp_init_lib(void)
PJ_DEF(pj_status_t) pjmedia_srtp_init_lib(pjmedia_endpt *endpt)
{
if (libsrtp_initialized == PJ_FALSE) {
err_status_t err;
@ -284,7 +284,8 @@ PJ_DEF(pj_status_t) pjmedia_srtp_init_lib(void)
return PJMEDIA_ERRNO_FROM_LIBSRTP(err);
}
if (pj_atexit(pjmedia_srtp_deinit_lib) != PJ_SUCCESS) {
if (pjmedia_endpt_atexit(endpt, pjmedia_srtp_deinit_lib) != PJ_SUCCESS)
{
/* There will be memory leak when it fails to schedule libsrtp
* deinitialization, however the memory leak could be harmless,
* since in modern OS's memory used by an application is released
@ -299,10 +300,19 @@ PJ_DEF(pj_status_t) pjmedia_srtp_init_lib(void)
return PJ_SUCCESS;
}
static void pjmedia_srtp_deinit_lib(void)
static void pjmedia_srtp_deinit_lib(pjmedia_endpt *endpt)
{
err_status_t err;
/* Note that currently this SRTP init/deinit is not equipped with
* reference counter, it should be safe as normally there is only
* one single instance of media endpoint and even if it isn't, the
* pjmedia_transport_srtp_create() will invoke SRTP init (the only
* drawback should be the delay described by #788).
*/
PJ_UNUSED_ARG(endpt);
err = srtp_deinit();
if (err != err_status_ok) {
PJ_LOG(4, (THIS_FILE, "Failed to deinitialize libsrtp: %s",
@ -410,7 +420,7 @@ PJ_DEF(pj_status_t) pjmedia_transport_srtp_create(
}
/* Init libsrtp. */
status = pjmedia_srtp_init_lib();
status = pjmedia_srtp_init_lib(endpt);
if (status != PJ_SUCCESS)
return status;
@ -907,19 +917,22 @@ static void srtp_rtp_cb( void *user_data, void *pkt, pj_ssize_t size)
(err == err_status_replay_old || err == err_status_replay_fail))
{
/* Handle such condition that stream is updated (RTP seq is reinited
* & SRTP is restarted), but some old packets are still coming
* so SRTP is learning wrong RTP seq. While the newly inited RTP seq
* comes, SRTP thinks the RTP seq is replayed, so srtp_unprotect()
* will returning err_status_replay_*. Restarting SRTP can resolve
* this.
*/
if (pjmedia_transport_srtp_start((pjmedia_transport*)srtp,
&srtp->tx_policy, &srtp->rx_policy)
!= PJ_SUCCESS)
{
* & SRTP is restarted), but some old packets are still coming
* so SRTP is learning wrong RTP seq. While the newly inited RTP seq
* comes, SRTP thinks the RTP seq is replayed, so srtp_unprotect()
* will return err_status_replay_*. Restarting SRTP can resolve this.
*/
pjmedia_srtp_crypto tx, rx;
pj_status_t status;
tx = srtp->tx_policy;
rx = srtp->rx_policy;
status = pjmedia_transport_srtp_start((pjmedia_transport*)srtp,
&tx, &rx);
if (status != PJ_SUCCESS) {
PJ_LOG(5,(srtp->pool->obj_name, "Failed to restart SRTP, err=%s",
get_libsrtp_errstr(err)));
} else {
} else if (!srtp->bypass_srtp) {
err = srtp_unprotect(srtp->srtp_rx_ctx, (pj_uint8_t*)pkt, &len);
}
}

View File

@ -2854,6 +2854,8 @@ PJ_DEF(pj_status_t) pj_ice_sess_send_data(pj_ice_sess *ice,
pj_status_t status = PJ_SUCCESS;
pj_ice_sess_comp *comp;
pj_ice_sess_cand *cand;
pj_uint8_t transport_id;
pj_sockaddr addr;
PJ_ASSERT_RETURN(ice && comp_id, PJ_EINVAL);
@ -2869,22 +2871,29 @@ PJ_DEF(pj_status_t) pj_ice_sess_send_data(pj_ice_sess *ice,
comp = find_comp(ice, comp_id);
if (comp == NULL) {
status = PJNATH_EICEINCOMPID;
pj_mutex_unlock(ice->mutex);
goto on_return;
}
if (comp->valid_check == NULL) {
status = PJNATH_EICEINPROGRESS;
pj_mutex_unlock(ice->mutex);
goto on_return;
}
cand = comp->valid_check->lcand;
status = (*ice->cb.on_tx_pkt)(ice, comp_id, cand->transport_id,
transport_id = cand->transport_id;
pj_sockaddr_cp(&addr, &comp->valid_check->rcand->addr);
/* Release the mutex now to avoid deadlock (see ticket #1451). */
pj_mutex_unlock(ice->mutex);
status = (*ice->cb.on_tx_pkt)(ice, comp_id, transport_id,
data, data_len,
&comp->valid_check->rcand->addr,
&addr,
sizeof(pj_sockaddr_in));
on_return:
pj_mutex_unlock(ice->mutex);
return status;
}

View File

@ -1180,8 +1180,11 @@ PJ_DEF(pj_status_t) pj_ice_strans_sendto( pj_ice_strans *ice_st,
/* If ICE is available, send data with ICE, otherwise send with the
* default candidate selected during initialization.
*
* https://trac.pjsip.org/repos/ticket/1416:
* Once ICE has failed, also send data with the default candidate.
*/
if (ice_st->ice) {
if (ice_st->ice && ice_st->state < PJ_ICE_STRANS_STATE_FAILED) {
if (comp->turn_sock) {
pj_turn_sock_lock(comp->turn_sock);
}
@ -1406,6 +1409,11 @@ static pj_bool_t stun_on_rx_data(pj_stun_sock *stun_sock,
pj_status_t status;
comp = (pj_ice_strans_comp*) pj_stun_sock_get_user_data(stun_sock);
if (comp == NULL) {
/* We have disassociated ourselves from the STUN socket */
return PJ_FALSE;
}
ice_st = comp->ice_st;
sess_add_ref(ice_st);

View File

@ -504,7 +504,7 @@ static pj_status_t get_mapped_addr(pj_stun_sock *stun_sock)
PJ_FALSE, PJ_TRUE, &stun_sock->srv_addr,
pj_sockaddr_get_len(&stun_sock->srv_addr),
tdata);
if (status != PJ_SUCCESS)
if (status != PJ_SUCCESS && status != PJ_EPENDING)
goto on_error;
return PJ_SUCCESS;

View File

@ -31,6 +31,7 @@
3A3479871154EC4E00D51880 /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3A3479861154EC4E00D51880 /* AudioToolbox.framework */; };
3A34799A1154ECA300D51880 /* libgsmcodec-arm-apple-darwin9.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3A3479991154ECA300D51880 /* libgsmcodec-arm-apple-darwin9.a */; };
3A34799C1154ECB100D51880 /* libresample-arm-apple-darwin9.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3A34799B1154ECB100D51880 /* libresample-arm-apple-darwin9.a */; };
3ABE0507147CA00B00A57A62 /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3ABE0506147CA00B00A57A62 /* CFNetwork.framework */; };
3AC6435E1162192900B7A751 /* tock8.wav in Resources */ = {isa = PBXBuildFile; fileRef = 3AC6435D1162192900B7A751 /* tock8.wav */; };
3ADA4AB911572300008D95FE /* input.8.wav in Resources */ = {isa = PBXBuildFile; fileRef = 3ADA4AB811572300008D95FE /* input.8.wav */; };
3AE90E9B115F7A4F00FAEAA5 /* libg7221codec-arm-apple-darwin9.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3AE90E95115F7A4E00FAEAA5 /* libg7221codec-arm-apple-darwin9.a */; };
@ -73,8 +74,9 @@
3A3479861154EC4E00D51880 /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; };
3A3479991154ECA300D51880 /* libgsmcodec-arm-apple-darwin9.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libgsmcodec-arm-apple-darwin9.a"; path = "../../../third_party/lib/libgsmcodec-arm-apple-darwin9.a"; sourceTree = SOURCE_ROOT; };
3A34799B1154ECB100D51880 /* libresample-arm-apple-darwin9.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libresample-arm-apple-darwin9.a"; path = "../../../third_party/lib/libresample-arm-apple-darwin9.a"; sourceTree = SOURCE_ROOT; };
3ABE0506147CA00B00A57A62 /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = System/Library/Frameworks/CFNetwork.framework; sourceTree = SDKROOT; };
3AC6435D1162192900B7A751 /* tock8.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; name = tock8.wav; path = ../../../tests/pjsua/wavs/tock8.wav; sourceTree = SOURCE_ROOT; };
3ADA4AB811572300008D95FE /* input.8.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; name = input.8.wav; path = ../../../../../tests/pjsua/wavs/input.8.wav; sourceTree = BUILT_PRODUCTS_DIR; };
3ADA4AB811572300008D95FE /* input.8.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; name = input.8.wav; path = "../../../../../../../../teluu/pjproject-new-iphone/tests/pjsua/wavs/input.8.wav"; sourceTree = BUILT_PRODUCTS_DIR; };
3AE90E95115F7A4E00FAEAA5 /* libg7221codec-arm-apple-darwin9.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libg7221codec-arm-apple-darwin9.a"; path = "../../../third_party/lib/libg7221codec-arm-apple-darwin9.a"; sourceTree = SOURCE_ROOT; };
3AE90E96115F7A4F00FAEAA5 /* libilbccodec-arm-apple-darwin9.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libilbccodec-arm-apple-darwin9.a"; path = "../../../third_party/lib/libilbccodec-arm-apple-darwin9.a"; sourceTree = SOURCE_ROOT; };
3AE90E97115F7A4F00FAEAA5 /* libmilenage-arm-apple-darwin9.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libmilenage-arm-apple-darwin9.a"; path = "../../../third_party/lib/libmilenage-arm-apple-darwin9.a"; sourceTree = SOURCE_ROOT; };
@ -111,6 +113,7 @@
3AE90E9E115F7A4F00FAEAA5 /* libpjsdp-arm-apple-darwin9.a in Frameworks */,
3AE90E9F115F7A4F00FAEAA5 /* libspeex-arm-apple-darwin9.a in Frameworks */,
3AE90EA0115F7A4F00FAEAA5 /* libsrtp-arm-apple-darwin9.a in Frameworks */,
3ABE0507147CA00B00A57A62 /* CFNetwork.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -177,6 +180,7 @@
29B97323FDCFA39411CA2CEA /* Frameworks */ = {
isa = PBXGroup;
children = (
3ABE0506147CA00B00A57A62 /* CFNetwork.framework */,
3A3479861154EC4E00D51880 /* AudioToolbox.framework */,
1DF5F4DF0D08C38300B7A737 /* UIKit.framework */,
1D30AB110D05D00D00671497 /* Foundation.framework */,
@ -250,6 +254,7 @@
};
buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "ipjsystest" */;
compatibilityVersion = "Xcode 3.1";
developmentRegion = English;
hasScannedForEncodings = 1;
knownRegions = (
English,
@ -307,6 +312,7 @@
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = ipjsystest_Prefix.pch;
GCC_PREPROCESSOR_DEFINITIONS = "PJ_AUTOCONF=1";
INFOPLIST_FILE = "ipjsystest-Info.plist";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
@ -318,6 +324,7 @@
"\"$(SRCROOT)/../../../third_party/lib\"",
);
PRODUCT_NAME = ipjsystest;
SDKROOT = iphoneos;
};
name = Debug;
};
@ -328,6 +335,7 @@
COPY_PHASE_STRIP = YES;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = ipjsystest_Prefix.pch;
GCC_PREPROCESSOR_DEFINITIONS = "PJ_AUTOCONF=1";
INFOPLIST_FILE = "ipjsystest-Info.plist";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
@ -339,6 +347,7 @@
"\"$(SRCROOT)/../../../third_party/lib\"",
);
PRODUCT_NAME = ipjsystest;
SDKROOT = iphoneos;
};
name = Release;
};

View File

@ -269,6 +269,8 @@ static void usage(void)
puts (" May be specified multiple times");
puts (" --stun-srv=FORMAT Set STUN server host or domain. This option may be");
puts (" specified more than once. FORMAT is hostdom[:PORT]");
#if defined(PJSIP_HAS_TLS_TRANSPORT) && (PJSIP_HAS_TLS_TRANSPORT != 0)
puts ("");
puts ("TLS Options:");
puts (" --use-tls Enable TLS transport (default=no)");
@ -280,6 +282,9 @@ static void usage(void)
puts (" --tls-verify-client Verify client's certificate (default=no)");
puts (" --tls-neg-timeout Specify TLS negotiation timeout (default=no)");
puts (" --tls-srv-name Specify TLS server name for multihosting server");
puts (" --tls-cipher Specify prefered TLS cipher (optional).");
puts (" May be specified multiple times");
#endif
puts ("");
puts ("Audio Options:");
@ -560,7 +565,7 @@ static pj_status_t parse_args(int argc, char *argv[],
OPT_NOREFERSUB, OPT_ACCEPT_REDIRECT,
OPT_USE_TLS, OPT_TLS_CA_FILE, OPT_TLS_CERT_FILE, OPT_TLS_PRIV_FILE,
OPT_TLS_PASSWORD, OPT_TLS_VERIFY_SERVER, OPT_TLS_VERIFY_CLIENT,
OPT_TLS_NEG_TIMEOUT, OPT_TLS_SRV_NAME,
OPT_TLS_NEG_TIMEOUT, OPT_TLS_CIPHER,
OPT_CAPTURE_DEV, OPT_PLAYBACK_DEV,
OPT_CAPTURE_LAT, OPT_PLAYBACK_LAT, OPT_NO_TONES, OPT_JB_MAX_SIZE,
OPT_STDOUT_REFRESH, OPT_STDOUT_REFRESH_TEXT, OPT_IPV6, OPT_QOS,
@ -662,6 +667,7 @@ static pj_status_t parse_args(int argc, char *argv[],
{ "max-calls", 1, 0, OPT_MAX_CALLS},
{ "duration", 1, 0, OPT_DURATION},
{ "thread-cnt", 1, 0, OPT_THREAD_CNT},
#if defined(PJSIP_HAS_TLS_TRANSPORT) && (PJSIP_HAS_TLS_TRANSPORT != 0)
{ "use-tls", 0, 0, OPT_USE_TLS},
{ "tls-ca-file",1, 0, OPT_TLS_CA_FILE},
{ "tls-cert-file",1,0, OPT_TLS_CERT_FILE},
@ -670,7 +676,8 @@ static pj_status_t parse_args(int argc, char *argv[],
{ "tls-verify-server", 0, 0, OPT_TLS_VERIFY_SERVER},
{ "tls-verify-client", 0, 0, OPT_TLS_VERIFY_CLIENT},
{ "tls-neg-timeout", 1, 0, OPT_TLS_NEG_TIMEOUT},
{ "tls-srv-name", 1, 0, OPT_TLS_SRV_NAME},
{ "tls-cipher", 1, 0, OPT_TLS_CIPHER},
#endif
{ "capture-dev", 1, 0, OPT_CAPTURE_DEV},
{ "playback-dev", 1, 0, OPT_PLAYBACK_DEV},
{ "capture-lat", 1, 0, OPT_CAPTURE_LAT},
@ -1345,28 +1352,17 @@ static pj_status_t parse_args(int argc, char *argv[],
}
break;
#if defined(PJSIP_HAS_TLS_TRANSPORT) && (PJSIP_HAS_TLS_TRANSPORT != 0)
case OPT_USE_TLS:
cfg->use_tls = PJ_TRUE;
#if !defined(PJSIP_HAS_TLS_TRANSPORT) || PJSIP_HAS_TLS_TRANSPORT==0
PJ_LOG(1,(THIS_FILE, "Error: TLS support is not configured"));
return -1;
#endif
break;
case OPT_TLS_CA_FILE:
cfg->udp_cfg.tls_setting.ca_list_file = pj_str(pj_optarg);
#if !defined(PJSIP_HAS_TLS_TRANSPORT) || PJSIP_HAS_TLS_TRANSPORT==0
PJ_LOG(1,(THIS_FILE, "Error: TLS support is not configured"));
return -1;
#endif
break;
case OPT_TLS_CERT_FILE:
cfg->udp_cfg.tls_setting.cert_file = pj_str(pj_optarg);
#if !defined(PJSIP_HAS_TLS_TRANSPORT) || PJSIP_HAS_TLS_TRANSPORT==0
PJ_LOG(1,(THIS_FILE, "Error: TLS support is not configured"));
return -1;
#endif
break;
case OPT_TLS_PRIV_FILE:
@ -1375,10 +1371,6 @@ static pj_status_t parse_args(int argc, char *argv[],
case OPT_TLS_PASSWORD:
cfg->udp_cfg.tls_setting.password = pj_str(pj_optarg);
#if !defined(PJSIP_HAS_TLS_TRANSPORT) || PJSIP_HAS_TLS_TRANSPORT==0
PJ_LOG(1,(THIS_FILE, "Error: TLS support is not configured"));
return -1;
#endif
break;
case OPT_TLS_VERIFY_SERVER:
@ -1394,9 +1386,39 @@ static pj_status_t parse_args(int argc, char *argv[],
cfg->udp_cfg.tls_setting.timeout.sec = atoi(pj_optarg);
break;
case OPT_TLS_SRV_NAME:
cfg->udp_cfg.tls_setting.server_name = pj_str(pj_optarg);
break;
case OPT_TLS_CIPHER:
{
pj_ssl_cipher cipher;
if (pj_ansi_strnicmp(pj_optarg, "0x", 2) == 0) {
pj_str_t cipher_st = pj_str(pj_optarg + 2);
cipher = pj_strtoul2(&cipher_st, NULL, 16);
} else {
cipher = atoi(pj_optarg);
}
if (pj_ssl_cipher_is_supported(cipher)) {
static pj_ssl_cipher tls_ciphers[128];
tls_ciphers[cfg->udp_cfg.tls_setting.ciphers_num++] = cipher;
cfg->udp_cfg.tls_setting.ciphers = tls_ciphers;
} else {
pj_ssl_cipher ciphers[128];
unsigned j, ciphers_cnt;
ciphers_cnt = PJ_ARRAY_SIZE(ciphers);
pj_ssl_cipher_get_availables(ciphers, &ciphers_cnt);
PJ_LOG(1,(THIS_FILE, "Cipher \"%s\" is not supported by "
"TLS/SSL backend.", pj_optarg));
printf("Available TLS/SSL ciphers (%d):\n", ciphers_cnt);
for (j=0; j<ciphers_cnt; ++j)
printf("- 0x%06X: %s\n", ciphers[j], pj_ssl_cipher_name(ciphers[j]));
return -1;
}
}
break;
#endif /* PJSIP_HAS_TLS_TRANSPORT */
case OPT_CAPTURE_DEV:
cfg->vid.vcapture_dev = atoi(pj_optarg);
@ -1834,6 +1856,7 @@ static int write_settings(const struct app_config *config,
pj_strcat2(&cfg, line);
}
#if defined(PJSIP_HAS_TLS_TRANSPORT) && (PJSIP_HAS_TLS_TRANSPORT != 0)
/* TLS */
if (config->use_tls)
pj_strcat2(&cfg, "--use-tls\n");
@ -1863,13 +1886,6 @@ static int write_settings(const struct app_config *config,
pj_strcat2(&cfg, line);
}
if (config->udp_cfg.tls_setting.server_name.slen) {
pj_ansi_sprintf(line, "--tls-srv-name %.*s\n",
(int)config->udp_cfg.tls_setting.server_name.slen,
config->udp_cfg.tls_setting.server_name.ptr);
pj_strcat2(&cfg, line);
}
if (config->udp_cfg.tls_setting.verify_server)
pj_strcat2(&cfg, "--tls-verify-server\n");
@ -1882,6 +1898,14 @@ static int write_settings(const struct app_config *config,
pj_strcat2(&cfg, line);
}
for (i=0; i<config->udp_cfg.tls_setting.ciphers_num; ++i) {
pj_ansi_sprintf(line, "--tls-cipher 0x%06X # %s\n",
config->udp_cfg.tls_setting.ciphers[i],
pj_ssl_cipher_name(config->udp_cfg.tls_setting.ciphers[i]));
pj_strcat2(&cfg, line);
}
#endif
pj_strcat2(&cfg, "\n#\n# Media settings:\n#\n");
/* Video & extra audio */
@ -3211,6 +3235,11 @@ static void on_transport_state(pjsip_transport *tp,
const char *verif_msgs[32];
unsigned verif_msg_cnt;
/* Dump server TLS cipher */
PJ_LOG(4,(THIS_FILE, "TLS cipher used: 0x%06X/%s",
ssl_sock_info->cipher,
pj_ssl_cipher_name(ssl_sock_info->cipher) ));
/* Dump server TLS certificate */
pj_ssl_cert_info_dump(ssl_sock_info->remote_cert_info, " ",
buf, sizeof(buf));

View File

@ -2347,7 +2347,7 @@ static PyObject *py_pjsua_conf_get_port_info(PyObject *pSelf, PyObject *pArgs)
ret = (PyObj_pjsua_conf_port_info *)
conf_port_info_new(&PyTyp_pjsua_conf_port_info, NULL, NULL);
ret->bits_per_sample = info.bits_per_sample;
ret->channel_count = info.bits_per_sample;
ret->channel_count = info.channel_count;
ret->clock_rate = info.clock_rate;
ret->name = PyString_FromPJ(&info.name);
ret->samples_per_frame = info.samples_per_frame;

View File

@ -21,6 +21,7 @@
from distutils.core import setup, Extension
import os
import sys
import platform
# find pjsip version
pj_version=""
@ -58,9 +59,12 @@ for line in f:
f.close()
# Mac OS X depedencies
if sys.platform == 'darwin':
if platform.system() == 'Darwin':
extra_link_args = ["-framework", "CoreFoundation",
"-framework", "AudioToolbox"]
# OS X Lion support
if platform.mac_ver()[0].startswith("10.7"):
extra_link_args += ["-framework", "AudioUnit"]
else:
extra_link_args = []

View File

@ -58,9 +58,6 @@
#define ENABLE_SIP_TCP 0 // experimental
#define ENABLE_SIP_TLS 0 // experimental
#define TLS_SRV_NAME "pjsip.org" // TLS servername (required for
// TLS transport)
//
// Configure nameserver if DNS SRV is to be used with both SIP
// or STUN (for STUN see other settings below)
@ -490,7 +487,6 @@ static pj_status_t app_startup()
tcfg.qos_params.dscp_val = SIP_QOS_DSCP;
tcfg.tls_setting.qos_params = tcfg.qos_params;
}
tcfg.tls_setting.server_name = pj_str(TLS_SRV_NAME);
status = pjsua_transport_create(PJSIP_TRANSPORT_TLS, &tcfg, &tid);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "Error creating TLS transport", status);

View File

@ -81,6 +81,13 @@ typedef struct pjsip_cfg_t
* Disable rport in request.
*/
pj_bool_t disable_rport;
/**
* Disable automatic switching from UDP to TCP if outgoing request
* is greater than 1300 bytes. See PJSIP_DONT_SWITCH_TO_TCP.
*/
pj_bool_t disable_tcp_switch;
} endpt;
/** Transaction layer settings. */
@ -251,6 +258,9 @@ PJ_INLINE(pjsip_cfg_t*) pjsip_cfg(void)
* Disable the behavior of automatic switching to TCP whenever UDP packet
* size exceeds the threshold defined in PJSIP_UDP_SIZE_THRESHOLD.
*
* This option can also be controlled at run-time by the \a disable_tcp_switch
* setting in pjsip_cfg_t.
*
* Default is 0 (no).
*/
#ifndef PJSIP_DONT_SWITCH_TO_TCP
@ -420,10 +430,10 @@ PJ_INLINE(pjsip_cfg_t*) pjsip_cfg(void)
* Idle timeout interval to be applied to transports with no usage
* before the transport is destroyed. Value is in seconds.
*
* Default: 600
* Default: 30
*/
#ifndef PJSIP_TRANSPORT_IDLE_TIME
# define PJSIP_TRANSPORT_IDLE_TIME 600
# define PJSIP_TRANSPORT_IDLE_TIME 30
#endif

View File

@ -62,6 +62,13 @@ PJ_BEGIN_DECL
* @{
*/
/**
* Type of callback to register to pjsip_endpt_atexit().
*/
typedef void (*pjsip_endpt_exit_callback)(pjsip_endpoint *endpt);
/**
* Create an instance of SIP endpoint from the specified pool factory.
* The pool factory reference then will be kept by the endpoint, so that
@ -511,6 +518,21 @@ PJ_DECL(const pjsip_hdr*) pjsip_endpt_get_request_headers(pjsip_endpoint *e);
PJ_DECL(void) pjsip_endpt_dump( pjsip_endpoint *endpt, pj_bool_t detail );
/**
* Register cleanup function to be called by SIP endpoint when
* #pjsip_endpt_destroy() is called. Note that application should not
* use or access any endpoint resource (such as pool, ioqueue, timer heap)
* from within the callback as such resource may have been released when
* the callback function is invoked.
*
* @param endpt The SIP endpoint.
* @param func The function to be registered.
*
* @return PJ_SUCCESS on success.
*/
PJ_DECL(pj_status_t) pjsip_endpt_atexit(pjsip_endpoint *endpt,
pjsip_endpt_exit_callback func);
/**
* @}

View File

@ -573,6 +573,13 @@ struct pjsip_tx_data
*/
pjsip_tpselector tp_sel;
/**
* Special flag to indicate that this transmit data is a request that has
* been updated with proper authentication response and is ready to be
* sent for retry.
*/
pj_bool_t auth_retry;
/**
* Arbitrary data attached by PJSIP modules.
*/

View File

@ -26,6 +26,7 @@
*/
#include <pjsip/sip_transport.h>
#include <pj/pool.h>
#include <pj/ssl_sock.h>
#include <pj/string.h>
#include <pj/sock_qos.h>
@ -106,20 +107,19 @@ typedef struct pjsip_tls_setting
int method;
/**
* TLS cipher list string in OpenSSL format. If empty, then default
* cipher list of the backend will be used.
* Number of ciphers contained in the specified cipher preference.
* If this is set to zero, then default cipher list of the backend
* will be used.
*
* Default: 0 (zero).
*/
pj_str_t ciphers;
unsigned ciphers_num;
/**
* Optionally specify the server name instance to be contacted when
* making outgoing TLS connection. This setting is useful when the
* server is hosting multiple domains for the same TLS listening
* socket.
*
* Default: empty.
* Ciphers and order preference. The #pj_ssl_cipher_get_availables()
* can be used to check the available ciphers supported by backend.
*/
pj_str_t server_name;
pj_ssl_cipher *ciphers;
/**
* Specifies TLS transport behavior on the server TLS certificate
@ -246,7 +246,13 @@ PJ_INLINE(void) pjsip_tls_setting_copy(pj_pool_t *pool,
pj_strdup_with_null(pool, &dst->cert_file, &src->cert_file);
pj_strdup_with_null(pool, &dst->privkey_file, &src->privkey_file);
pj_strdup_with_null(pool, &dst->password, &src->password);
pj_strdup_with_null(pool, &dst->ciphers, &src->ciphers);
if (src->ciphers_num) {
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];
}
}

View File

@ -4886,7 +4886,7 @@ PJ_DECL(pj_status_t) pjsua_im_typing(pjsua_acc_id acc_id,
{
pjsua_player_id player_id;
status = pjsua_player_create("mysong.wav", 0, NULL, &player_id);
status = pjsua_player_create("mysong.wav", 0, &player_id);
if (status != PJ_SUCCESS)
return status;

View File

@ -212,7 +212,16 @@ void inv_set_state(pjsip_inv_session *inv, pjsip_inv_state state,
* otherwise disconnect the session.
*/
if (state == PJSIP_INV_STATE_CONFIRMED) {
if (pjmedia_sdp_neg_get_state(inv->neg)!=PJMEDIA_SDP_NEG_STATE_DONE) {
struct tsx_inv_data *tsx_inv_data = NULL;
if (inv->invite_tsx) {
tsx_inv_data = (struct tsx_inv_data*)
inv->invite_tsx->mod_data[mod_inv.mod.id];
}
if (pjmedia_sdp_neg_get_state(inv->neg)!=PJMEDIA_SDP_NEG_STATE_DONE &&
(tsx_inv_data && !tsx_inv_data->sdp_done) )
{
pjsip_tx_data *bye;
PJ_LOG(4,(inv->obj_name, "SDP offer/answer incomplete, ending the "
@ -3952,6 +3961,32 @@ static void inv_on_state_connecting( pjsip_inv_session *inv, pjsip_event *e)
status = pjsip_dlg_send_response(dlg, tsx, tdata);
if (status != PJ_SUCCESS) return;
} else if (tsx->role == PJSIP_ROLE_UAS &&
tsx->state == PJSIP_TSX_STATE_TRYING &&
pjsip_method_cmp(&tsx->method, &pjsip_invite_method)==0)
{
pjsip_rx_data *rdata = e->body.tsx_state.src.rdata;
pjsip_tx_data *tdata;
pj_status_t status;
/* See https://trac.pjsip.org/repos/ticket/1455
* Handle incoming re-INVITE before current INVITE is confirmed.
* According to RFC 5407:
* - answer with 200 if we don't have pending offer-answer
* - answer with 491 if we *have* pending offer-answer
*
* But unfortunately accepting the re-INVITE would mean we have
* two outstanding INVITEs, and we don't support that because
* we will get confused when we handle the ACK.
*/
status = pjsip_dlg_create_response(inv->dlg, rdata,
PJSIP_SC_REQUEST_PENDING,
NULL, &tdata);
if (status != PJ_SUCCESS)
return;
pjsip_timer_update_resp(inv, tdata);
status = pjsip_dlg_send_response(dlg, tsx, tdata);
} else if (tsx->role == PJSIP_ROLE_UAS &&
tsx->state == PJSIP_TSX_STATE_TRYING &&
pjsip_method_cmp(&tsx->method, &pjsip_update_method)==0)
@ -3986,6 +4021,7 @@ static void inv_on_state_connecting( pjsip_inv_session *inv, pjsip_event *e)
/* Generic handling for UAC tsx completion */
handle_uac_tsx_response(inv, e);
}
}

View File

@ -162,8 +162,10 @@ static pjsip_hdr *parse_hdr_replaces(pjsip_parse_ctx *ctx)
/* Deinitialize Replaces */
static void pjsip_replaces_deinit_module(void)
static void pjsip_replaces_deinit_module(pjsip_endpoint *endpt)
{
PJ_TODO(provide_initialized_flag_for_each_endpoint);
PJ_UNUSED_ARG(endpt);
is_initialized = PJ_FALSE;
}
@ -191,7 +193,8 @@ PJ_DEF(pj_status_t) pjsip_replaces_init_module(pjsip_endpoint *endpt)
1, &STR_REPLACES);
/* Register deinit module to be executed when PJLIB shutdown */
if (pj_atexit(&pjsip_replaces_deinit_module) != PJ_SUCCESS) {
if (pjsip_endpt_atexit(endpt, &pjsip_replaces_deinit_module) != PJ_SUCCESS)
{
/* Failure to register this function may cause this module won't
* work properly when the stack is restarted (without quitting
* application).

View File

@ -495,8 +495,10 @@ static void stop_timer(pjsip_inv_session *inv)
}
/* Deinitialize Session Timers */
static void pjsip_timer_deinit_module(void)
static void pjsip_timer_deinit_module(pjsip_endpoint *endpt)
{
PJ_TODO(provide_initialized_flag_for_each_endpoint);
PJ_UNUSED_ARG(endpt);
is_initialized = PJ_FALSE;
}
@ -531,7 +533,7 @@ PJ_DEF(pj_status_t) pjsip_timer_init_module(pjsip_endpoint *endpt)
return status;
/* Register deinit module to be executed when PJLIB shutdown */
if (pj_atexit(&pjsip_timer_deinit_module) != PJ_SUCCESS) {
if (pjsip_endpt_atexit(endpt, &pjsip_timer_deinit_module) != PJ_SUCCESS) {
/* Failure to register this function may cause this module won't
* work properly when the stack is restarted (without quitting
* application).

View File

@ -152,22 +152,39 @@ PJ_DEF(pj_status_t) pjsip_auth_create_aka_response(
&auth->uri, &chal->realm, &aka_cred, method);
} else if (aka_version == 2) {
/*
* For AKAv2, password is base64 encoded [1] parameters:
* PRF(RES||IK||CK,"http-digest-akav2-password")
*
* The pseudo-random function (PRF) is HMAC-MD5 in this case.
*
* Hmmm.. but those above doesn't seem to work, and this below does!
*/
aka_cred.data.slen = PJSIP_AKA_RESLEN + PJSIP_AKA_IKLEN +
PJSIP_AKA_CKLEN;
aka_cred.data.ptr = pj_pool_alloc(pool, aka_cred.data.slen);
pj_memcpy(aka_cred.data.ptr + 0, res, PJSIP_AKA_RESLEN);
pj_memcpy(aka_cred.data.ptr + PJSIP_AKA_RESLEN, ik, PJSIP_AKA_IKLEN);
pj_memcpy(aka_cred.data.ptr + PJSIP_AKA_RESLEN + PJSIP_AKA_IKLEN,
ck, PJSIP_AKA_CKLEN);
pj_str_t resikck;
const pj_str_t AKAv2_Passwd = { "http-digest-akav2-password", 26 };
pj_uint8_t hmac_digest[16];
char tmp_buf[48];
int hmac64_len;
resikck.slen = PJSIP_AKA_RESLEN + PJSIP_AKA_IKLEN + PJSIP_AKA_CKLEN;
pj_assert(resikck.slen <= PJ_ARRAY_SIZE(tmp_buf));
resikck.ptr = tmp_buf;
pj_memcpy(resikck.ptr + 0, res, PJSIP_AKA_RESLEN);
pj_memcpy(resikck.ptr + PJSIP_AKA_RESLEN, ik, PJSIP_AKA_IKLEN);
pj_memcpy(resikck.ptr + PJSIP_AKA_RESLEN + PJSIP_AKA_IKLEN,
ck, PJSIP_AKA_CKLEN);
pj_hmac_md5((const pj_uint8_t*)AKAv2_Passwd.ptr, AKAv2_Passwd.slen,
(const pj_uint8_t*)resikck.ptr, resikck.slen,
hmac_digest);
aka_cred.data.slen = hmac64_len =
PJ_BASE256_TO_BASE64_LEN(PJ_ARRAY_SIZE(hmac_digest));
pj_assert(aka_cred.data.slen+1 <= PJ_ARRAY_SIZE(tmp_buf));
aka_cred.data.ptr = tmp_buf;
pj_base64_encode(hmac_digest, PJ_ARRAY_SIZE(hmac_digest),
aka_cred.data.ptr, &len);
aka_cred.data.slen = hmac64_len;
pjsip_auth_create_digest(&auth->response, &chal->nonce,
&auth->nc, &auth->cnonce, &auth->qop,

View File

@ -1103,7 +1103,8 @@ PJ_DEF(pj_status_t) pjsip_auth_clt_reinit_req( pjsip_auth_clt_sess *sess,
PJSIP_EINVALIDSTATUS);
tdata = old_request;
tdata->auth_retry = PJ_FALSE;
/*
* Respond to each authentication challenge.
*/
@ -1174,6 +1175,9 @@ PJ_DEF(pj_status_t) pjsip_auth_clt_reinit_req( pjsip_auth_clt_sess *sess,
/* Must invalidate the message! */
pjsip_tx_data_invalidate_msg(tdata);
/* Retrying.. */
tdata->auth_retry = PJ_TRUE;
/* Increment reference counter. */
pjsip_tx_data_add_ref(tdata);

View File

@ -25,7 +25,9 @@ pjsip_cfg_t pjsip_sip_cfg_var =
{
/* Global settings */
{
PJSIP_ALLOW_PORT_IN_FROMTO_HDR
PJSIP_ALLOW_PORT_IN_FROMTO_HDR,
0,
PJSIP_DONT_SWITCH_TO_TCP
},
/* Transaction settings */

View File

@ -40,6 +40,15 @@
#define MAX_METHODS 32
/* List of SIP endpoint exit callback. */
typedef struct exit_cb
{
PJ_DECL_LIST_MEMBER (struct exit_cb);
pjsip_endpt_exit_callback func;
} exit_cb;
/**
* The SIP endpoint.
*/
@ -86,6 +95,9 @@ struct pjsip_endpoint
/** Additional request headers. */
pjsip_hdr req_hdr;
/** List of exit callback. */
exit_cb exit_cb_list;
};
@ -445,6 +457,9 @@ PJ_DEF(pj_status_t) pjsip_endpt_create(pj_pool_factory *pf,
/* Init modules list. */
pj_list_init(&endpt->module_list);
/* Initialize exit callback list. */
pj_list_init(&endpt->exit_cb_list);
/* Create R/W mutex for module manipulation. */
status = pj_rwmutex_create(endpt->pool, "ept%p", &endpt->mod_mutex);
if (status != PJ_SUCCESS)
@ -559,6 +574,7 @@ on_error:
PJ_DEF(void) pjsip_endpt_destroy(pjsip_endpoint *endpt)
{
pjsip_module *mod;
exit_cb *ecb;
PJ_LOG(5, (THIS_FILE, "Destroying endpoing instance.."));
@ -592,6 +608,13 @@ PJ_DEF(void) pjsip_endpt_destroy(pjsip_endpoint *endpt)
/* Destroy timer heap */
pj_timer_heap_destroy(endpt->timer_heap);
/* Call all registered exit callbacks */
ecb = endpt->exit_cb_list.next;
while (ecb != &endpt->exit_cb_list) {
(*ecb->func)(endpt);
ecb = ecb->next;
}
/* Delete endpoint mutex. */
pj_mutex_destroy(endpt->mutex);
@ -1182,3 +1205,20 @@ PJ_DEF(void) pjsip_endpt_dump( pjsip_endpoint *endpt, pj_bool_t detail )
#endif
}
PJ_DEF(pj_status_t) pjsip_endpt_atexit( pjsip_endpoint *endpt,
pjsip_endpt_exit_callback func)
{
exit_cb *new_cb;
PJ_ASSERT_RETURN(endpt && func, PJ_EINVAL);
new_cb = PJ_POOL_ZALLOC_T(endpt->pool, exit_cb);
new_cb->func = func;
pj_mutex_lock(endpt->mutex);
pj_list_push_back(&endpt->exit_cb_list, new_cb);
pj_mutex_unlock(endpt->mutex);
return PJ_SUCCESS;
}

View File

@ -714,23 +714,17 @@ static pj_status_t mod_tsx_layer_stop(void)
}
pj_mutex_unlock(mod_tsx_layer.mutex);
PJ_LOG(4,(THIS_FILE, "Stopped transaction layer module"));
return PJ_SUCCESS;
}
/* This module callback is called when module is being unloaded by
* endpoint.
*/
static pj_status_t mod_tsx_layer_unload(void)
/* Destroy this module */
static void tsx_layer_destroy(pjsip_endpoint *endpt)
{
/* Only self destroy when there's no transaction in the table.
* Transaction may refuse to destroy when it has pending
* transmission. If we destroy the module now, application will
* crash when the pending transaction finally got error response
* from transport and when it tries to unregister itself.
*/
if (pj_hash_count(mod_tsx_layer.htable) != 0)
return PJ_EBUSY;
PJ_UNUSED_ARG(endpt);
/* Destroy mutex. */
pj_mutex_destroy(mod_tsx_layer.mutex);
@ -745,6 +739,31 @@ static pj_status_t mod_tsx_layer_unload(void)
mod_tsx_layer.endpt = NULL;
PJ_LOG(4,(THIS_FILE, "Transaction layer module destroyed"));
}
/* This module callback is called when module is being unloaded by
* endpoint.
*/
static pj_status_t mod_tsx_layer_unload(void)
{
/* Only self destroy when there's no transaction in the table.
* Transaction may refuse to destroy when it has pending
* transmission. If we destroy the module now, application will
* crash when the pending transaction finally got error response
* from transport and when it tries to unregister itself.
*/
if (pj_hash_count(mod_tsx_layer.htable) != 0) {
if (pjsip_endpt_atexit(mod_tsx_layer.endpt, &tsx_layer_destroy) !=
PJ_SUCCESS)
{
PJ_LOG(3,(THIS_FILE, "Failed to register transaction layer "
"module destroy."));
}
return PJ_EBUSY;
}
tsx_layer_destroy(mod_tsx_layer.endpt);
return PJ_SUCCESS;
}
@ -3239,7 +3258,10 @@ static pj_status_t tsx_on_state_destroyed(pjsip_transaction *tsx,
{
PJ_UNUSED_ARG(tsx);
PJ_UNUSED_ARG(event);
pj_assert(!"Not expecting any events!!");
return PJ_EBUG;
// See https://trac.pjsip.org/repos/ticket/1432
//pj_assert(!"Not expecting any events!!");
return PJ_EIGNORED;
}

View File

@ -293,6 +293,8 @@ PJ_DEF(pj_status_t) pjsip_tls_transport_start (pjsip_endpoint *endpt,
ssock_param.send_buffer_size = PJSIP_MAX_PKT_LEN;
if (ssock_param.read_buffer_size < PJSIP_MAX_PKT_LEN)
ssock_param.read_buffer_size = PJSIP_MAX_PKT_LEN;
ssock_param.ciphers_num = listener->tls_setting.ciphers_num;
ssock_param.ciphers = listener->tls_setting.ciphers;
ssock_param.qos_type = listener->tls_setting.qos_type;
ssock_param.qos_ignore_error = listener->tls_setting.qos_ignore_error;
pj_memcpy(&ssock_param.qos_params, &listener->tls_setting.qos_params,
@ -862,7 +864,6 @@ static pj_status_t lis_create_transport(pjsip_tpfactory *factory,
ssock_param.cb.on_data_sent = &on_data_sent;
ssock_param.async_cnt = 1;
ssock_param.ioqueue = pjsip_endpt_get_ioqueue(listener->endpt);
PJ_TODO(synchronize_tls_cipher_type_with_ssl_sock_cipher_type);
ssock_param.server_name = remote_name;
ssock_param.timeout = listener->tls_setting.timeout;
ssock_param.user_data = NULL; /* pending, must be set later */
@ -872,6 +873,8 @@ static pj_status_t lis_create_transport(pjsip_tpfactory *factory,
ssock_param.send_buffer_size = PJSIP_MAX_PKT_LEN;
if (ssock_param.read_buffer_size < PJSIP_MAX_PKT_LEN)
ssock_param.read_buffer_size = PJSIP_MAX_PKT_LEN;
ssock_param.ciphers_num = listener->tls_setting.ciphers_num;
ssock_param.ciphers = listener->tls_setting.ciphers;
ssock_param.qos_type = listener->tls_setting.qos_type;
ssock_param.qos_ignore_error = listener->tls_setting.qos_ignore_error;
pj_memcpy(&ssock_param.qos_params, &listener->tls_setting.qos_params,

View File

@ -1248,14 +1248,14 @@ stateless_send_resolver_callback( pj_status_t status,
}
pj_assert(tdata->dest_info.addr.count != 0);
#if !defined(PJSIP_DONT_SWITCH_TO_TCP) || PJSIP_DONT_SWITCH_TO_TCP==0
/* RFC 3261 section 18.1.1:
* If a request is within 200 bytes of the path MTU, or if it is larger
* than 1300 bytes and the path MTU is unknown, the request MUST be sent
* using an RFC 2914 [43] congestion controlled transport protocol, such
* as TCP.
*/
if (tdata->msg->type == PJSIP_REQUEST_MSG &&
if (pjsip_cfg()->endpt.disable_tcp_switch==0 &&
tdata->msg->type == PJSIP_REQUEST_MSG &&
tdata->dest_info.addr.count > 0 &&
tdata->dest_info.addr.entry[0].type == PJSIP_TRANSPORT_UDP)
{
@ -1297,7 +1297,6 @@ stateless_send_resolver_callback( pj_status_t status,
tdata->dest_info.addr.count = count * 2;
}
}
#endif /* !PJSIP_DONT_SWITCH_TO_TCP */
/* Process the addresses. */
stateless_send_transport_cb( stateless_data, tdata, -PJ_EPENDING);

View File

@ -26,7 +26,7 @@
#define NULL_SND_DEV_ID -99
/*****************************************************************************
/*
*
* Prototypes
*/
/* Open sound dev */
@ -43,7 +43,7 @@ static pj_status_t create_aud_param(pjmedia_aud_param *param,
unsigned bits_per_sample);
/*****************************************************************************
/*
*
* Call API that are closely tied to PJMEDIA
*/
/*
@ -223,7 +223,7 @@ on_return:
/*****************************************************************************
/*
*
* Audio media with PJMEDIA backend
*/
@ -806,13 +806,13 @@ PJ_DEF(pj_status_t) pjsua_conf_connect( pjsua_conf_port_id source,
source, sink));
pj_log_push_indent();
/* If sound device idle timer is active, cancel it first. */
PJSUA_LOCK();
/* If sound device idle timer is active, cancel it first. */
if (pjsua_var.snd_idle_timer.id) {
pjsip_endpt_cancel_timer(pjsua_var.endpt, &pjsua_var.snd_idle_timer);
pjsua_var.snd_idle_timer.id = PJ_FALSE;
}
PJSUA_UNLOCK();
/* For audio switchboard (i.e. APS-Direct):
@ -910,8 +910,6 @@ PJ_DEF(pj_status_t) pjsua_conf_connect( pjsua_conf_port_id source,
if (pjsua_var.snd_port==NULL && pjsua_var.null_snd==NULL &&
!pjsua_var.no_snd)
{
pj_status_t status;
status = pjsua_set_snd_dev(pjsua_var.cap_dev, pjsua_var.play_dev);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "Error opening sound device", status);
@ -926,9 +924,13 @@ PJ_DEF(pj_status_t) pjsua_conf_connect( pjsua_conf_port_id source,
}
}
status = pjmedia_conf_connect_port(pjsua_var.mconf, source, sink, 0);
on_return:
PJSUA_UNLOCK();
if (status == PJ_SUCCESS) {
status = pjmedia_conf_connect_port(pjsua_var.mconf, source, sink, 0);
}
pj_log_pop_indent();
return status;
}
@ -1851,8 +1853,11 @@ PJ_DEF(pj_status_t) pjsua_set_snd_dev( int capture_dev,
capture_dev, playback_dev));
pj_log_push_indent();
PJSUA_LOCK();
/* Null-sound */
if (capture_dev==NULL_SND_DEV_ID && playback_dev==NULL_SND_DEV_ID) {
PJSUA_UNLOCK();
status = pjsua_set_null_snd_dev();
pj_log_pop_indent();
return status;
@ -1903,10 +1908,12 @@ PJ_DEF(pj_status_t) pjsua_set_snd_dev( int capture_dev,
pjsua_var.no_snd = PJ_FALSE;
pjsua_var.snd_is_on = PJ_TRUE;
PJSUA_UNLOCK();
pj_log_pop_indent();
return PJ_SUCCESS;
on_error:
PJSUA_UNLOCK();
pj_log_pop_indent();
return status;
}
@ -1920,6 +1927,8 @@ on_error:
PJ_DEF(pj_status_t) pjsua_get_snd_dev(int *capture_dev,
int *playback_dev)
{
PJSUA_LOCK();
if (capture_dev) {
*capture_dev = pjsua_var.cap_dev;
}
@ -1927,6 +1936,7 @@ PJ_DEF(pj_status_t) pjsua_get_snd_dev(int *capture_dev,
*playback_dev = pjsua_var.play_dev;
}
PJSUA_UNLOCK();
return PJ_SUCCESS;
}
@ -1942,6 +1952,7 @@ PJ_DEF(pj_status_t) pjsua_set_null_snd_dev(void)
PJ_LOG(4,(THIS_FILE, "Setting null sound device.."));
pj_log_push_indent();
PJSUA_LOCK();
/* Close existing sound device */
close_snd_dev();
@ -1969,6 +1980,7 @@ PJ_DEF(pj_status_t) pjsua_set_null_snd_dev(void)
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "Unable to create null sound device",
status);
PJSUA_UNLOCK();
pj_log_pop_indent();
return status;
}
@ -1983,6 +1995,7 @@ PJ_DEF(pj_status_t) pjsua_set_null_snd_dev(void)
pjsua_var.no_snd = PJ_FALSE;
pjsua_var.snd_is_on = PJ_TRUE;
PJSUA_UNLOCK();
pj_log_pop_indent();
return PJ_SUCCESS;
}
@ -1994,10 +2007,14 @@ PJ_DEF(pj_status_t) pjsua_set_null_snd_dev(void)
*/
PJ_DEF(pjmedia_port*) pjsua_set_no_snd_dev(void)
{
PJSUA_LOCK();
/* Close existing sound device */
close_snd_dev();
pjsua_var.no_snd = PJ_TRUE;
PJSUA_UNLOCK();
return pjmedia_conf_get_master_port(pjsua_var.mconf);
}
@ -2007,13 +2024,18 @@ PJ_DEF(pjmedia_port*) pjsua_set_no_snd_dev(void)
*/
PJ_DEF(pj_status_t) pjsua_set_ec(unsigned tail_ms, unsigned options)
{
pj_status_t status = PJ_SUCCESS;
PJSUA_LOCK();
pjsua_var.media_cfg.ec_tail_len = tail_ms;
if (pjsua_var.snd_port)
return pjmedia_snd_port_set_ec( pjsua_var.snd_port, pjsua_var.pool,
tail_ms, options);
status = pjmedia_snd_port_set_ec(pjsua_var.snd_port, pjsua_var.pool,
tail_ms, options);
return PJ_SUCCESS;
PJSUA_UNLOCK();
return status;
}
@ -2050,6 +2072,8 @@ PJ_DEF(pj_status_t) pjsua_snd_set_setting( pjmedia_aud_dev_cap cap,
return PJMEDIA_EAUD_INVCAP;
}
PJSUA_LOCK();
/* If sound is active, set it immediately */
if (pjsua_snd_is_active()) {
pjmedia_aud_stream *strm;
@ -2060,8 +2084,10 @@ PJ_DEF(pj_status_t) pjsua_snd_set_setting( pjmedia_aud_dev_cap cap,
status = PJ_SUCCESS;
}
if (status != PJ_SUCCESS)
if (status != PJ_SUCCESS) {
PJSUA_UNLOCK();
return status;
}
/* Save in internal param for later device open */
if (keep) {
@ -2069,6 +2095,7 @@ PJ_DEF(pj_status_t) pjsua_snd_set_setting( pjmedia_aud_dev_cap cap,
cap, pval);
}
PJSUA_UNLOCK();
return status;
}
@ -2078,6 +2105,10 @@ PJ_DEF(pj_status_t) pjsua_snd_set_setting( pjmedia_aud_dev_cap cap,
PJ_DEF(pj_status_t) pjsua_snd_get_setting( pjmedia_aud_dev_cap cap,
void *pval)
{
pj_status_t status;
PJSUA_LOCK();
/* If sound device has never been opened before, open it to
* retrieve the initial setting from the device (e.g. audio
* volume)
@ -2093,12 +2124,15 @@ PJ_DEF(pj_status_t) pjsua_snd_get_setting( pjmedia_aud_dev_cap cap,
pjmedia_aud_stream *strm;
strm = pjmedia_snd_port_get_snd_stream(pjsua_var.snd_port);
return pjmedia_aud_stream_get_cap(strm, cap, pval);
status = pjmedia_aud_stream_get_cap(strm, cap, pval);
} else {
/* Otherwise retrieve from internal param */
return pjmedia_aud_param_get_cap(&pjsua_var.aud_param,
cap, pval);
status = pjmedia_aud_param_get_cap(&pjsua_var.aud_param,
cap, pval);
}
PJSUA_UNLOCK();
return status;
}
#endif /* PJSUA_MEDIA_HAS_PJMEDIA */

View File

@ -2929,12 +2929,10 @@ static void pjsua_call_on_state_changed(pjsip_inv_session *inv,
pjsua_call *call;
pj_log_push_indent();
PJSUA_LOCK();
call = (pjsua_call*) inv->dlg->mod_data[pjsua_var.mod.id];
if (!call) {
PJSUA_UNLOCK();
pj_log_pop_indent();
return;
}
@ -3077,21 +3075,21 @@ static void pjsua_call_on_state_changed(pjsip_inv_session *inv,
/* Destroy media session when invite session is disconnected. */
if (inv->state == PJSIP_INV_STATE_DISCONNECTED) {
pj_assert(call != NULL);
if (call)
pjsua_media_channel_deinit(call->index);
PJSUA_LOCK();
pjsua_media_channel_deinit(call->index);
/* Free call */
call->inv = NULL;
pj_assert(pjsua_var.call_cnt > 0);
--pjsua_var.call_cnt;
/* Reset call */
reset_call(call->index);
PJSUA_UNLOCK();
}
PJSUA_UNLOCK();
pj_log_pop_indent();
}
@ -3202,7 +3200,6 @@ static void pjsua_call_on_media_update(pjsip_inv_session *inv,
//const pj_str_t st_update = {"UPDATE", 6};
pj_log_push_indent();
PJSUA_LOCK();
call = (pjsua_call*) inv->dlg->mod_data[pjsua_var.mod.id];
@ -3279,7 +3276,6 @@ static void pjsua_call_on_media_update(pjsip_inv_session *inv,
pjsua_var.ua_cfg.cb.on_call_media_state(call->index);
on_return:
PJSUA_UNLOCK();
pj_log_pop_indent();
}
@ -3392,8 +3388,6 @@ static void pjsua_call_on_rx_offer(pjsip_inv_session *inv,
unsigned i;
pj_status_t status;
PJSUA_LOCK();
call = (pjsua_call*) inv->dlg->mod_data[pjsua_var.mod.id];
/* Supply candidate answer */
@ -3480,7 +3474,6 @@ static void pjsua_call_on_rx_offer(pjsip_inv_session *inv,
}
on_return:
PJSUA_UNLOCK();
pj_log_pop_indent();
}
@ -3495,7 +3488,6 @@ static void pjsua_call_on_create_offer(pjsip_inv_session *inv,
pj_status_t status;
pj_log_push_indent();
PJSUA_LOCK();
call = (pjsua_call*) inv->dlg->mod_data[pjsua_var.mod.id];
@ -3520,7 +3512,6 @@ static void pjsua_call_on_create_offer(pjsip_inv_session *inv,
}
on_return:
PJSUA_UNLOCK();
pj_log_pop_indent();
}
@ -3983,7 +3974,6 @@ static void pjsua_call_on_tsx_state_changed(pjsip_inv_session *inv,
pjsua_call *call;
pj_log_push_indent();
PJSUA_LOCK();
call = (pjsua_call*) inv->dlg->mod_data[pjsua_var.mod.id];
@ -3999,6 +3989,17 @@ static void pjsua_call_on_tsx_state_changed(pjsip_inv_session *inv,
goto on_return;
}
/* https://trac.pjsip.org/repos/ticket/1452:
* If a request is retried due to 401/407 challenge, don't process the
* transaction first but wait until we've retried it.
*/
if (tsx->role == PJSIP_ROLE_UAC &&
(tsx->status_code==401 || tsx->status_code==407) &&
tsx->last_tx && tsx->last_tx->auth_retry)
{
goto on_return;
}
/* Notify application callback first */
if (pjsua_var.ua_cfg.cb.on_call_tsx_state) {
(*pjsua_var.ua_cfg.cb.on_call_tsx_state)(call->index, tsx, e);
@ -4124,8 +4125,6 @@ static void pjsua_call_on_tsx_state_changed(pjsip_inv_session *inv,
}
on_return:
PJSUA_UNLOCK();
pj_log_pop_indent();
}
@ -4139,7 +4138,6 @@ static pjsip_redirect_op pjsua_call_on_redirected(pjsip_inv_session *inv,
pjsip_redirect_op op;
pj_log_push_indent();
PJSUA_LOCK();
if (pjsua_var.ua_cfg.cb.on_call_redirected) {
op = (*pjsua_var.ua_cfg.cb.on_call_redirected)(call->index,
@ -4152,7 +4150,6 @@ static pjsip_redirect_op pjsua_call_on_redirected(pjsip_inv_session *inv,
op = PJSIP_REDIRECT_STOP;
}
PJSUA_UNLOCK();
pj_log_pop_indent();
return op;

View File

@ -413,7 +413,6 @@ static void dump_media_session(const char *indent,
const char *type2 = pj_ice_get_cand_type_name(ii->comp[jj].rcand_type);
char addr1[PJ_INET6_ADDRSTRLEN+10];
char addr2[PJ_INET6_ADDRSTRLEN+10];
const char *comp_name[2] = {"rtp ", "rtcp"};
if (pj_sockaddr_has_addr(&ii->comp[jj].lcand_addr))
pj_sockaddr_print(&ii->comp[jj].lcand_addr, addr1, sizeof(addr1), 3);

View File

@ -97,8 +97,8 @@ pj_status_t pjsua_media_subsys_init(const pjsua_media_config *cfg)
goto on_error;
#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
/* Initialize SRTP library. */
status = pjmedia_srtp_init_lib();
/* Initialize SRTP library (ticket #788). */
status = pjmedia_srtp_init_lib(pjsua_var.med_endpt);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "Error initializing SRTP library",
status);

View File

@ -5,7 +5,6 @@ export LIBDIR := ../../lib
RULES_MAK := $(PJDIR)/build/rules.mak
export RESAMPLE_LIB := ../../lib/libresample-$(TARGET_NAME)$(LIBEXT)
###############################################################################
# Gather all flags.
@ -22,6 +21,9 @@ export RESAMPLE_SRCDIR = ../../resample/src
export RESAMPLE_OBJS = resamplesubs.o
export RESAMPLE_CFLAGS = $(_CFLAGS)
SHLIB_NAME := libresample.$(SHLIB_SUFFIX)
export RESAMPLE_SHLIB := ../../lib/$(SHLIB_NAME).$(PJ_VERSION_MAJOR)
export RESAMPLE_LIB := ../../lib/libresample-$(TARGET_NAME)$(LIBEXT)
export CC_OUT CC AR RANLIB HOST_MV HOST_RM HOST_RMDIR HOST_MKDIR OBJEXT LD LDOUT
###############################################################################
@ -29,7 +31,18 @@ export CC_OUT CC AR RANLIB HOST_MV HOST_RM HOST_RMDIR HOST_MKDIR OBJEXT LD LDOUT
#
# $(TARGET) is defined in os-$(OS_NAME).mak file in current directory.
#
ifeq ($(PJ_RESAMPLE_DLL),1)
TARGETS := ../../lib/$(SHLIB_NAME)
ifeq ($(SHLIB_SUFFIX),so)
SHLIB_OPT := -Wl,-soname,$(SHLIB_NAME).$(PJ_VERSION_MAJOR)
else
SHLIB_OPT :=
endif
export RESAMPLE_CFLAGS := -fPIC $(RESAMPLE_CFLAGS)
export RESAMPLE_LDFLAGS := -shared $(SHLIB_OPT) $(RESAMPLE_LDFLAGS)
else
TARGETS := libresample
endif
all: $(TARGETS)
@ -44,12 +57,18 @@ distclean: realclean
libresample:
$(MAKE) -f $(RULES_MAK) APP=RESAMPLE app=libresample $(RESAMPLE_LIB)
../../lib/$(SHLIB_NAME): $(RESAMPLE_SHLIB)
ln -s $(SHLIB_NAME).$(PJ_VERSION_MAJOR) $@
$(RESAMPLE_SHLIB):
$(MAKE) -f $(RULES_MAK) APP=RESAMPLE app=libresample $(RESAMPLE_SHLIB)
clean print_lib:
$(MAKE) -f $(RULES_MAK) APP=RESAMPLE app=libresample $@
realclean:
$(subst @@,$(subst /,$(HOST_PSEP),.ilbc-$(TARGET_NAME).depend),$(HOST_RMR))
$(subst @@,$(subst /,$(HOST_PSEP),../../lib/$(SHLIB_NAME)),$(HOST_RMR))
$(subst @@,$(subst /,$(HOST_PSEP),$(RESAMPLE_SHLIB)),$(HOST_RMR))
$(MAKE) -f $(RULES_MAK) APP=RESAMPLE app=libresample $@
depend:

View File

@ -1 +1,15 @@
export PJ_VERSION := 2.0-beta-svn
export PJ_VERSION_MAJOR := 2
export PJ_VERSION_MINOR := 0
export PJ_VERSION_REV :=
export PJ_VERSION_SUFFIX := beta-svn
export PJ_VERSION := $(PJ_VERSION_MAJOR).$(PJ_VERSION_MINOR)
ifneq ($(PJ_VERSION_REV),)
export PJ_VERSION := $(PJ_VERSION).$(PJ_VERSION_REV)
endif
ifneq ($(PJ_VERSION_SUFFIX),)
export PJ_VERSION := $(PJ_VERSION)-$(PJ_VERSION_SUFFIX)
endif