Merge remote-tracking branch 'linphone/master'

This commit is contained in:
Simon Morlat 2015-02-05 01:22:30 +01:00
commit 2003ca847a
64 changed files with 3340 additions and 573 deletions

View file

@ -33,6 +33,11 @@ fi
INTLTOOLIZE=$(which intltoolize)
#workaround for mingw bug in intltoolize script.
if test "$INTLTOOLIZE" = "/bin/intltoolize" ; then
INTLTOOLIZE=/usr/bin/intltoolize
fi
echo "Generating build scripts in linphone..."
set -x
$LIBTOOLIZE --copy --force

View file

@ -60,9 +60,12 @@ case $target in
mingwce_found=yes
;;
*mingw*)
dnl Workaround for mingw, whose compiler does not check in /usr/include ...
CPPFLAGS="$CPPFLAGS -I/usr/include"
LDFLAGS="$LDFLAGS -L/usr/lib"
CFLAGS="$CFLAGS -DORTP_STATIC -D_WIN32_WINNT=0x0501 "
CXXFLAGS="$CXXFLAGS -DORTP_STATIC -D_WIN32_WINNT=0x0501"
LIBS="$LIBS -L/lib -lws2_32"
LIBS="$LIBS -lws2_32"
GUI_FLAGS="-mwindows"
CONSOLE_FLAGS="-mconsole"
mingw_found=yes
@ -625,6 +628,16 @@ AC_ARG_ENABLE(zrtp,
[zrtp=false]
)
AC_ARG_ENABLE(dtls,
[AS_HELP_STRING([--enable-dtls], [Turn on dtls support - requires polarssl > 1.4])],
[case "${enableval}" in
yes) dtls=true ;;
no) dtls=false ;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-dtls) ;;
esac],
[dtls=false]
)
dnl build console if required
AM_CONDITIONAL(BUILD_CONSOLE, test x$console_ui = xtrue)
@ -635,6 +648,7 @@ dnl compilation of gtk user interface
AM_CONDITIONAL(BUILD_GTK_UI, [test x$gtk_ui = xtrue ] )
AM_CONDITIONAL(BUILD_WIN32, test x$mingw_found = xyes )
AM_CONDITIONAL(BUILD_ZRTP, test x$zrtp = xtrue)
AM_CONDITIONAL(BUILD_DTLS, test x$dtls = xtrue)
dnl check getenv
AH_TEMPLATE([HAVE_GETENV])
@ -795,7 +809,6 @@ AC_SUBST([MS2_VERSION])
AC_SUBST([MS2_DIR])
AC_ARG_ENABLE(tunnel,
[AS_HELP_STRING([--enable-tunnel=[yes/no]], [Turn on compilation of tunnel support (default=no)])],
[case "${enableval}" in
@ -932,6 +945,7 @@ case "$target_os" in
;;
esac
dnl ##################################################
dnl # Check for doxygen
dnl ##################################################
@ -983,6 +997,7 @@ printf "* %-30s %s\n" "Console interface" $console_ui
printf "* %-30s %s\n" "Tools" $build_tools
printf "* %-30s %s\n" "Message storage" $enable_msg_storage
printf "* %-30s %s\n" "zRTP encryption" $zrtp
printf "* %-30s %s\n" "DTLS encryption" $dtls
printf "* %-30s %s\n" "uPnP support" $build_upnp
printf "* %-30s %s\n" "LDAP support" $enable_ldap
printf "* %-30s %s\n" "ZLIB support" $found_zlib

View file

@ -150,6 +150,15 @@ static LPC_COMMAND commands[] = {
"'help <command>'\t: displays specific help for command.\n"
"'help advanced'\t: shows advanced commands.\n"
},
{ "answer", lpc_cmd_answer, "Answer a call",
"'answer' : Answer the current incoming call\n"
"'answer <call id>' : Answer the call with given id\n"
},
{ "autoanswer", lpc_cmd_autoanswer, "Show/set auto-answer mode",
"'autoanswer' \t: show current autoanswer mode\n"
"'autoanswer enable'\t: enable autoanswer mode\n"
"'autoanswer disable'\t: disable autoanswer mode\n"
},
{ "call", lpc_cmd_call, "Call a SIP uri or number",
#ifdef VIDEO_ENABLED
"'call <sip-url or number> [options]' \t: initiate a call to the specified destination.\n"
@ -162,83 +171,24 @@ static LPC_COMMAND commands[] = {
},
{ "calls", lpc_cmd_calls, "Show all the current calls with their id and status.",
NULL
},
},
{ "call-logs", lpc_cmd_call_logs, "Calls history", NULL
},
#ifdef VIDEO_ENABLED
{ "camera", lpc_cmd_camera, "Send camera output for current call.",
"'camera on'\t: allow sending of local camera video to remote end.\n"
"'camera off'\t: disable sending of local camera's video to remote end.\n"
},
#endif
{ "chat", lpc_cmd_chat, "Chat with a SIP uri",
"'chat <sip-url> \"message\"' "
": send a chat message \"message\" to the specified destination."
},
{ "terminate", lpc_cmd_terminate, "Terminate a call",
"'terminate' : Terminate the current call\n"
"'terminate <call id>' : Terminate the call with supplied id\n"
"'terminate <all>' : Terminate all the current calls\n"
},
{ "answer", lpc_cmd_answer, "Answer a call",
"'answer' : Answer the current incoming call\n"
"'answer <call id>' : Answer the call with given id\n"
},
{ "pause", lpc_cmd_pause, "pause a call",
"'pause' : pause the current call\n"},
{ "resume", lpc_cmd_resume, "resume a call",
"'resume' : resume the unique call\n"
"'resume <call id>' : hold off the call with given id\n"},
{ "transfer", lpc_cmd_transfer,
"Transfer a call to a specified destination.",
"'transfer <sip-uri>' : transfers the current active call to the destination sip-uri\n"
"'transfer <call id> <sip-uri>': transfers the call with 'id' to the destination sip-uri\n"
"'transfer <call id1> --to-call <call id2>': transfers the call with 'id1' to the destination of call 'id2' (attended transfer)\n"
},
{ "conference", lpc_cmd_conference, "Create and manage an audio conference.",
"'conference add <call id> : join the call with id 'call id' into the audio conference."
"'conference rm <call id> : remove the call with id 'call id' from the audio conference."
},
{ "mute", lpc_cmd_mute_mic,
"Mute microphone and suspend voice transmission."},
#ifdef VIDEO_ENABLED
{ "camera", lpc_cmd_camera, "Send camera output for current call.",
"'camera on'\t: allow sending of local camera video to remote end.\n"
"'camera off'\t: disable sending of local camera's video to remote end.\n"},
#endif
{ "unmute", lpc_cmd_unmute_mic,
"Unmute microphone and resume voice transmission."},
{ "playbackgain", lpc_cmd_playback_gain,
"Adjust playback gain."},
{ "duration", lpc_cmd_duration, "Print duration in seconds of the last call.", NULL },
{ "autoanswer", lpc_cmd_autoanswer, "Show/set auto-answer mode",
"'autoanswer' \t: show current autoanswer mode\n"
"'autoanswer enable'\t: enable autoanswer mode\n"
"'autoanswer disable'\t: disable autoanswer mode<64><65>\n"},
{ "proxy", lpc_cmd_proxy, "Manage proxies",
"'proxy list' : list all proxy setups.\n"
"'proxy add' : add a new proxy setup.\n"
"'proxy remove <index>' : remove proxy setup with number index.\n"
"'proxy use <index>' : use proxy with number index as default proxy.\n"
"'proxy unuse' : don't use a default proxy.\n"
"'proxy show <index>' : show configuration and status of the proxy numbered by index.\n"
"'proxy show default' : show configuration and status of the default proxy.\n"
},
{ "soundcard", lpc_cmd_soundcard, "Manage soundcards",
"'soundcard list' : list all sound devices.\n"
"'soundcard show' : show current sound devices configuration.\n"
"'soundcard use <index>' : select a sound device.\n"
"'soundcard use files' : use .wav files instead of soundcard\n"
},
{ "webcam", lpc_cmd_webcam, "Manage webcams",
"'webcam list' : list all known devices.\n"
"'webcam use <index>' : select a video device.\n"
},
{ "ipv6", lpc_cmd_ipv6, "Use IPV6",
"'ipv6 status' : show ipv6 usage status.\n"
"'ipv6 enable' : enable the use of the ipv6 network.\n"
"'ipv6 disable' : do not use ipv6 network."
},
{ "nat", lpc_cmd_nat, "Set nat address",
"'nat' : show nat settings.\n"
"'nat <addr>' : set nat address.\n"
},
{ "stun", lpc_cmd_stun, "Set stun server address",
"'stun' : show stun settings.\n"
"'stun <addr>' : set stun server address.\n"
{ "duration", lpc_cmd_duration, "Print duration in seconds of the last call.", NULL
},
{ "firewall", lpc_cmd_firewall, "Set firewall policy",
"'firewall' : show current firewall policy.\n"
@ -248,7 +198,6 @@ static LPC_COMMAND commands[] = {
"'firewall ice' : use ice.\n"
"'firewall upnp' : use uPnP IGD.\n"
},
{ "call-logs", lpc_cmd_call_logs, "Calls history", NULL },
{ "friend", lpc_cmd_friend, "Manage friends",
"'friend list [<pattern>]' : list friends.\n"
"'friend call <index>' : call a friend.\n"
@ -257,18 +206,79 @@ static LPC_COMMAND commands[] = {
" there. Don't use '<' '>' around <addr>.\n"
"'friend delete <index>' : remove friend, 'all' removes all\n"
},
{ "ipv6", lpc_cmd_ipv6, "Use IPV6",
"'ipv6 status' : show ipv6 usage status.\n"
"'ipv6 enable' : enable the use of the ipv6 network.\n"
"'ipv6 disable' : do not use ipv6 network."
},
{ "mute", lpc_cmd_mute_mic,
"Mute microphone and suspend voice transmission."
},
{ "nat", lpc_cmd_nat, "Set nat address",
"'nat' : show nat settings.\n"
"'nat <addr>' : set nat address.\n"
},
{ "pause", lpc_cmd_pause, "pause a call",
"'pause' : pause the current call\n"
},
{ "play", lpc_cmd_play, "play a wav file",
"This command has two roles:\n"
"Plays a file instead of capturing from soundcard - only available in file mode (see 'help soundcard')\n"
"Specifies a wav file to be played to play music to far end when putting it on hold (pause)\n"
"'play <wav file>' : play a wav file."
},
{ "playbackgain", lpc_cmd_playback_gain,
"Adjust playback gain."
},
{ "proxy", lpc_cmd_proxy, "Manage proxies",
"'proxy list' : list all proxy setups.\n"
"'proxy add' : add a new proxy setup.\n"
"'proxy remove <index>' : remove proxy setup with number index.\n"
"'proxy use <index>' : use proxy with number index as default proxy.\n"
"'proxy unuse' : don't use a default proxy.\n"
"'proxy show <index>' : show configuration and status of the proxy numbered by index.\n"
"'proxy show default' : show configuration and status of the default proxy.\n"
},
{ "record", lpc_cmd_record, "record to a wav file",
"This feature is available only in file mode (see 'help soundcard')\n"
"'record <wav file>' : record into wav file."
},
{ "quit", lpc_cmd_quit, "Exit linphonec", NULL },
{ (char *)NULL, (lpc_cmd_handler)NULL, (char *)NULL, (char *)NULL }
{ "resume", lpc_cmd_resume, "resume a call",
"'resume' : resume the unique call\n"
"'resume <call id>' : hold off the call with given id\n"
},
{ "soundcard", lpc_cmd_soundcard, "Manage soundcards",
"'soundcard list' : list all sound devices.\n"
"'soundcard show' : show current sound devices configuration.\n"
"'soundcard use <index>' : select a sound device.\n"
"'soundcard use files' : use .wav files instead of soundcard\n"
},
{ "stun", lpc_cmd_stun, "Set stun server address",
"'stun' : show stun settings.\n"
"'stun <addr>' : set stun server address.\n"
},
{ "terminate", lpc_cmd_terminate, "Terminate a call",
"'terminate' : Terminate the current call\n"
"'terminate <call id>' : Terminate the call with supplied id\n"
"'terminate <all>' : Terminate all the current calls\n"
},
{ "transfer", lpc_cmd_transfer,
"Transfer a call to a specified destination.",
"'transfer <sip-uri>' : transfers the current active call to the destination sip-uri\n"
"'transfer <call id> <sip-uri>': transfers the call with 'id' to the destination sip-uri\n"
"'transfer <call id1> --to-call <call id2>': transfers the call with 'id1' to the destination of call 'id2' (attended transfer)\n"
},
{ "unmute", lpc_cmd_unmute_mic,
"Unmute microphone and resume voice transmission."
},
{ "webcam", lpc_cmd_webcam, "Manage webcams",
"'webcam list' : list all known devices.\n"
"'webcam use <index>' : select a video device.\n"
},
{ "quit", lpc_cmd_quit, "Exit linphonec", NULL
},
{ (char *)NULL, (lpc_cmd_handler)NULL, (char *)NULL, (char *)NULL
}
};
@ -292,7 +302,8 @@ static LPC_COMMAND advanced_commands[] = {
{ "nortp-on-audio-mute", lpc_cmd_rtp_no_xmit_on_audio_mute,
"Set the rtp_no_xmit_on_audio_mute configuration parameter",
" If set to 1 then rtp transmission will be muted when\n"
" audio is muted , otherwise rtp is always sent."},
" audio is muted , otherwise rtp is always sent."
},
#ifdef VIDEO_ENABLED
{ "vwindow", lpc_cmd_video_window, "Control video display window",
"'vwindow show': shows video window\n"
@ -316,14 +327,16 @@ static LPC_COMMAND advanced_commands[] = {
{ "preview-snapshot", lpc_cmd_preview_snapshot, "Take a snapshot of currently captured video stream",
"'preview-snapshot <file path>': take a snapshot and records it in jpeg format into the supplied path\n"
},
{ "vfureq", lpc_cmd_vfureq, "Request the other side to send VFU for the current call"},
{ "vfureq", lpc_cmd_vfureq, "Request the other side to send VFU for the current call"
},
#endif
{ "states", lpc_cmd_states, "Show internal states of liblinphone, registrations and calls, according to linphonecore.h definitions",
"'states global': shows global state of liblinphone \n"
"'states calls': shows state of calls\n"
"'states proxies': shows state of proxy configurations"
},
{ "register", lpc_cmd_register, "Register in one line to a proxy" , "register <sip identity> <sip proxy> <password>"},
{ "register", lpc_cmd_register, "Register in one line to a proxy" , "register <sip identity> <sip proxy> <password>"
},
{ "unregister", lpc_cmd_unregister, "Unregister from default proxy", NULL },
{ "status", lpc_cmd_status, "Print various status information",
"'status register' \t: print status concerning registration\n"

View file

@ -161,6 +161,7 @@ static int trace_level = 0;
static char *logfile_name = NULL;
static char configfile_name[PATH_MAX];
static char zrtpsecrets[PATH_MAX];
static char usr_certificates_path[PATH_MAX];
static const char *factory_configfile_name=NULL;
static char *sip_addr_to_call = NULL; /* for autocall */
static int window_id = 0; /* 0=standalone window, or window id for embedding video */
@ -535,7 +536,7 @@ char *linphonec_readline(char *prompt){
fprintf(stdout,"%s",prompt);
fflush(stdout);
while(1){
ms_mutex_lock(&prompt_mutex);
if (have_prompt){
char *ret=strdup(received_prompt);
@ -680,6 +681,8 @@ linphonec_init(int argc, char **argv)
getenv("HOME"));
snprintf(zrtpsecrets, PATH_MAX, "%s/.linphone-zidcache",
getenv("HOME"));
snprintf(usr_certificates_path, PATH_MAX, "%s/.linphone-usr-crt",
getenv("HOME"));
#elif defined(_WIN32_WCE)
strncpy(configfile_name,PACKAGE_DIR "\\linphonerc",PATH_MAX);
mylogfile=fopen(PACKAGE_DIR "\\" "linphonec.log","w");
@ -689,6 +692,8 @@ linphonec_init(int argc, char **argv)
getenv("APPDATA"));
snprintf(zrtpsecrets, PATH_MAX, "%s/Linphone/linphone-zidcache",
getenv("APPDATA"));
snprintf(usr_certificates_path, PATH_MAX, "%s/Linphone/linphone-usr-crt",
getenv("APPDATA"));
#endif
/* Handle configuration filename changes */
switch (handle_configfile_migration())
@ -745,6 +750,7 @@ linphonec_init(int argc, char **argv)
linphone_core_set_user_agent(linphonec,"Linphonec", LINPHONE_VERSION);
linphone_core_set_zrtp_secrets_file(linphonec,zrtpsecrets);
linphone_core_set_user_certificates_path(linphonec,usr_certificates_path);
linphone_core_enable_video_capture(linphonec, vcap_enabled);
linphone_core_enable_video_display(linphonec, display_enabled);
if (display_enabled && window_id != 0)
@ -925,7 +931,8 @@ print_usage (int exit_status)
" -D enable video display only (disabled by default)\n"
" -S show general state messages (disabled by default)\n"
" --wid windowid force embedding of video window into provided windowid (disabled by default)\n"
" -v or --version display version and exits.\n");
" -v or --version display version and exits.\n"
);
exit(exit_status);
}

View file

@ -160,13 +160,13 @@ test_numbers_LDADD=liblinphone.la $(liblinphone_la_LIBADD)
endif
AM_CPPFLAGS=\
-I$(top_srcdir) -I$(top_srcdir)/include -I$(builddir)
-I$(top_srcdir) -I$(top_srcdir)/include -I$(builddir) \
$(ORTP_CFLAGS) \
$(MEDIASTREAMER_CFLAGS)
COMMON_CFLAGS=\
$(STRICT_OPTIONS) \
-DIN_LINPHONE \
$(ORTP_CFLAGS) \
$(MEDIASTREAMER_CFLAGS) \
$(SIPSTACK_CFLAGS) \
$(LIBSOUP_CFLAGS) \
-DENABLE_TRACE \

View file

@ -16,9 +16,6 @@
#include "ortp/rtpsession.h"
#include "linphonecore.h"
#include "linphonecore_utils.h"
#ifndef USE_BELLESIP
#include "eXosip2/eXosip_transport_hook.h"
#endif
#include "private.h"
#ifdef ANDROID
@ -97,7 +94,7 @@ RtpTransport *TunnelManager::createRtpTransport(int port){
void TunnelManager::startClient() {
ms_message("TunnelManager: Starting tunnel client");
mTunnelClient = new TunnelClient();
mTunnelClient = new TunnelClient(TRUE);
mTunnelClient->setCallback((TunnelClientController::StateCallback)tunnelCallback,this);
list<ServerAddr>::iterator it;
for(it=mServerAddrs.begin();it!=mServerAddrs.end();++it){
@ -122,18 +119,16 @@ int TunnelManager::customSendto(struct _RtpTransport *t, mblk_t *msg , int flags
}
int TunnelManager::customRecvfrom(struct _RtpTransport *t, mblk_t *msg, int flags, struct sockaddr *from, socklen_t *fromlen){
memset(&msg->recv_addr,0,sizeof(msg->recv_addr));
int err=((TunnelSocket*)t->data)->recvfrom(msg->b_wptr,msg->b_datap->db_lim-msg->b_datap->db_base,from,*fromlen);
//to make ice happy
inet_aton(((TunnelManager*)((TunnelSocket*)t->data)->getUserPointer())->mLocalAddr,&msg->recv_addr.addr.ipi_addr);
if (err>0) return err;
return 0;
}
TunnelManager::TunnelManager(LinphoneCore* lc) :
mCore(lc),
#ifndef USE_BELLESIP
mSipSocket(NULL),
mExosipTransport(NULL),
#endif
mMode(LinphoneTunnelModeDisable),
mState(disabled),
mTunnelizeSipPackets(true),
@ -153,6 +148,7 @@ TunnelManager::TunnelManager(LinphoneCore* lc) :
mVTable = linphone_core_v_table_new();
mVTable->network_reachable = networkReachableCb;
linphone_core_add_listener(mCore, mVTable);
linphone_core_get_local_ip_for(AF_INET, NULL, mLocalAddr);
}
TunnelManager::~TunnelManager(){
@ -371,6 +367,7 @@ void TunnelManager::networkReachableCb(LinphoneCore *lc, bool_t reachable) {
tunnel->startAutoDetection();
tunnel->mState = autodetecting;
}
linphone_core_get_local_ip_for(AF_INET, NULL,tunnel->mLocalAddr);
}
bool TunnelManager::startAutoDetection() {

View file

@ -200,6 +200,7 @@ namespace belledonnecomm {
LinphoneRtpTransportFactories mTransportFactories;
Mutex mMutex;
std::queue<Event> mEvq;
char mLocalAddr[64];
};
/**

View file

@ -154,11 +154,27 @@ char *linphone_address_as_string_uri_only(const LinphoneAddress *u){
/**
* Returns true if address refers to a secure location (sips)
* @deprecated use linphone_address_get_secure()
**/
bool_t linphone_address_is_secure(const LinphoneAddress *uri){
return sal_address_is_secure(uri);
}
/**
* Returns true if address refers to a secure location (sips)
**/
bool_t linphone_address_get_secure(const LinphoneAddress *uri){
return sal_address_is_secure(uri);
}
/**
* Make the address refer to a secure location (sips scheme)
* @param enabled TRUE if address is requested to be secure.
**/
void linphone_address_set_secure(LinphoneAddress *addr, bool_t enabled){
sal_address_set_secure(addr, enabled);
}
/**
* returns true if address is a routable sip address
*/

View file

@ -49,6 +49,12 @@ const char *sal_address_get_scheme(const SalAddress *addr){
return NULL;
}
void sal_address_set_secure(SalAddress *addr, bool_t enabled){
belle_sip_header_address_t* header_addr = BELLE_SIP_HEADER_ADDRESS(addr);
belle_sip_uri_t* uri = belle_sip_header_address_get_uri(header_addr);
if (uri) belle_sip_uri_set_secure(uri,enabled);
}
bool_t sal_address_is_secure(const SalAddress *addr){
belle_sip_header_address_t* header_addr = BELLE_SIP_HEADER_ADDRESS(addr);
belle_sip_uri_t* uri = belle_sip_header_address_get_uri(header_addr);

View file

@ -1073,6 +1073,45 @@ void sal_signing_key_parse_file(SalAuthInfo* auth_info, const char* path, const
if (auth_info->key) belle_sip_object_ref((belle_sip_object_t *) auth_info->key);
}
/**
* Parse a directory to get a certificate with the given subject common name
*
*/
void sal_certificates_chain_parse_directory(char **certificate_pem, char **key_pem, char **fingerprint, const char* path, const char *subject, SalCertificateRawFormat format, bool_t generate_certificate, bool_t generate_dtls_fingerprint) {
belle_sip_certificates_chain_t *certificate = NULL;
belle_sip_signing_key_t *key = NULL;
*certificate_pem = NULL;
*key_pem = NULL;
if (belle_sip_get_certificate_and_pkey_in_dir(path, subject, &certificate, &key, (belle_sip_certificate_raw_format_t)format) == 0) {
*certificate_pem = belle_sip_certificates_chain_get_pem(certificate);
*key_pem = belle_sip_signing_key_get_pem(key);
ms_message("Retrieve certificate with CN=%s successful\n", subject);
} else {
if (generate_certificate == TRUE) {
if ( belle_sip_generate_self_signed_certificate(path, subject, &certificate, &key) == 0) {
*certificate_pem = belle_sip_certificates_chain_get_pem(certificate);
*key_pem = belle_sip_signing_key_get_pem(key);
ms_message("Generate self-signed certificate with CN=%s successful\n", subject);
}
}
}
/* generate the fingerprint as described in RFC4572 if needed */
if ((generate_dtls_fingerprint == TRUE) && (fingerprint != NULL)) {
if (*fingerprint != NULL) {
ms_free(*fingerprint);
}
*fingerprint = belle_sip_certificates_chain_get_fingerprint(certificate);
}
/* free key and certificate */
if ( certificate != NULL ) {
belle_sip_object_unref(certificate);
}
if ( key != NULL ) {
belle_sip_object_unref(key);
}
}
unsigned char * sal_get_random_bytes(unsigned char *ret, size_t size){
return belle_sip_random_bytes(ret,size);
}

View file

@ -97,6 +97,7 @@ static int set_sdp(belle_sip_message_t *msg,belle_sdp_session_description_t* ses
error = belle_sip_object_marshal(BELLE_SIP_OBJECT(session_desc),buff,bufLen,&length);
if( error != BELLE_SIP_OK ){
bufLen *= 2;
length = 0;
buff = belle_sip_realloc(buff,bufLen);
}
}
@ -388,7 +389,8 @@ static void unsupported_method(belle_sip_server_transaction_t* server_transactio
*
**/
static int extract_sdp(SalOp *op, belle_sip_message_t* message,belle_sdp_session_description_t** session_desc, SalReason *error) {
belle_sip_header_content_type_t* content_type=belle_sip_message_get_header_by_type(message,belle_sip_header_content_type_t);
const char *body;
belle_sip_header_content_type_t* content_type;
if (op&&op->sdp_removal){
ms_error("Removed willingly SDP because sal_call_enable_sdp_removal was set to TRUE.");
@ -396,11 +398,18 @@ static int extract_sdp(SalOp *op, belle_sip_message_t* message,belle_sdp_session
*error=SalReasonNotAcceptable;
return -1;
}
body = belle_sip_message_get_body(message);
if(body == NULL) {
*session_desc = NULL;
return 0;
}
content_type = belle_sip_message_get_header_by_type(message,belle_sip_header_content_type_t);
if (content_type){
if (strcmp("application",belle_sip_header_content_type_get_type(content_type))==0
&& strcmp("sdp",belle_sip_header_content_type_get_subtype(content_type))==0) {
*session_desc=belle_sdp_session_description_parse(belle_sip_message_get_body(message));
*session_desc=belle_sdp_session_description_parse(body);
if (*session_desc==NULL) {
ms_error("Failed to parse SDP message.");
*error=SalReasonNotAcceptable;

View file

@ -210,10 +210,18 @@ static void stream_description_to_sdp ( belle_sdp_session_description_t *session
/*only add a c= line within the stream description if address are differents*/
if (rtp_addr[0]!='\0' && strcmp(rtp_addr,md->addr)!=0){
bool_t inet6;
belle_sdp_connection_t *connection;
if (strchr(rtp_addr,':')!=NULL){
inet6=TRUE;
}else inet6=FALSE;
belle_sdp_media_description_set_connection(media_desc,belle_sdp_connection_create("IN", inet6 ? "IP6" : "IP4", rtp_addr));
connection = belle_sdp_connection_create("IN", inet6 ? "IP6" : "IP4", rtp_addr);
if (ms_is_multicast(rtp_addr)) {
/*remove session cline in case of multicast*/
belle_sdp_session_description_set_connection(session_desc,NULL);
if (inet6 == FALSE)
belle_sdp_connection_set_ttl(connection,stream->ttl);
}
belle_sdp_media_description_set_connection(media_desc,connection);
}
if ( stream->bandwidth>0 )
@ -233,6 +241,29 @@ static void stream_description_to_sdp ( belle_sdp_session_description_t *session
}else break;
}
}
/* insert DTLS session attribute if needed */
if ((stream->proto == SalProtoUdpTlsRtpSavpf) || (stream->proto == SalProtoUdpTlsRtpSavp)) {
char* ssrc_attribute = ms_strdup_printf("%u cname:%s",htonl(stream->rtp_ssrc),stream->rtcp_cname);
if ((stream->dtls_role != SalDtlsRoleInvalid) && (strlen(stream->dtls_fingerprint)>0)) {
switch(stream->dtls_role) {
case SalDtlsRoleIsClient:
belle_sdp_media_description_add_attribute(media_desc, belle_sdp_attribute_create("setup","active"));
break;
case SalDtlsRoleIsServer:
belle_sdp_media_description_add_attribute(media_desc, belle_sdp_attribute_create("setup","passive"));
break;
case SalDtlsRoleUnset:
default:
belle_sdp_media_description_add_attribute(media_desc, belle_sdp_attribute_create("setup","actpass"));
break;
}
belle_sdp_media_description_add_attribute(media_desc, belle_sdp_attribute_create("fingerprint",stream->dtls_fingerprint));
}
belle_sdp_media_description_add_attribute(media_desc, belle_sdp_attribute_create("ssrc",ssrc_attribute)); /* truc de Jehan a virer? */
ms_free(ssrc_attribute);
}
switch ( stream->dir ) {
case SalStreamSendRecv:
/*dir="sendrecv";*/
@ -301,6 +332,13 @@ static void stream_description_to_sdp ( belle_sdp_session_description_t *session
belle_sip_object_unref((belle_sip_object_t*)media_attribute);
}
}
/*
* rfc5576
* 4.1. The "ssrc" Media Attribute
* <ssrc-id> is the synchronization source (SSRC) ID of the
* source being described, interpreted as a 32-bit unsigned integer in
* network byte order and represented in decimal.*/
belle_sdp_session_description_add_media_description(session_desc, media_desc);
}
@ -351,6 +389,23 @@ belle_sdp_session_description_t * media_description_to_sdp ( const SalMediaDescr
if (desc->ice_pwd[0] != '\0') belle_sdp_session_description_add_attribute(session_desc, belle_sdp_attribute_create("ice-pwd",desc->ice_pwd));
if (desc->ice_ufrag[0] != '\0') belle_sdp_session_description_add_attribute(session_desc, belle_sdp_attribute_create("ice-ufrag",desc->ice_ufrag));
/* insert DTLS session attribute if needed */
if ((desc->dtls_role != SalDtlsRoleInvalid) && (strlen(desc->dtls_fingerprint)>0)) {
switch(desc->dtls_role) {
case SalDtlsRoleIsClient:
belle_sdp_session_description_add_attribute(session_desc, belle_sdp_attribute_create("setup","active"));
break;
case SalDtlsRoleIsServer:
belle_sdp_session_description_add_attribute(session_desc, belle_sdp_attribute_create("setup","passive"));
break;
case SalDtlsRoleUnset:
default:
belle_sdp_session_description_add_attribute(session_desc, belle_sdp_attribute_create("setup","actpass"));
break;
}
belle_sdp_session_description_add_attribute(session_desc, belle_sdp_attribute_create("fingerprint",desc->dtls_fingerprint));
}
if (desc->rtcp_xr.enabled == TRUE) {
belle_sdp_session_description_add_attribute(session_desc, create_rtcp_xr_attribute(&desc->rtcp_xr));
}
@ -450,12 +505,15 @@ static void sdp_parse_media_ice_parameters(belle_sdp_media_description_t *media_
att_name = belle_sdp_attribute_get_name(attribute);
value = belle_sdp_attribute_get_value(attribute);
if ((keywordcmp("candidate", att_name) == 0) && (value != NULL)) {
if ( (nb_ice_candidates < sizeof (stream->ice_candidates)/sizeof(SalIceCandidate))
&& (keywordcmp("candidate", att_name) == 0)
&& (value != NULL)) {
SalIceCandidate *candidate = &stream->ice_candidates[nb_ice_candidates];
int nb = sscanf(value, "%s %u UDP %u %s %d typ %s raddr %s rport %d",
candidate->foundation, &candidate->componentID, &candidate->priority, candidate->addr, &candidate->port,
char proto[4];
int nb = sscanf(value, "%s %u %3s %u %s %d typ %s raddr %s rport %d",
candidate->foundation, &candidate->componentID, proto, &candidate->priority, candidate->addr, &candidate->port,
candidate->type, candidate->raddr, &candidate->rport);
if ((nb == 6) || (nb == 8)) nb_ice_candidates++;
if (strcasecmp("udp",proto)==0 && ((nb == 7) || (nb == 9))) nb_ice_candidates++;
else memset(candidate, 0, sizeof(*candidate));
} else if ((keywordcmp("remote-candidates", att_name) == 0) && (value != NULL)) {
SalIceRemoteCandidate candidate;
@ -646,12 +704,17 @@ static SalStreamDescription * sdp_to_stream_description(SalMediaDescription *md,
stream->proto = SalProtoRtpAvpf;
} else if (strcasecmp(proto, "RTP/SAVPF") == 0) {
stream->proto = SalProtoRtpSavpf;
} else if (strcasecmp(proto, "UDP/TLS/RTP/SAVP") == 0) {
stream->proto = SalProtoUdpTlsRtpSavp;
} else if (strcasecmp(proto, "UDP/TLS/RTP/SAVPF") == 0) {
stream->proto = SalProtoUdpTlsRtpSavpf;
} else {
strncpy(stream->proto_other,proto,sizeof(stream->proto_other)-1);
}
}
if ( ( cnx=belle_sdp_media_description_get_connection ( media_desc ) ) && belle_sdp_connection_get_address ( cnx ) ) {
strncpy ( stream->rtp_addr,belle_sdp_connection_get_address ( cnx ), sizeof ( stream->rtp_addr ) -1 );
stream->ttl=belle_sdp_connection_get_ttl(cnx);
}
stream->rtp_port=belle_sdp_media_get_media_port ( media );
@ -701,6 +764,36 @@ static SalStreamDescription * sdp_to_stream_description(SalMediaDescription *md,
}
}
/* Read DTLS specific attributes : check is some are found in the stream description otherwise copy the session description one(which are at least set to Invalid) */
stream->dtls_role = SalDtlsRoleInvalid;
stream->dtls_fingerprint[0] = '\0';
if (((stream->proto == SalProtoUdpTlsRtpSavpf) || (stream->proto == SalProtoUdpTlsRtpSavp))) {
attribute=belle_sdp_media_description_get_attribute(media_desc,"setup");
if (attribute && (value=belle_sdp_attribute_get_value(attribute))!=NULL){
if (strncmp(value, "actpass", 7) == 0) {
stream->dtls_role = SalDtlsRoleUnset;
} else if (strncmp(value, "active", 6) == 0) {
stream->dtls_role = SalDtlsRoleIsClient;
} else if (strncmp(value, "passive", 7) == 0) {
stream->dtls_role = SalDtlsRoleIsServer;
}
if (stream->dtls_role != SalDtlsRoleInvalid || md->dtls_role != SalDtlsRoleInvalid) {
attribute=belle_sdp_media_description_get_attribute(media_desc,"fingerprint");
if (attribute && (value=belle_sdp_attribute_get_value(attribute))!=NULL){
strncpy(stream->dtls_fingerprint, value, sizeof(stream->dtls_fingerprint)-1);
} else {
/* no valid stream attributes, get them from session */
if (stream->dtls_role == SalDtlsRoleInvalid) stream->dtls_role = md->dtls_role;
strncpy(stream->dtls_fingerprint, md->dtls_fingerprint, strlen(md->dtls_fingerprint)+1);
}
}
} else { /* no setup attribute found in the stream, get the one from the session */
stream->dtls_role = md->dtls_role;
strncpy(stream->dtls_fingerprint, md->dtls_fingerprint, strlen(md->dtls_fingerprint)+1);
}
}
/* Read crypto lines if any */
if ((stream->proto == SalProtoRtpSavpf) || (stream->proto == SalProtoRtpSavp)) {
sdp_parse_media_crypto_parameters(media_desc, stream);
@ -756,6 +849,27 @@ int sdp_to_media_description ( belle_sdp_session_description_t *session_desc, S
desc->dir=SalStreamInactive;
}
/* Read dtls specific session attributes if any (setup and fingerprint - rfc5763) */
/* Presence of a valid dtls offer(setup and fingerprint attribute) is set in media Description by a dtls_fingerprint string longer than 0
* and a dtls_role != SalDtlsRoleInvalid */
desc->dtls_role = SalDtlsRoleInvalid;
desc->dtls_fingerprint[0] = '\0';
value=belle_sdp_session_description_get_attribute_value(session_desc,"setup");
if (value){
if (strncmp(value, "actpass", 7) == 0) {
desc->dtls_role = SalDtlsRoleUnset;
} else if (strncmp(value, "active", 6) == 0) {
desc->dtls_role = SalDtlsRoleIsClient;
} else if (strncmp(value, "passive", 7) == 0) {
desc->dtls_role = SalDtlsRoleIsServer;
}
}
value=belle_sdp_session_description_get_attribute_value(session_desc,"fingerprint");
if (value){
strncpy(desc->dtls_fingerprint, value, sizeof(desc->dtls_fingerprint)-1);
}
/* Get ICE remote ufrag and remote pwd, and ice_lite flag */
value=belle_sdp_session_description_get_attribute_value(session_desc,"ice-ufrag");
if (value) strncpy(desc->ice_ufrag, value, sizeof(desc->ice_ufrag) - 1);

View file

@ -27,6 +27,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
SalMediaProto get_proto_from_call_params(const LinphoneCallParams *params) {
if ((params->media_encryption == LinphoneMediaEncryptionSRTP) && params->avpf_enabled) return SalProtoRtpSavpf;
if (params->media_encryption == LinphoneMediaEncryptionSRTP) return SalProtoRtpSavp;
if ((params->media_encryption == LinphoneMediaEncryptionDTLS) && params->avpf_enabled) return SalProtoUdpTlsRtpSavpf;
if (params->media_encryption == LinphoneMediaEncryptionDTLS) return SalProtoUdpTlsRtpSavp;
if (params->avpf_enabled) return SalProtoRtpAvpf;
return SalProtoRtpAvp;
}
@ -49,6 +51,7 @@ LinphoneCallParams * linphone_call_params_copy(const LinphoneCallParams *cp){
* The management of the custom headers is not optimal. We copy everything while ref counting would be more efficient.
*/
if (cp->custom_headers) ncp->custom_headers=sal_custom_header_clone(cp->custom_headers);
return ncp;
}
@ -156,6 +159,21 @@ bool_t linphone_call_params_video_enabled(const LinphoneCallParams *cp){
return cp->has_video;
}
LinphoneCallParamsMediaDirection linphone_call_params_get_audio_direction(const LinphoneCallParams *cp) {
return cp->audio_dir;
}
LinphoneCallParamsMediaDirection linphone_call_params_get_video_direction(const LinphoneCallParams *cp) {
return cp->video_dir;
}
void linphone_call_params_set_audio_direction(LinphoneCallParams *cp,LinphoneCallParamsMediaDirection dir) {
cp->audio_dir=dir;
}
void linphone_call_params_set_video_direction(LinphoneCallParams *cp,LinphoneCallParamsMediaDirection dir) {
cp->video_dir=dir;
}
/*******************************************************************************

View file

@ -30,6 +30,20 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
/*******************************************************************************
* Structures and enums *
******************************************************************************/
/**
* Indicates for a given media the stream direction
* */
enum _LinphoneCallParamsMediaDirection {
LinphoneCallParamsMediaDirectionInactive, /** No active media not supported yet*/
LinphoneCallParamsMediaDirectionSendOnly, /** Send only mode*/
LinphoneCallParamsMediaDirectionRecvOnly, /** recv only mode*/
LinphoneCallParamsMediaDirectionSendRecv, /*send receive mode not supported yet*/
};
/**
* Typedef for enum
**/
typedef enum _LinphoneCallParamsMediaDirection LinphoneCallParamsMediaDirection;
/**
* Private structure definition for LinphoneCallParams.
@ -247,6 +261,34 @@ LINPHONE_PUBLIC void linphone_call_params_set_session_name(LinphoneCallParams *c
**/
LINPHONE_PUBLIC bool_t linphone_call_params_video_enabled(const LinphoneCallParams *cp);
/**
* Get the audio stream direction.
* @param[in] cl LinphoneCallParams object
* @return The audio stream direction associated with the call params.
**/
LINPHONE_PUBLIC LinphoneCallParamsMediaDirection linphone_call_params_get_audio_direction(const LinphoneCallParams *cp);
/**
* Get the video stream direction.
* @param[in] cl LinphoneCallParams object
* @return The video stream direction associated with the call params.
**/
LINPHONE_PUBLIC LinphoneCallParamsMediaDirection linphone_call_params_get_video_direction(const LinphoneCallParams *cp);
/**
* Set the audio stream direction. Only relevant for multicast
* @param[in] cl LinphoneCallParams object
* @param[in] The audio stream direction associated with this call params.
**/
/*LINPHONE_PUBLIC void linphone_call_params_set_audio_direction(LinphoneCallParams *cp, LinphoneCallParamsMediaDirection dir);*/
/**
* Set the video stream direction. Only relevant for multicast
* @param[in] cl LinphoneCallParams object
* @param[in] The video stream direction associated with this call params.
**/
/*LINPHONE_PUBLIC void linphone_call_params_set_video_direction(LinphoneCallParams *cp, LinphoneCallParamsMediaDirection dir);*/
/*******************************************************************************
* Reference and user data handling functions *

View file

@ -338,7 +338,7 @@ static void call_received(SalOp *h){
linphone_core_add_call(lc,call);
linphone_call_ref(call); /*prevent the call from being destroyed while we are notifying, if the user declines within the state callback */
if ((_linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (call->ice_session != NULL)) {
if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (call->ice_session != NULL)) {
/* Defer ringing until the end of the ICE candidates gathering process. */
ms_message("Defer ringing to gather ICE candidates");
return;
@ -380,7 +380,11 @@ static void try_early_media_forking(LinphoneCall *call, SalMediaDescription *md)
RtpSession *session=ms->sessions.rtp_session;
const char *rtp_addr=new_stream->rtp_addr[0]!='\0' ? new_stream->rtp_addr : md->addr;
const char *rtcp_addr=new_stream->rtcp_addr[0]!='\0' ? new_stream->rtcp_addr : md->addr;
rtp_session_add_aux_remote_addr_full(session,rtp_addr,new_stream->rtp_port,rtcp_addr,new_stream->rtcp_port);
if (ms_is_multicast(rtp_addr))
ms_message("Multicast addr [%s/%i] does not need auxiliary rtp's destination for call [%p]",
rtp_addr,new_stream->rtp_port,call);
else
rtp_session_add_aux_remote_addr_full(session,rtp_addr,new_stream->rtp_port,rtcp_addr,new_stream->rtcp_port);
}
}
}
@ -425,8 +429,15 @@ static void call_ringing(SalOp *h){
if (call->audiostream && audio_stream_started(call->audiostream)){
/*streams already started */
try_early_media_forking(call,md);
return;
#ifdef VIDEO_ENABLED
if (call->videostream){
/*just request for iframe*/
video_stream_send_vfu(call->videostream);
}
#endif
return;
}
linphone_core_notify_show_interface(lc);
linphone_core_notify_display_status(lc,_("Early media."));
linphone_call_set_state(call,LinphoneCallOutgoingEarlyMedia,"Early media");
@ -614,7 +625,7 @@ static void call_updated_by_remote(LinphoneCore *lc, LinphoneCall *call, bool_t
}
}
if (call->state==LinphoneCallStreamsRunning) {
if ( call->state == LinphoneCallStreamsRunning) {
/*reINVITE and in-dialogs UPDATE go here*/
linphone_core_notify_display_status(lc,_("Call is updated by remote."));
call->defer_update=FALSE;
@ -622,8 +633,21 @@ static void call_updated_by_remote(LinphoneCore *lc, LinphoneCall *call, bool_t
if (call->defer_update==FALSE){
linphone_core_accept_call_update(lc,call,NULL);
}
if (rmd==NULL)
if (rmd==NULL){
call->expect_media_in_ack=TRUE;
}
} else if( call->state == LinphoneCallPausedByRemote ){
/* Case where no SDP is present and we were paused by remote.
* We send back an ACK with our SDP and expect the remote to send its own.
* No state change here until an answer is received. */
call->defer_update=FALSE;
if (call->defer_update==FALSE){
_linphone_core_accept_call_update(lc,call,NULL,call->state,linphone_call_state_to_string(call->state));
}
if (rmd==NULL){
call->expect_media_in_ack=TRUE;
}
} else if (is_update){ /*SIP UPDATE case, can occur in early states*/
linphone_call_set_state(call, LinphoneCallEarlyUpdatedByRemote, "EarlyUpdatedByRemote");
_linphone_core_accept_call_update(lc,call,NULL,call->prevstate,linphone_call_state_to_string(call->prevstate));

View file

@ -106,7 +106,8 @@ void linphone_event_set_publish_state(LinphoneEvent *lev, LinphonePublishState s
linphone_core_notify_publish_state_changed(lev->lc,lev,state);
switch(state){
case LinphonePublishCleared:
linphone_event_unref(lev);
if (lev->expires!=-1)
linphone_event_unref(lev);
break;
case LinphonePublishOk:
case LinphonePublishError:

View file

@ -53,6 +53,11 @@
/**
* @defgroup media_parameters Controlling media parameters
*<b> Multicast </b>
*<br> Call using rtp multicast addresses are supported for both audio and video with some limitations. Limitations are, no stun, no ice, no encryption.
*<br><li> Incoming call with multicast address are automatically accepted. The called party switches in a media receive only mode.
*<br><li> Outgoing call willing to send media to a multicast address can activate multicast using \link linphone_core_enable_video_multicast\endlink or
*\link linphone_core_enable_audio_multicast\endlink . The calling party switches in a media listen send only mode.
**/
/**

View file

@ -35,7 +35,7 @@ import org.linphone.core.LinphoneCore.RegistrationState;
import org.linphone.core.LinphoneCore.RemoteProvisioningState;
import org.linphone.core.LinphoneCoreException;
import org.linphone.core.LinphoneCoreFactory;
import org.linphone.core.LinphoneCoreListener.LinphoneListener;
import org.linphone.core.LinphoneCoreListener;
import org.linphone.core.LinphoneEvent;
import org.linphone.core.LinphoneFriend;
import org.linphone.core.LinphoneFriend.SubscribePolicy;
@ -61,7 +61,7 @@ import org.linphone.core.SubscriptionState;
* @author Guillaume Beraudo
*
*/
public class TutorialBuddyStatus implements LinphoneListener {
public class TutorialBuddyStatus implements LinphoneCoreListener {
private boolean running;
private TutorialNotifier TutorialNotifier;

View file

@ -35,7 +35,7 @@ import org.linphone.core.LinphoneCore.RegistrationState;
import org.linphone.core.LinphoneCore.RemoteProvisioningState;
import org.linphone.core.LinphoneCoreException;
import org.linphone.core.LinphoneCoreFactory;
import org.linphone.core.LinphoneCoreListener.LinphoneListener;
import org.linphone.core.LinphoneCoreListener;
import org.linphone.core.LinphoneEvent;
import org.linphone.core.LinphoneFriend;
import org.linphone.core.LinphoneInfoMessage;
@ -59,7 +59,7 @@ import org.linphone.core.SubscriptionState;
* @author Guillaume Beraudo
*
*/
public class TutorialChatRoom implements LinphoneListener, LinphoneChatMessage.StateListener {
public class TutorialChatRoom implements LinphoneCoreListener, LinphoneChatMessage.StateListener {
private boolean running;
private TutorialNotifier TutorialNotifier;

View file

@ -35,7 +35,7 @@ import org.linphone.core.LinphoneCore.RegistrationState;
import org.linphone.core.LinphoneCore.RemoteProvisioningState;
import org.linphone.core.LinphoneCoreException;
import org.linphone.core.LinphoneCoreFactory;
import org.linphone.core.LinphoneCoreListener.LinphoneListener;
import org.linphone.core.LinphoneCoreListener;
import org.linphone.core.LinphoneEvent;
import org.linphone.core.LinphoneFriend;
import org.linphone.core.LinphoneInfoMessage;
@ -53,7 +53,7 @@ import org.linphone.core.SubscriptionState;
* @author Guillaume Beraudo
*
*/
public class TutorialHelloWorld implements LinphoneListener {
public class TutorialHelloWorld implements LinphoneCoreListener {
private boolean running;
private TutorialNotifier TutorialNotifier;

View file

@ -35,7 +35,7 @@ import org.linphone.core.LinphoneCore.RegistrationState;
import org.linphone.core.LinphoneCore.RemoteProvisioningState;
import org.linphone.core.LinphoneCoreException;
import org.linphone.core.LinphoneCoreFactory;
import org.linphone.core.LinphoneCoreListener.LinphoneListener;
import org.linphone.core.LinphoneCoreListener;
import org.linphone.core.LinphoneEvent;
import org.linphone.core.LinphoneFriend;
import org.linphone.core.LinphoneInfoMessage;
@ -58,7 +58,7 @@ import org.linphone.core.SubscriptionState;
* @author Guillaume Beraudo
*
*/
public class TutorialRegistration implements LinphoneListener {
public class TutorialRegistration implements LinphoneCoreListener {
private boolean running;
private TutorialNotifier TutorialNotifier;

View file

@ -159,8 +159,12 @@ static void propagate_encryption_changed(LinphoneCall *call){
call->current_params->media_encryption=LinphoneMediaEncryptionNone;
linphone_core_notify_call_encryption_changed(call->core, call, FALSE, call->auth_token);
} else {
ms_message("All streams are encrypted");
call->current_params->media_encryption=LinphoneMediaEncryptionZRTP;
if (call->auth_token) {/* ZRTP only is using auth_token */
call->current_params->media_encryption=LinphoneMediaEncryptionZRTP;
} else { /* otherwise it must be DTLS as SDES doesn't go through this function */
call->current_params->media_encryption=LinphoneMediaEncryptionDTLS;
}
ms_message("All streams are encrypted key exchanged using %s", call->current_params->media_encryption==LinphoneMediaEncryptionZRTP?"ZRTP":call->current_params->media_encryption==LinphoneMediaEncryptionDTLS?"DTLS":"Unknown mechanism");
linphone_core_notify_call_encryption_changed(call->core, call, TRUE, call->auth_token);
}
}
@ -172,8 +176,10 @@ static void linphone_call_audiostream_encryption_changed(void *data, bool_t encr
call = (LinphoneCall *)data;
if (encrypted) {
snprintf(status,sizeof(status)-1,_("Authentication token is %s"),call->auth_token);
linphone_core_notify_display_status(call->core, status);
if (call->params->media_encryption==LinphoneMediaEncryptionZRTP) { /* if encryption is DTLS, no status to be displayed */
snprintf(status,sizeof(status)-1,_("Authentication token is %s"),call->auth_token);
linphone_core_notify_display_status(call->core, status);
}
}
propagate_encryption_changed(call);
@ -334,6 +340,16 @@ static MSList * create_telephone_events(LinphoneCore *lc, const MSList *codecs){
return ret;
}
static MSList *create_special_payload_types(LinphoneCore *lc, const MSList *codecs){
MSList *ret=create_telephone_events(lc, codecs);
if (linphone_core_generic_confort_noise_enabled(lc)){
PayloadType *cn=payload_type_clone(&payload_type_cn);
payload_type_set_number(cn, 13);
ret=ms_list_append(ret, cn);
}
return ret;
}
typedef struct _CodecConstraints{
int bandwidth_limit;
int max_codecs;
@ -342,7 +358,7 @@ typedef struct _CodecConstraints{
static MSList *make_codec_list(LinphoneCore *lc, CodecConstraints * hints, const MSList *codecs){
MSList *l=NULL;
MSList *tevs=NULL;
MSList *specials=NULL;
const MSList *it;
int nb = 0;
@ -373,8 +389,8 @@ static MSList *make_codec_list(LinphoneCore *lc, CodecConstraints * hints, const
nb++;
if ((hints->max_codecs > 0) && (nb >= hints->max_codecs)) break;
}
tevs=create_telephone_events(lc,l);
l=ms_list_concat(l,tevs);
specials=create_special_payload_types(lc,l);
l=ms_list_concat(l,specials);
linphone_core_assign_payload_type_numbers(lc, l);
return l;
}
@ -522,6 +538,29 @@ static void transfer_already_assigned_payload_types(SalMediaDescription *old, Sa
}
}
static const char *linphone_call_get_bind_ip_for_stream(LinphoneCall *call, int stream_index){
const char *bind_ip=call->af==AF_INET6 ? "::0" : "0.0.0.0";
if (stream_index<2 && call->media_ports[stream_index].multicast_ip[0]!='\0'){
if (call->dir==LinphoneCallOutgoing){
/*as multicast sender, we must decide a local interface to use to send multicast, and bind to it*/
bind_ip=call->localip;
}else{
/*as receiver, just bind to the multicast address*/
bind_ip=call->media_ports[stream_index].multicast_ip;
}
}
return bind_ip;
}
static const char *linphone_call_get_public_ip_for_stream(LinphoneCall *call, int stream_index){
const char *public_ip=call->localip;
if (stream_index<2 && call->media_ports[stream_index].multicast_ip[0]!='\0')
public_ip=call->media_ports[stream_index].multicast_ip;
return public_ip;
}
void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *call){
MSList *l;
SalMediaDescription *old_md=call->localdesc;
@ -530,9 +569,21 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *
const char *me;
SalMediaDescription *md=sal_media_description_new();
LinphoneAddress *addr;
char* local_ip=call->localip;
const char *subject=linphone_call_params_get_session_name(call->params);
const char *subject;
CodecConstraints codec_hints={0};
/*multicast is only set in case of outgoing call*/
if (call->dir == LinphoneCallOutgoing && linphone_core_audio_multicast_enabled(lc)) {
md->streams[0].ttl=linphone_core_get_audio_multicast_ttl(lc);
md->streams[0].multicast_role = SalMulticastSender;
}
if (call->dir == LinphoneCallOutgoing && linphone_core_video_multicast_enabled(lc)) {
md->streams[1].ttl=linphone_core_get_video_multicast_ttl(lc);
md->streams[1].multicast_role = SalMulticastSender;
}
subject=linphone_call_params_get_session_name(call->params);
linphone_core_adapt_to_network(lc,call->ping_time,call->params);
@ -546,7 +597,7 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *
md->session_ver=(old_md ? (old_md->session_ver+1) : (rand() & 0xfff));
md->nb_streams=(call->biggestdesc ? call->biggestdesc->nb_streams : 1);
strncpy(md->addr,local_ip,sizeof(md->addr));
strncpy(md->addr,call->localip,sizeof(md->addr));
strncpy(md->username,linphone_address_get_username(addr),sizeof(md->username));
if (subject) strncpy(md->name,subject,sizeof(md->name));
@ -555,8 +606,8 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *
else md->bandwidth=linphone_core_get_download_bandwidth(lc);
/*set audio capabilities */
strncpy(md->streams[0].rtp_addr,local_ip,sizeof(md->streams[0].rtp_addr));
strncpy(md->streams[0].rtcp_addr,local_ip,sizeof(md->streams[0].rtcp_addr));
strncpy(md->streams[0].rtp_addr,linphone_call_get_public_ip_for_stream(call,0),sizeof(md->streams[0].rtp_addr));
strncpy(md->streams[0].rtcp_addr,linphone_call_get_public_ip_for_stream(call,0),sizeof(md->streams[0].rtcp_addr));
strncpy(md->streams[0].name,"Audio",sizeof(md->streams[0].name)-1);
md->streams[0].rtp_port=call->media_ports[0].rtp_port;
md->streams[0].rtcp_port=call->media_ports[0].rtcp_port;
@ -572,11 +623,19 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *
l=make_codec_list(lc, &codec_hints, lc->codecs_conf.audio_codecs);
md->streams[0].max_rate=get_max_codec_sample_rate(l);
md->streams[0].payloads=l;
if (call->audiostream && call->audiostream->ms.sessions.rtp_session) {
char* me = linphone_address_as_string_uri_only(call->me);
md->streams[0].rtp_ssrc=rtp_session_get_send_ssrc(call->audiostream->ms.sessions.rtp_session);
strncpy(md->streams[0].rtcp_cname,me,sizeof(md->streams[0].rtcp_cname));
ms_free(me);
}
else
ms_warning("Cannot get audio local ssrc for call [%p]",call);
nb_active_streams++;
if (call->params->has_video){
strncpy(md->streams[1].rtp_addr,local_ip,sizeof(md->streams[1].rtp_addr));
strncpy(md->streams[1].rtcp_addr,local_ip,sizeof(md->streams[1].rtcp_addr));
strncpy(md->streams[1].rtp_addr,linphone_call_get_public_ip_for_stream(call,1),sizeof(md->streams[1].rtp_addr));
strncpy(md->streams[1].rtcp_addr,linphone_call_get_public_ip_for_stream(call,1),sizeof(md->streams[1].rtcp_addr));
strncpy(md->streams[1].name,"Video",sizeof(md->streams[1].name)-1);
md->streams[1].rtp_port=call->media_ports[1].rtp_port;
md->streams[1].rtcp_port=call->media_ports[1].rtcp_port;
@ -587,6 +646,14 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *
codec_hints.previously_used=old_md ? old_md->streams[1].already_assigned_payloads : NULL;
l=make_codec_list(lc, &codec_hints, lc->codecs_conf.video_codecs);
md->streams[1].payloads=l;
if (call->videostream && call->videostream->ms.sessions.rtp_session) {
char* me = linphone_address_as_string_uri_only(call->me);
md->streams[0].rtp_ssrc=rtp_session_get_send_ssrc(call->videostream->ms.sessions.rtp_session);
strncpy(md->streams[0].rtcp_cname,me,sizeof(md->streams[0].rtcp_cname));
ms_free(me);
}
else
ms_warning("Cannot get video local ssrc for call [%p]",call);
nb_active_streams++;
}
@ -608,6 +675,14 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *
}
setup_encryption_keys(call,md);
/* if media encryption is set to DTLS check presence of fingerprint in the call which shall have been set at stream init but it may have failed when retrieving certificate resulting in no fingerprint present and then DTLS not usable */
if ((call->params->media_encryption==LinphoneMediaEncryptionDTLS) && (call->dtls_certificate_fingerprint!= NULL)) {
memcpy(md->dtls_fingerprint, call->dtls_certificate_fingerprint, strlen((const char *)(call->dtls_certificate_fingerprint))); /* get the self fingerprint from call(it's computed at stream init) */
md->dtls_role = SalDtlsRoleUnset; /* if we are offering, SDP will have actpass setup attribute when role is unset, if we are responding the result mediadescription will be set to SalDtlsRoleIsClient */
} else {
md->dtls_fingerprint[0] = '\0';
md->dtls_role = SalDtlsRoleInvalid;
}
setup_rtcp_fb(call, md);
setup_rtcp_xr(call, md);
@ -709,15 +784,38 @@ static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from,
call->camera_enabled=TRUE;
call->current_params = linphone_call_params_new();
call->current_params->media_encryption=LinphoneMediaEncryptionNone;
call->dtls_certificate_fingerprint = NULL;
if (call->dir == LinphoneCallIncoming)
call->me=to;
else
call->me=from;
linphone_address_ref(call->me);
linphone_core_get_audio_port_range(call->core, &min_port, &max_port);
port_config_set(call,0,min_port,max_port);
linphone_core_get_video_port_range(call->core, &min_port, &max_port);
port_config_set(call,1,min_port,max_port);
if (call->dir==LinphoneCallOutgoing){
if ( linphone_core_audio_multicast_enabled(call->core)){
strncpy(call->media_ports[0].multicast_ip,
linphone_core_get_audio_multicast_addr(call->core), sizeof(call->media_ports[0].multicast_ip));
}
if ( linphone_core_video_multicast_enabled(call->core)){
strncpy(call->media_ports[1].multicast_ip,
linphone_core_get_video_multicast_addr(call->core), sizeof(call->media_ports[1].multicast_ip));
}
}
linphone_call_init_stats(&call->stats[LINPHONE_CALL_STATS_AUDIO], LINPHONE_CALL_STATS_AUDIO);
linphone_call_init_stats(&call->stats[LINPHONE_CALL_STATS_VIDEO], LINPHONE_CALL_STATS_VIDEO);
#ifdef ANDROID
ms_message("Call [%p] acquires both wifi and multicast lock",call);
linphone_core_wifi_lock_acquire(call->core);
linphone_core_multicast_lock_acquire(call->core); /*does no affect battery more than regular rtp traffic*/
#endif
}
void linphone_call_init_stats(LinphoneCallStats *stats, int type) {
@ -799,7 +897,7 @@ static void linphone_call_get_local_ip(LinphoneCall *call, const LinphoneAddress
}
if (res != NULL) freeaddrinfo(res);
}
if (_linphone_core_get_firewall_policy(call->core)==LinphonePolicyUseNatAddress
if (linphone_core_get_firewall_policy(call->core)==LinphonePolicyUseNatAddress
&& (ip=linphone_core_get_nat_address_resolved(call->core))!=NULL){
strncpy(call->localip,ip,LINPHONE_IPADDR_SIZE);
return;
@ -836,11 +934,13 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr
linphone_call_init_common(call,from,to);
call->params = linphone_call_params_copy(params);
if (_linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) {
if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) {
call->ice_session = ice_session_new();
/*for backward compatibility purposes, shall be enabled by default in futur*/
ice_session_enable_message_integrity_check(call->ice_session,lp_config_get_int(lc->config,"net","ice_session_enable_message_integrity_check",0));
ice_session_set_role(call->ice_session, IR_Controlling);
}
if (_linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseStun) {
if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseStun) {
call->ping_time=linphone_core_run_stun_tests(call->core,call);
}
#ifdef BUILD_UPNP
@ -870,9 +970,10 @@ static void linphone_call_incoming_select_ip_version(LinphoneCall *call){
* Fix call parameters on incoming call to eg. enable AVPF if the incoming call propose it and it is not enabled locally.
*/
void linphone_call_set_compatible_incoming_call_parameters(LinphoneCall *call, const SalMediaDescription *md) {
int i;
call->params->has_video &= linphone_core_media_description_contains_video_stream(md);
/* Handle AVPF and SRTP. */
/* Handle AVPF, SRTP and DTLS. */
call->params->avpf_enabled = sal_media_description_has_avpf(md);
if (call->params->avpf_enabled == TRUE) {
if (call->dest_proxy != NULL) {
@ -881,9 +982,22 @@ void linphone_call_set_compatible_incoming_call_parameters(LinphoneCall *call, c
call->params->avpf_rr_interval = linphone_core_get_avpf_rr_interval(call->core)*1000;
}
}
if ((sal_media_description_has_dtls(md) == TRUE) && (media_stream_dtls_supported() == TRUE)) {
call->params->media_encryption = LinphoneMediaEncryptionDTLS;
}
if ((sal_media_description_has_srtp(md) == TRUE) && (ms_srtp_supported() == TRUE)) {
call->params->media_encryption = LinphoneMediaEncryptionSRTP;
}
/* set both local audio & video multicast ip address if any*/
for (i=0;i<2;++i){
if (md->streams[i].rtp_addr[i]!='\0' && ms_is_multicast(md->streams[i].rtp_addr)) {
strncpy(call->media_ports[i].multicast_ip,md->streams[i].rtp_addr,sizeof(call->media_ports[i].multicast_ip));
ms_message("Disabling rtcp on call [%p], stream [%i] because of multicast",call,i);
call->media_ports[i].rtp_port=md->streams[i].rtp_port;
call->media_ports[i].rtcp_port=0;
}
}
}
LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, SalOp *op){
@ -939,17 +1053,20 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro
// In this case WE chose the media parameters according to policy.
linphone_call_set_compatible_incoming_call_parameters(call, md);
}
fpol=_linphone_core_get_firewall_policy(call->core);
fpol=linphone_core_get_firewall_policy(call->core);
/*create the ice session now if ICE is required*/
if (fpol==LinphonePolicyUseIce){
if (md){
call->ice_session = ice_session_new();
/*for backward compatibility purposes, shall be enabled by default in futur*/
ice_session_enable_message_integrity_check(call->ice_session,lp_config_get_int(lc->config,"net","ice_session_enable_message_integrity_check",0));
ice_session_set_role(call->ice_session, IR_Controlled);
}else{
fpol=LinphonePolicyNoFirewall;
ms_warning("ICE not supported for incoming INVITE without SDP.");
}
}
/*reserve the sockets immediately*/
linphone_call_init_media_streams(call);
switch (fpol) {
@ -1054,8 +1171,19 @@ static void linphone_call_set_terminated(LinphoneCall *call){
void linphone_call_fix_call_parameters(LinphoneCall *call){
call->params->has_video=call->current_params->has_video;
if (call->params->media_encryption != LinphoneMediaEncryptionZRTP) /*in case of ZRTP call parameter are handle after zrtp negociation*/
call->params->media_encryption=call->current_params->media_encryption;
switch(call->params->media_encryption) {
case LinphoneMediaEncryptionZRTP:
case LinphoneMediaEncryptionDTLS:
case LinphoneMediaEncryptionNone:
/* do nothing */
break;
case LinphoneMediaEncryptionSRTP:
call->params->media_encryption=call->current_params->media_encryption;
break;
default:
ms_fatal("Unknown media encryption type on call [%p]", call);
break;
}
}
const char *linphone_call_state_to_string(LinphoneCallState cs){
@ -1204,6 +1332,10 @@ static void linphone_call_destroy(LinphoneCall *obj){
ms_free(obj->auth_token);
obj->auth_token=NULL;
}
if (obj->dtls_certificate_fingerprint) {
ms_free(obj->dtls_certificate_fingerprint);
obj->dtls_certificate_fingerprint=NULL;
}
if (obj->dtmfs_timer) {
linphone_call_cancel_dtmfs(obj);
}
@ -1219,7 +1351,17 @@ static void linphone_call_destroy(LinphoneCall *obj){
linphone_call_params_unref(obj->remote_params);
obj->remote_params=NULL;
}
if (obj->me) {
linphone_address_unref(obj->me);
obj->me = NULL;
}
sal_error_info_reset(&obj->non_op_error);
#ifdef ANDROID
ms_message("Call [%p] releases wifi/multicast lock",obj);
linphone_core_wifi_lock_release(obj->core);
linphone_core_multicast_lock_release(obj->core);
#endif
}
/**
@ -1256,11 +1398,16 @@ const LinphoneCallParams * linphone_call_get_current_params(LinphoneCall *call){
#endif
if (linphone_call_all_streams_encrypted(call)) {
if (linphone_call_get_authentication_token(call)) {
call->current_params->media_encryption=LinphoneMediaEncryptionZRTP;
} else {
call->current_params->media_encryption=LinphoneMediaEncryptionSRTP;
}
if (linphone_call_get_authentication_token(call)) {
call->current_params->media_encryption=LinphoneMediaEncryptionZRTP;
} else {
/* TODO : check this or presence of dtls_fingerprint in the call? */
if (call->params->media_encryption == LinphoneMediaEncryptionDTLS) {
call->current_params->media_encryption=LinphoneMediaEncryptionDTLS;
} else {
call->current_params->media_encryption=LinphoneMediaEncryptionSRTP;
}
}
} else {
call->current_params->media_encryption=LinphoneMediaEncryptionNone;
}
@ -1629,7 +1776,7 @@ static void port_config_set_random_choosed(LinphoneCall *call, int stream_index,
static void _linphone_call_prepare_ice_for_stream(LinphoneCall *call, int stream_index, bool_t create_checklist){
MediaStream *ms=stream_index == 0 ? (MediaStream*)call->audiostream : (MediaStream*)call->videostream;
if ((_linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) && (call->ice_session != NULL)){
if ((linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) && (call->ice_session != NULL)){
IceCheckList *cl;
rtp_session_set_pktinfo(ms->sessions.rtp_session, TRUE);
rtp_session_set_symmetric_rtp(ms->sessions.rtp_session, FALSE);
@ -1650,7 +1797,7 @@ int linphone_call_prepare_ice(LinphoneCall *call, bool_t incoming_offer){
SalMediaDescription *remote = NULL;
bool_t has_video=FALSE;
if ((_linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) && (call->ice_session != NULL)){
if ((linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) && (call->ice_session != NULL)){
if (incoming_offer){
remote=sal_call_get_remote_media_description(call->op);
has_video=call->params->has_video && linphone_core_media_description_contains_video_stream(remote);
@ -1681,18 +1828,47 @@ int linphone_call_prepare_ice(LinphoneCall *call, bool_t incoming_offer){
return 0;
}
void linphone_call_init_audio_stream(LinphoneCall *call){
LinphoneCore *lc=call->core;
AudioStream *audiostream;
const char *location;
int dscp;
RtpTransport *meta_rtp=NULL;
RtpTransport *meta_rtcp=NULL;
char rtcp_tool[128]={0};
char* cname;
snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version());
if (call->audiostream != NULL) return;
if (call->sessions[0].rtp_session==NULL){
call->audiostream=audiostream=audio_stream_new(call->media_ports[0].rtp_port,call->media_ports[0].rtcp_port,call->af==AF_INET6);
call->audiostream=audiostream=audio_stream_new2(linphone_call_get_bind_ip_for_stream(call,0),
call->media_ports[0].rtp_port, call->media_ports[0].rtcp_port);
cname = linphone_address_as_string_uri_only(call->me);
audio_stream_set_rtcp_information(call->audiostream, cname, rtcp_tool);
ms_free(cname);
rtp_session_set_symmetric_rtp(audiostream->ms.sessions.rtp_session,linphone_core_symmetric_rtp_enabled(lc));
if (call->params->media_encryption==LinphoneMediaEncryptionDTLS) {
MSDtlsSrtpParams params;
char *certificate, *key;
memset(&params,0,sizeof(MSDtlsSrtpParams));
/* TODO : search for a certificate with CNAME=sip uri(retrieved from variable me) or default : linphone-dtls-default-identity */
/* This will parse the directory to find a matching fingerprint or generate it if not found */
/* returned string must be freed */
sal_certificates_chain_parse_directory(&certificate, &key, &call->dtls_certificate_fingerprint, lc->user_certificates_path, "linphone-dtls-default-identity", SAL_CERTIFICATE_RAW_FORMAT_PEM, TRUE, TRUE);
if (key!= NULL && certificate!=NULL) {
params.pem_certificate = (char *)certificate;
params.pem_pkey = (char *)key;
params.role = MSDtlsSrtpRoleUnset; /* default is unset, then check if we have a result SalMediaDescription */
audio_stream_enable_dtls(call->audiostream,&params);
ms_free(certificate);
ms_free(key);
} else {
ms_error("Unable to retrieve or generate DTLS certificate and key - DTLS disabled");
/* TODO : check if encryption forced, if yes, stop call */
}
}
}else{
call->audiostream=audio_stream_new_with_sessions(&call->sessions[0]);
}
@ -1739,14 +1915,18 @@ void linphone_call_init_audio_stream(LinphoneCall *call){
}
audio_stream_set_features(audiostream,linphone_core_get_audio_features(lc));
rtp_session_get_transports(audiostream->ms.sessions.rtp_session,&meta_rtp,&meta_rtcp);
if (lc->rtptf && (meta_rtp==NULL && meta_rtcp==NULL)){
/*the transport just need to be created once, then they are kept into the RtpSession, which is the same for the entire call duration.*/
RtpTransport *artp=lc->rtptf->audio_rtp_func(lc->rtptf->audio_rtp_func_data, call->media_ports[0].rtp_port);
RtpTransport *artcp=lc->rtptf->audio_rtcp_func(lc->rtptf->audio_rtcp_func_data, call->media_ports[0].rtcp_port);
meta_rtp_transport_new(&meta_rtp,TRUE,artp, 0);
meta_rtp_transport_new(&meta_rtcp,FALSE,artcp, 0);
rtp_session_set_transports(audiostream->ms.sessions.rtp_session,meta_rtp,meta_rtcp);
if (lc->rtptf){
RtpTransport *meta_rtp;
RtpTransport *meta_rtcp;
rtp_session_get_transports(audiostream->ms.sessions.rtp_session,&meta_rtp,&meta_rtcp);
if (meta_rtp_transport_get_endpoint(meta_rtp) == NULL) {
meta_rtp_transport_set_endpoint(meta_rtp,lc->rtptf->audio_rtp_func(lc->rtptf->audio_rtp_func_data, call->media_ports[0].rtp_port));
}
if (meta_rtp_transport_get_endpoint(meta_rtcp) == NULL) {
meta_rtp_transport_set_endpoint(meta_rtcp,lc->rtptf->audio_rtcp_func(lc->rtptf->audio_rtcp_func_data, call->media_ports[0].rtcp_port));
}
}
call->audiostream_app_evq = ortp_ev_queue_new();
@ -1758,8 +1938,9 @@ void linphone_call_init_audio_stream(LinphoneCall *call){
void linphone_call_init_video_stream(LinphoneCall *call){
#ifdef VIDEO_ENABLED
LinphoneCore *lc=call->core;
RtpTransport *meta_rtp=NULL;
RtpTransport *meta_rtcp=NULL;
char* cname;
char rtcp_tool[128];
snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version());
if (call->videostream == NULL){
int video_recv_buf_size=lp_config_get_int(lc->config,"video","recv_buf_size",0);
@ -1767,11 +1948,38 @@ void linphone_call_init_video_stream(LinphoneCall *call){
const char *display_filter=linphone_core_get_video_display_filter(lc);
if (call->sessions[1].rtp_session==NULL){
call->videostream=video_stream_new(call->media_ports[1].rtp_port,call->media_ports[1].rtcp_port, call->af==AF_INET6);
call->videostream=video_stream_new2(linphone_call_get_bind_ip_for_stream(call,1),
call->media_ports[1].rtp_port,call->media_ports[1].rtcp_port);
cname = linphone_address_as_string_uri_only(call->me);
video_stream_set_rtcp_information(call->videostream, cname, rtcp_tool);
ms_free(cname);
rtp_session_set_symmetric_rtp(call->videostream->ms.sessions.rtp_session,linphone_core_symmetric_rtp_enabled(lc));
if (call->params->media_encryption==LinphoneMediaEncryptionDTLS) {
MSDtlsSrtpParams params;
char *certificate, *key;
memset(&params,0,sizeof(MSDtlsSrtpParams));
/* TODO : search for a certificate with CNAME=sip uri(retrieved from variable me) or default : linphone-dtls-default-identity */
/* This will parse the directory to find a matching fingerprint or generate it if not found */
/* returned string must be freed */
sal_certificates_chain_parse_directory(&certificate, &key, &call->dtls_certificate_fingerprint, lc->user_certificates_path, "linphone-dtls-default-identity", SAL_CERTIFICATE_RAW_FORMAT_PEM, TRUE, TRUE);
if (key!= NULL && certificate!=NULL) {
params.pem_certificate = (char *)certificate;
params.pem_pkey = (char *)key;
params.role = MSDtlsSrtpRoleUnset; /* default is unset, then check if we have a result SalMediaDescription */
video_stream_enable_dtls(call->videostream,&params);
ms_free(certificate);
ms_free(key);
} else {
ms_error("Unable to retrieve or generate DTLS certificate and key - DTLS disabled");
/* TODO : check if encryption forced, if yes, stop call */
}
}
}else{
call->videostream=video_stream_new_with_sessions(&call->sessions[1]);
}
if (call->media_ports[1].rtp_port==-1){
port_config_set_random_choosed(call,1,call->videostream->ms.sessions.rtp_session);
}
@ -1783,14 +1991,18 @@ void linphone_call_init_video_stream(LinphoneCall *call){
if (display_filter != NULL)
video_stream_set_display_filter_name(call->videostream,display_filter);
video_stream_set_event_callback(call->videostream,video_stream_event_cb, call);
rtp_session_get_transports(call->videostream->ms.sessions.rtp_session,&meta_rtp,&meta_rtcp);
if (lc->rtptf && (meta_rtp==NULL && meta_rtcp==NULL)){
RtpTransport *vrtp=lc->rtptf->video_rtp_func(lc->rtptf->video_rtp_func_data, call->media_ports[1].rtp_port);
RtpTransport *vrtcp=lc->rtptf->video_rtcp_func(lc->rtptf->video_rtcp_func_data, call->media_ports[1].rtcp_port);
meta_rtp_transport_new(&meta_rtp,TRUE,vrtp, 0);
meta_rtp_transport_new(&meta_rtcp,FALSE,vrtcp, 0);
rtp_session_set_transports(call->videostream->ms.sessions.rtp_session,meta_rtp,meta_rtcp);
if (lc->rtptf){
RtpTransport *meta_rtp;
RtpTransport *meta_rtcp;
rtp_session_get_transports(call->videostream->ms.sessions.rtp_session,&meta_rtp,&meta_rtcp);
if (meta_rtp_transport_get_endpoint(meta_rtp) == NULL) {
meta_rtp_transport_set_endpoint(meta_rtp,lc->rtptf->video_rtp_func(lc->rtptf->video_rtp_func_data, call->media_ports[1].rtp_port));
}
if (meta_rtp_transport_get_endpoint(meta_rtcp) == NULL) {
meta_rtp_transport_set_endpoint(meta_rtcp,lc->rtptf->video_rtcp_func(lc->rtptf->video_rtcp_func_data, call->media_ports[1].rtcp_port));
}
}
call->videostream_app_evq = ortp_ev_queue_new();
rtp_session_register_event_queue(call->videostream->ms.sessions.rtp_session,call->videostream_app_evq);
@ -2084,7 +2296,7 @@ static void configure_rtp_session_for_rtcp_xr(LinphoneCore *lc, LinphoneCall *ca
rtp_session_configure_rtcp_xr(session, &currentconfig);
}
static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cname, bool_t muted, bool_t send_ringbacktone, bool_t use_arc){
static void linphone_call_start_audio_stream(LinphoneCall *call, bool_t muted, bool_t send_ringbacktone, bool_t use_arc){
LinphoneCore *lc=call->core;
LpConfig* conf;
int used_pt=-1;
@ -2103,13 +2315,15 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cna
stream = sal_media_description_find_best_stream(call->resultdesc, SalAudio);
if (stream && stream->dir!=SalStreamInactive && stream->rtp_port!=0){
const char *rtp_addr=stream->rtp_addr[0]!='\0' ? stream->rtp_addr : call->resultdesc->addr;
bool_t is_multicast=ms_is_multicast(rtp_addr);
playcard=lc->sound_conf.lsd_card ?
lc->sound_conf.lsd_card : lc->sound_conf.play_sndcard;
captcard=lc->sound_conf.capt_sndcard;
playfile=lc->play_file;
recfile=lc->rec_file;
call->audio_profile=make_profile(call,call->resultdesc,stream,&used_pt);
if (used_pt!=-1){
call->current_params->audio_codec = rtp_profile_get_payload(call->audio_profile, used_pt);
if (playcard==NULL) {
@ -2120,7 +2334,9 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cna
}
/*Replace soundcard filters by inactive file players or recorders
when placed in recvonly or sendonly mode*/
if (stream->rtp_port==0 || stream->dir==SalStreamRecvOnly){
if (stream->rtp_port==0
|| stream->dir==SalStreamRecvOnly
|| (stream->multicast_role == SalMulticastReceiver && is_multicast)){
captcard=NULL;
playfile=NULL;
}else if (stream->dir==SalStreamSendOnly){
@ -2169,21 +2385,23 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cna
crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, stream->crypto_local_tag);
if (crypto_idx >= 0) {
media_stream_set_srtp_recv_key_b64(&call->audiostream->ms,stream->crypto[0].algo,stream->crypto[0].master_key);
media_stream_set_srtp_send_key_b64(&call->audiostream->ms,stream->crypto[0].algo,local_st_desc->crypto[crypto_idx].master_key);
media_stream_set_srtp_recv_key_b64(&(call->audiostream->ms.sessions),stream->crypto[0].algo,stream->crypto[0].master_key);
media_stream_set_srtp_send_key_b64(&(call->audiostream->ms.sessions),stream->crypto[0].algo,local_st_desc->crypto[crypto_idx].master_key);
} else {
ms_warning("Failed to find local crypto algo with tag: %d", stream->crypto_local_tag);
}
}
configure_rtp_session_for_rtcp_xr(lc, call, SalAudio);
audio_stream_set_rtcp_information(call->audiostream, cname, rtcp_tool);
if (is_multicast)
rtp_session_set_multicast_ttl(call->audiostream->ms.sessions.rtp_session,stream->ttl);
audio_stream_start_full(
call->audiostream,
call->audio_profile,
stream->rtp_addr[0]!='\0' ? stream->rtp_addr : call->resultdesc->addr,
rtp_addr,
stream->rtp_port,
stream->rtcp_addr[0]!='\0' ? stream->rtcp_addr : call->resultdesc->addr,
linphone_core_rtcp_enabled(lc) ? (stream->rtcp_port ? stream->rtcp_port : stream->rtp_port+1) : 0,
(linphone_core_rtcp_enabled(lc) && !is_multicast) ? (stream->rtcp_port ? stream->rtcp_port : stream->rtp_port+1) : 0,
used_pt,
linphone_core_get_audio_jittcomp(lc),
playfile,
@ -2212,16 +2430,14 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cna
}
}
static void linphone_call_start_video_stream(LinphoneCall *call, const char *cname,bool_t all_inputs_muted){
static void linphone_call_start_video_stream(LinphoneCall *call, bool_t all_inputs_muted){
#ifdef VIDEO_ENABLED
LinphoneCore *lc=call->core;
int used_pt=-1;
char rtcp_tool[128]={0};
const SalStreamDescription *vstream;
MSFilter* source = NULL;
bool_t reused_preview = FALSE;
snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version());
/* shutdown preview */
if (lc->previewstream!=NULL) {
@ -2237,7 +2453,7 @@ static void linphone_call_start_video_stream(LinphoneCall *call, const char *cna
const char *rtp_addr=vstream->rtp_addr[0]!='\0' ? vstream->rtp_addr : call->resultdesc->addr;
const char *rtcp_addr=vstream->rtcp_addr[0]!='\0' ? vstream->rtcp_addr : call->resultdesc->addr;
const SalStreamDescription *local_st_desc=sal_media_description_find_stream(call->localdesc,vstream->proto,SalVideo);
bool_t is_multicast=ms_is_multicast(rtp_addr);
call->video_profile=make_profile(call,call->resultdesc,vstream,&used_pt);
if (used_pt!=-1){
@ -2258,13 +2474,20 @@ static void linphone_call_start_video_stream(LinphoneCall *call, const char *cna
video_stream_set_fps(call->videostream,linphone_core_get_preferred_framerate(lc));
video_stream_set_sent_video_size(call->videostream,linphone_core_get_preferred_video_size(lc));
video_stream_enable_self_view(call->videostream,lc->video_conf.selfview);
if (lc->video_window_id!=0)
if (call->video_window_id != 0)
video_stream_set_native_window_id(call->videostream,call->video_window_id);
else if (lc->video_window_id!=0)
video_stream_set_native_window_id(call->videostream,lc->video_window_id);
if (lc->preview_window_id!=0)
video_stream_set_native_preview_window_id (call->videostream,lc->preview_window_id);
video_stream_use_preview_video_window (call->videostream,lc->use_preview_window);
if (vstream->dir==SalStreamSendOnly && lc->video_conf.capture ){
if (is_multicast){
if (vstream->multicast_role == SalMulticastReceiver)
dir=VideoStreamRecvOnly;
else
dir=VideoStreamSendOnly;
} else if (vstream->dir==SalStreamSendOnly && lc->video_conf.capture ){
if (local_st_desc->dir==SalStreamSendOnly){
/* localdesc stream dir to SendOnly is when we want to put on hold, so use nowebcam in this case*/
cam=get_nowebcam_device();
@ -2291,8 +2514,8 @@ static void linphone_call_start_video_stream(LinphoneCall *call, const char *cna
if (sal_stream_description_has_srtp(vstream) == TRUE) {
int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, vstream->crypto_local_tag);
if (crypto_idx >= 0) {
media_stream_set_srtp_recv_key_b64(&call->videostream->ms,vstream->crypto[0].algo,vstream->crypto[0].master_key);
media_stream_set_srtp_send_key_b64(&call->videostream->ms,vstream->crypto[0].algo,local_st_desc->crypto[crypto_idx].master_key);
media_stream_set_srtp_recv_key_b64(&(call->videostream->ms.sessions),vstream->crypto[0].algo,vstream->crypto[0].master_key);
media_stream_set_srtp_send_key_b64(&(call->videostream->ms.sessions),vstream->crypto[0].algo,local_st_desc->crypto[crypto_idx].master_key);
}
}
configure_rtp_session_for_rtcp_xr(lc, call, SalVideo);
@ -2301,8 +2524,10 @@ static void linphone_call_start_video_stream(LinphoneCall *call, const char *cna
video_stream_set_direction (call->videostream, dir);
ms_message("%s lc rotation:%d\n", __FUNCTION__, lc->device_rotation);
video_stream_set_device_rotation(call->videostream, lc->device_rotation);
video_stream_set_rtcp_information(call->videostream, cname, rtcp_tool);
video_stream_set_freeze_on_error(call->videostream, lp_config_get_int(lc->config, "video", "freeze_on_error", 0));
if (is_multicast)
rtp_session_set_multicast_ttl(call->videostream->ms.sessions.rtp_session,vstream->ttl);
if( lc->video_conf.reuse_preview_source && source ){
ms_message("video_stream_start_with_source kept: %p", source);
video_stream_start_with_source(call->videostream,
@ -2315,7 +2540,7 @@ static void linphone_call_start_video_stream(LinphoneCall *call, const char *cna
video_stream_start(call->videostream,
call->video_profile, rtp_addr, vstream->rtp_port,
rtcp_addr,
linphone_core_rtcp_enabled(lc) ? (vstream->rtcp_port ? vstream->rtcp_port : vstream->rtp_port+1) : 0,
(linphone_core_rtcp_enabled(lc) && !is_multicast) ? (vstream->rtcp_port ? vstream->rtcp_port : vstream->rtp_port+1) : 0,
used_pt, linphone_core_get_video_jittcomp(lc), cam);
}
}
@ -2333,8 +2558,6 @@ static void linphone_call_start_video_stream(LinphoneCall *call, const char *cna
void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_muted, bool_t send_ringbacktone){
LinphoneCore *lc=call->core;
LinphoneAddress *me=linphone_core_get_primary_contact_parsed(lc);
char *cname;
bool_t use_arc=linphone_core_adaptive_rate_control_enabled(lc);
#ifdef VIDEO_ENABLED
const SalStreamDescription *vstream=sal_media_description_find_best_stream(call->resultdesc,SalVideo);
@ -2347,8 +2570,6 @@ void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_mut
ms_fatal("start_media_stream() called without prior init !");
return;
}
cname=linphone_address_as_string_uri_only(me);
#if defined(VIDEO_ENABLED)
if (vstream!=NULL && vstream->dir!=SalStreamInactive && vstream->payloads!=NULL){
/*when video is used, do not make adaptive rate control on audio, it is stupid.*/
@ -2359,12 +2580,14 @@ void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_mut
call, linphone_core_get_upload_bandwidth(lc),linphone_core_get_download_bandwidth(lc));
if (call->audiostream!=NULL) {
linphone_call_start_audio_stream(call,cname,all_inputs_muted||call->audio_muted,send_ringbacktone,use_arc);
linphone_call_start_audio_stream(call,all_inputs_muted||call->audio_muted,send_ringbacktone,use_arc);
} else {
ms_warning("DTLS no audio stream!");
}
call->current_params->has_video=FALSE;
if (call->videostream!=NULL) {
if (call->audiostream) audio_stream_link_video(call->audiostream,call->videostream);
linphone_call_start_video_stream(call,cname,all_inputs_muted);
linphone_call_start_video_stream(call,all_inputs_muted);
}
call->all_muted=all_inputs_muted;
@ -2384,19 +2607,60 @@ void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_mut
video_stream_enable_zrtp(call->videostream,call->audiostream,&params);
}
#endif
}else{
} else if (call->params->media_encryption==LinphoneMediaEncryptionDTLS) {
/* DTLS engine was already initialised during stream init. Before starting it we must be sure that the role(client or server) is set.
* Role may have already been set to server if we initiate the call and already received a packet from peer, in that case do nothing */
SalDtlsRole salRole = call->resultdesc->streams[0].dtls_role; /* TODO: is streams[0] necessary the audiostream in the media description ? */
if (salRole==SalDtlsRoleInvalid) { /* it's invalid in streams[0] but check also at session level */
salRole = call->resultdesc->dtls_role;
}
if (salRole!=SalDtlsRoleInvalid) { /* if DTLS is available at both end points */
/* give the peer certificate fingerprint to dtls context */
SalMediaDescription *remote_desc = sal_call_get_remote_media_description(call->op);
ms_dtls_srtp_set_peer_fingerprint(call->audiostream->ms.sessions.dtls_context, remote_desc->streams[0].dtls_fingerprint);
} else {
ms_warning("unable to start DTLS engine on audiostream, Dtls role in resulting media description is invalid\n");
}
if (salRole == SalDtlsRoleIsClient) { /* local endpoint is client */
ms_dtls_srtp_set_role(call->audiostream->ms.sessions.dtls_context, MSDtlsSrtpRoleIsClient); /* set the role to client */
ms_dtls_srtp_start(call->audiostream->ms.sessions.dtls_context); /* then start the engine, it will send the DTLS client Hello */
} else if (salRole == SalDtlsRoleIsServer) { /* local endpoint is server */
ms_dtls_srtp_set_role(call->audiostream->ms.sessions.dtls_context, MSDtlsSrtpRoleIsServer); /* this may complete the server setup */
/* no need to start engine, we are waiting for DTLS Client Hello */
}
#ifdef VIDEO_ENABLED
salRole = call->resultdesc->streams[1].dtls_role; /* TODO: is streams[1] necessary the videostream in the media description ? */
if (salRole==SalDtlsRoleInvalid) { /* it's invalid in streams[0] but check also at session level */
salRole = call->resultdesc->dtls_role;
}
if (salRole!=SalDtlsRoleInvalid) { /* if DTLS is available at both end points */
/* give the peer certificate fingerprint to dtls context */
SalMediaDescription *remote_desc = sal_call_get_remote_media_description(call->op);
ms_dtls_srtp_set_peer_fingerprint(call->videostream->ms.sessions.dtls_context, remote_desc->streams[1].dtls_fingerprint);
} else {
ms_warning("unable to start DTLS engine on videostream, Dtls role in resulting media description is invalid\n");
}
if (salRole == SalDtlsRoleIsClient) { /* local endpoint is client */
ms_dtls_srtp_set_role(call->videostream->ms.sessions.dtls_context, MSDtlsSrtpRoleIsClient); /* set the role to client */
ms_dtls_srtp_start(call->videostream->ms.sessions.dtls_context); /* then start the engine, it will send the DTLS client Hello */
} else if (salRole == SalDtlsRoleIsServer) { /* local endpoint is server */
ms_dtls_srtp_set_role(call->videostream->ms.sessions.dtls_context, MSDtlsSrtpRoleIsServer); /* this may complete the server setup */
/* no need to start engine, we are waiting for DTLS Client Hello */
}
#endif
} else {
call->current_params->media_encryption=linphone_call_all_streams_encrypted(call) ?
LinphoneMediaEncryptionSRTP : LinphoneMediaEncryptionNone;
LinphoneMediaEncryptionSRTP : LinphoneMediaEncryptionNone;
}
if ((call->ice_session != NULL) && (ice_session_state(call->ice_session) != IS_Completed)) {
ice_session_start_connectivity_checks(call->ice_session);
}
goto end;
end:
ms_free(cname);
linphone_address_destroy(me);
}
void linphone_call_stop_media_streams_for_ice_gathering(LinphoneCall *call){
@ -2412,9 +2676,9 @@ static bool_t update_stream_crypto_params(LinphoneCall *call, const SalStreamDes
int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, new_stream->crypto_local_tag);
if (crypto_idx >= 0) {
if (call->localdesc_changed & SAL_MEDIA_DESCRIPTION_CRYPTO_KEYS_CHANGED)
media_stream_set_srtp_send_key_b64(ms,new_stream->crypto[0].algo,local_st_desc->crypto[crypto_idx].master_key);
media_stream_set_srtp_send_key_b64(&(ms->sessions),new_stream->crypto[0].algo,local_st_desc->crypto[crypto_idx].master_key);
if (strcmp(old_stream->crypto[0].master_key,new_stream->crypto[0].master_key)!=0){
media_stream_set_srtp_recv_key_b64(ms,new_stream->crypto[0].algo,new_stream->crypto[0].master_key);
media_stream_set_srtp_recv_key_b64(&(ms->sessions),new_stream->crypto[0].algo,new_stream->crypto[0].master_key);
}
return TRUE;
} else {
@ -2962,6 +3226,31 @@ static void linphone_core_disconnected(LinphoneCore *lc, LinphoneCall *call){
linphone_core_play_named_tone(lc,LinphoneToneCallLost);
}
static void change_ice_media_destinations(LinphoneCall *call) {
const char *rtp_addr;
const char *rtcp_addr;
int rtp_port;
int rtcp_port;
bool_t result;
if (call->audiostream && ice_session_check_list(call->ice_session, 0)) {
result = ice_check_list_selected_valid_remote_candidate(ice_session_check_list(call->ice_session, 0), &rtp_addr, &rtp_port, &rtcp_addr, &rtcp_port);
if (result == TRUE) {
ms_message("Change audio stream destination: RTP=%s:%d RTCP=%s:%d", rtp_addr, rtp_port, rtcp_addr, rtcp_port);
rtp_session_set_remote_addr_full(call->audiostream->ms.sessions.rtp_session, rtp_addr, rtp_port, rtcp_addr, rtcp_port);
}
}
#ifdef VIDEO_ENABLED
if (call->videostream && ice_session_check_list(call->ice_session, 1)) {
result = ice_check_list_selected_valid_remote_candidate(ice_session_check_list(call->ice_session, 1), &rtp_addr, &rtp_port, &rtcp_addr, &rtcp_port);
if (result == TRUE) {
ms_message("Change video stream destination: RTP=%s:%d RTCP=%s:%d", rtp_addr, rtp_port, rtcp_addr, rtcp_port);
rtp_session_set_remote_addr_full(call->videostream->ms.sessions.rtp_session, rtp_addr, rtp_port, rtcp_addr, rtcp_port);
}
}
#endif
}
static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){
OrtpEventType evt=ortp_event_get_type(ev);
OrtpEventData *evd=ortp_event_get_data(ev);
@ -2979,6 +3268,7 @@ static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){
if (ice_session_role(call->ice_session) == IR_Controlling) {
linphone_core_update_call(call->core, call, params);
}
change_ice_media_destinations(call);
break;
case IS_Failed:
if (ice_session_has_completed_check_list(call->ice_session) == TRUE) {
@ -3125,7 +3415,12 @@ void linphone_call_handle_stream_events(LinphoneCall *call, int stream_index){
} else if (evt == ORTP_EVENT_ZRTP_SAS_READY) {
if (ms->type==AudioStreamType)
linphone_call_audiostream_auth_token_ready(call, evd->info.zrtp_sas.sas, evd->info.zrtp_sas.verified);
} else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED)
} else if (evt == ORTP_EVENT_DTLS_ENCRYPTION_CHANGED) {
if (ms->type==AudioStreamType)
linphone_call_audiostream_encryption_changed(call, evd->info.dtls_stream_encrypted);
else if (ms->type==VideoStreamType)
propagate_encryption_changed(call);
}else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED)
|| (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) || (evt == ORTP_EVENT_ICE_RESTART_NEEDED)) {
handle_ice_events(call, ev);
} else if (evt==ORTP_EVENT_TELEPHONE_EVENT){
@ -3259,7 +3554,7 @@ static LinphoneAddress *get_fixed_contact(LinphoneCore *lc, LinphoneCall *call ,
const char *localip=call->localip;
/* first use user's supplied ip address if asked*/
if (_linphone_core_get_firewall_policy(lc)==LinphonePolicyUseNatAddress){
if (linphone_core_get_firewall_policy(lc)==LinphonePolicyUseNatAddress){
ctt=linphone_core_get_primary_contact_parsed(lc);
linphone_address_set_domain(ctt,linphone_core_get_nat_address_resolved(lc));
ret=ctt;
@ -3391,3 +3686,26 @@ void linphone_call_cancel_dtmfs(LinphoneCall *call) {
call->dtmf_sequence = NULL;
}
}
unsigned long linphone_call_get_native_video_window_id(const LinphoneCall *call) {
if (call->video_window_id) {
/* The video id was previously set by the app. */
return call->video_window_id;
}
#ifdef VIDEO_ENABLED
else if (call->videostream) {
/* It was not set but we want to get the one automatically created by mediastreamer2 (desktop versions only). */
return video_stream_get_native_window_id(call->videostream);
}
#endif
return 0;
}
void linphone_call_set_native_video_window_id(LinphoneCall *call, unsigned long id) {
call->video_window_id = id;
#ifdef VIDEO_ENABLED
if (call->videostream) {
video_stream_set_native_window_id(call->videostream, id);
}
#endif
}

View file

@ -28,6 +28,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include <sys/stat.h>
#include <ortp/telephonyevents.h>
#include <mediastreamer2/zrtp.h>
#include <mediastreamer2/dtls_srtp.h>
#include "mediastreamer2/mediastream.h"
#include "mediastreamer2/mseventqueue.h"
#include "mediastreamer2/msvolume.h"
@ -946,6 +947,8 @@ static void rtp_config_read(LinphoneCore *lc)
int nortp_timeout;
bool_t rtp_no_xmit_on_audio_mute;
bool_t adaptive_jitt_comp_enabled;
const char* tmp;
int tmp_int;
if (lp_config_get_range(lc->config, "rtp", "audio_rtp_port", &min_port, &max_port, 7078, 7078) == TRUE) {
if (min_port <= 0) min_port = 1;
@ -980,6 +983,26 @@ static void rtp_config_read(LinphoneCore *lc)
linphone_core_enable_video_adaptive_jittcomp(lc, adaptive_jitt_comp_enabled);
lc->rtp_conf.disable_upnp = lp_config_get_int(lc->config, "rtp", "disable_upnp", FALSE);
linphone_core_set_avpf_mode(lc,lp_config_get_int(lc->config,"rtp","avpf",0));
if ((tmp=lp_config_get_string(lc->config,"rtp","audio_multicast_addr",NULL)))
linphone_core_set_audio_multicast_addr(lc,tmp);
else
lc->rtp_conf.audio_multicast_addr=ms_strdup("224.1.2.3");
if ((tmp_int=lp_config_get_int(lc->config,"rtp","audio_multicast_enabled",-1)) >-1)
linphone_core_enable_audio_multicast(lc,tmp_int);
if ((tmp_int=lp_config_get_int(lc->config,"rtp","audio_multicast_ttl",-1))>0)
linphone_core_set_audio_multicast_ttl(lc,tmp_int);
else
lc->rtp_conf.audio_multicast_ttl=1;/*local network*/
if ((tmp=lp_config_get_string(lc->config,"rtp","video_multicast_addr",NULL)))
linphone_core_set_video_multicast_addr(lc,tmp);
else
lc->rtp_conf.video_multicast_addr=ms_strdup("224.1.2.3");
if ((tmp_int=lp_config_get_int(lc->config,"rtp","video_multicast_ttl",-1))>-1)
linphone_core_set_video_multicast_ttl(lc,tmp_int);
else
lc->rtp_conf.video_multicast_ttl=1;/*local network*/
if ((tmp_int=lp_config_get_int(lc->config,"rtp","video_multicast_enabled",-1)) >0)
linphone_core_enable_video_multicast(lc,tmp_int);
}
static PayloadType * find_payload(const MSList *default_list, const char *mime_type, int clock_rate, int channels, const char *recv_fmtp){
@ -1453,6 +1476,12 @@ static void misc_config_read(LinphoneCore *lc) {
lp_config_set_string(config,"misc","uuid",tmp);
}else if (strcmp(uuid,"0")!=0) /*to allow to disable sip.instance*/
sal_set_uuid(lc->sal, uuid);
/* DTLS: if media_encryption DTLS SRTP is available, get or create the certificate directory */
/*if (ms_dtls_srtp_available()){
*//*JOHAN: USELESS? REMOVE IT*/
//const char *user_certificate_config_path = lp_config_get_string(config,"misc","uuid",);
// }*/
}
static void linphone_core_start(LinphoneCore * lc) {
@ -1822,6 +1851,25 @@ int linphone_core_set_video_codecs(LinphoneCore *lc, MSList *codecs){
return 0;
}
/**
* Enable RFC3389 generic confort noise algorithm (CN payload type).
* It is disabled by default, because this algorithm is only relevant for legacy codecs (PCMU, PCMA, G722).
* @param lc the LinphoneCore
* @param enabled TRUE if enabled, FALSE otherwise.
**/
void linphone_core_enable_generic_confort_noise(LinphoneCore *lc, bool_t enabled){
lp_config_set_int(lc->config, "misc", "use_cn", enabled);
}
/**
* Returns enablement of RFC3389 generic confort noise algorithm.
* @param lc the LinphoneCore
* @return TRUE or FALSE.
**/
bool_t linphone_core_generic_confort_noise_enabled(const LinphoneCore *lc){
return lp_config_get_int(lc->config, "misc", "use_cn", FALSE);
}
const MSList * linphone_core_get_friend_list(const LinphoneCore *lc)
{
return lc->friends;
@ -3094,12 +3142,12 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const
call->log->start_date_time=ms_time(NULL);
linphone_call_init_media_streams(call);
if (_linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) {
if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) {
/* Defer the start of the call after the ICE gathering process. */
if (linphone_call_prepare_ice(call,FALSE)==1)
defer=TRUE;
}
else if (_linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseUpnp) {
else if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseUpnp) {
#ifdef BUILD_UPNP
if (linphone_core_update_upnp(lc,call)<0) {
/* uPnP port mappings failed, proceed with the call anyway. */
@ -3977,7 +4025,11 @@ int linphone_core_resume_call(LinphoneCore *lc, LinphoneCall *call){
linphone_core_update_local_media_description_from_upnp(call->localdesc, call->upnp_session);
}
#endif //BUILD_UPNP
sal_call_set_local_media_description(call->op,call->localdesc);
if (!lc->sip_conf.sdp_200_ack){
sal_call_set_local_media_description(call->op,call->localdesc);
} else {
sal_call_set_local_media_description(call->op,NULL);
}
sal_media_description_set_dir(call->localdesc,SalStreamSendRecv);
if (call->params->in_conference && !call->current_params->in_conference) subject="Conference";
if ( sal_call_update(call->op,subject,FALSE) != 0){
@ -3988,6 +4040,12 @@ int linphone_core_resume_call(LinphoneCore *lc, LinphoneCall *call){
lc->current_call=call;
snprintf(temp,sizeof(temp)-1,"Resuming the call with %s",linphone_call_get_remote_address_as_string(call));
linphone_core_notify_display_status(lc,temp);
if (lc->sip_conf.sdp_200_ack){
/*we are NOT offering, set local media description after sending the call so that we are ready to
process the remote offer when it will arrive*/
sal_call_set_local_media_description(call->op,call->localdesc);
}
return 0;
}
@ -4922,23 +4980,8 @@ void linphone_core_set_firewall_policy(LinphoneCore *lc, LinphoneFirewallPolicy
if (linphone_core_ready(lc))
lp_config_set_string(lc->config,"net","firewall_policy",policy);
}
LinphoneFirewallPolicy linphone_core_get_firewall_policy(const LinphoneCore *lc) {
return _linphone_core_get_firewall_policy_with_lie(lc, FALSE);
}
LinphoneFirewallPolicy _linphone_core_get_firewall_policy(const LinphoneCore *lc) {
return _linphone_core_get_firewall_policy_with_lie(lc, TRUE);
}
LinphoneFirewallPolicy _linphone_core_get_firewall_policy_with_lie(const LinphoneCore *lc, bool_t lie){
LinphoneFirewallPolicy linphone_core_get_firewall_policy(const LinphoneCore *lc){
const char *policy;
if(lie) {
LinphoneTunnel *tunnel = linphone_core_get_tunnel(lc);
if(tunnel != NULL && linphone_tunnel_get_mode(tunnel)) {
return LinphonePolicyNoFirewall;
}
}
policy = lp_config_get_string(lc->config, "net", "firewall_policy", NULL);
if ((policy == NULL) || (strcmp(policy, "0") == 0))
return LinphonePolicyNoFirewall;
@ -6102,6 +6145,8 @@ void rtp_config_uninit(LinphoneCore *lc)
lp_config_set_int(lc->config,"rtp","nortp_timeout",config->nortp_timeout);
lp_config_set_int(lc->config,"rtp","audio_adaptive_jitt_comp_enabled",config->audio_adaptive_jitt_comp_enabled);
lp_config_set_int(lc->config,"rtp","video_adaptive_jitt_comp_enabled",config->video_adaptive_jitt_comp_enabled);
ms_free(lc->rtp_conf.audio_multicast_addr);
ms_free(lc->rtp_conf.video_multicast_addr);
ms_free(config->srtp_suites);
}
@ -6261,6 +6306,9 @@ static void linphone_core_uninit(LinphoneCore *lc)
if(lc->zrtp_secrets_cache != NULL) {
ms_free(lc->zrtp_secrets_cache);
}
if(lc->user_certificates_path != NULL) {
ms_free(lc->user_certificates_path);
}
if(lc->play_file!=NULL){
ms_free(lc->play_file);
}
@ -6699,6 +6747,17 @@ const char *linphone_core_get_zrtp_secrets_file(LinphoneCore *lc){
return lc->zrtp_secrets_cache;
}
void linphone_core_set_user_certificates_path(LinphoneCore *lc, const char* path){
if (lc->user_certificates_path != NULL) {
ms_free(lc->user_certificates_path);
}
lc->user_certificates_path = path ? ms_strdup(path) : NULL;
}
const char *linphone_core_get_user_certificates_path(LinphoneCore *lc){
return lc->user_certificates_path;
}
LinphoneCall* linphone_core_find_call_from_uri(const LinphoneCore *lc, const char *uri) {
MSList *calls;
LinphoneCall *c;
@ -6759,6 +6818,8 @@ const char *linphone_media_encryption_to_string(LinphoneMediaEncryption menc){
switch(menc){
case LinphoneMediaEncryptionSRTP:
return "LinphoneMediaEncryptionSRTP";
case LinphoneMediaEncryptionDTLS:
return "LinphoneMediaEncryptionDTLS";
case LinphoneMediaEncryptionZRTP:
return "LinphoneMediaEncryptionZRTP";
case LinphoneMediaEncryptionNone:
@ -6775,6 +6836,8 @@ bool_t linphone_core_media_encryption_supported(const LinphoneCore *lc, Linphone
switch(menc){
case LinphoneMediaEncryptionSRTP:
return ms_srtp_supported();
case LinphoneMediaEncryptionDTLS:
return ms_dtls_srtp_available();
case LinphoneMediaEncryptionZRTP:
return ms_zrtp_available();
case LinphoneMediaEncryptionNone:
@ -6798,7 +6861,14 @@ int linphone_core_set_media_encryption(LinphoneCore *lc, LinphoneMediaEncryption
type="none";
ret=-1;
}else type="zrtp";
}else if (menc == LinphoneMediaEncryptionDTLS){
if (!ms_dtls_srtp_available()){
ms_warning("DTLS not supported by library.");
type="none";
ret=-1;
}else type="dtls";
}
lp_config_set_string(lc->config,"sip","media_encryption",type);
return ret;
}
@ -6810,6 +6880,8 @@ LinphoneMediaEncryption linphone_core_get_media_encryption(LinphoneCore *lc) {
return LinphoneMediaEncryptionNone;
else if (strcmp(menc, "srtp")==0)
return LinphoneMediaEncryptionSRTP;
else if (strcmp(menc, "dtls")==0)
return LinphoneMediaEncryptionDTLS;
else if (strcmp(menc, "zrtp")==0)
return LinphoneMediaEncryptionZRTP;
else
@ -6830,6 +6902,9 @@ void linphone_core_init_default_params(LinphoneCore*lc, LinphoneCallParams *para
params->in_conference=FALSE;
params->privacy=LinphonePrivacyDefault;
params->avpf_enabled=FALSE;
params->audio_dir=LinphoneCallParamsMediaDirectionSendRecv;
params->video_dir=LinphoneCallParamsMediaDirectionSendRecv;
params->real_early_media=lp_config_get_int(lc->config,"misc","real_early_media",FALSE);
}
void linphone_core_set_device_identifier(LinphoneCore *lc,const char* device_id) {
@ -7168,3 +7243,113 @@ void linphone_core_remove_listener(LinphoneCore *lc, const LinphoneCoreVTable *v
ms_message("Vtable [%p] unregistered on core [%p]",lc,vtable);
lc->vtables=ms_list_remove(lc->vtables,(void*)vtable);
}
int linphone_core_set_audio_multicast_addr(LinphoneCore *lc, const char* ip) {
char* new_value;
if (ip && !ms_is_multicast(ip)) {
ms_error("Cannot set multicast audio addr to core [%p] because [%s] is not multicast",lc,ip);
return -1;
}
new_value = ip?ms_strdup(ip):NULL;
if (lc->rtp_conf.audio_multicast_addr) ms_free(lc->rtp_conf.audio_multicast_addr);
lp_config_set_string(lc->config,"rtp","audio_multicast_addr",lc->rtp_conf.audio_multicast_addr=new_value);
return 0;
}
int linphone_core_set_video_multicast_addr(LinphoneCore *lc, const char* ip) {
char* new_value;
if (ip && !ms_is_multicast(ip)) {
ms_error("Cannot set multicast video addr to core [%p] because [%s] is not multicast",lc,ip);
return -1;
}
new_value = ip?ms_strdup(ip):NULL;
if (lc->rtp_conf.video_multicast_addr) ms_free(lc->rtp_conf.video_multicast_addr);
lp_config_set_string(lc->config,"rtp","video_multicast_addr",lc->rtp_conf.video_multicast_addr=new_value);
return 0;
}
const char* linphone_core_get_audio_multicast_addr(const LinphoneCore *lc) {
return lc->rtp_conf.audio_multicast_addr;
}
const char* linphone_core_get_video_multicast_addr(const LinphoneCore *lc){
return lc->rtp_conf.video_multicast_addr;
}
int linphone_core_set_audio_multicast_ttl(LinphoneCore *lc, int ttl) {
if (ttl>255) {
ms_error("Cannot set multicast audio ttl to core [%p] to [%i] value must be <256",lc,ttl);
return -1;
}
lp_config_set_int(lc->config,"rtp","audio_multicast_ttl",lc->rtp_conf.audio_multicast_ttl=ttl);
return 0;
}
int linphone_core_set_video_multicast_ttl(LinphoneCore *lc, int ttl) {
if (ttl>255) {
ms_error("Cannot set multicast video ttl to core [%p] to [%i] value must be <256",lc,ttl);
return -1;
}
lp_config_set_int(lc->config,"rtp","video_multicast_ttl",lc->rtp_conf.video_multicast_ttl=ttl);
return 0;
}
int linphone_core_get_audio_multicast_ttl(const LinphoneCore *lc) {
return lc->rtp_conf.audio_multicast_ttl;
}
int linphone_core_get_video_multicast_ttl(const LinphoneCore *lc){
return lc->rtp_conf.video_multicast_ttl;
}
void linphone_core_enable_audio_multicast(LinphoneCore *lc, bool_t yesno) {
lp_config_set_int(lc->config,"rtp","audio_multicast_enabled",lc->rtp_conf.audio_multicast_enabled=yesno);
}
bool_t linphone_core_audio_multicast_enabled(const LinphoneCore *lc) {
return lc->rtp_conf.audio_multicast_enabled;
}
void linphone_core_enable_video_multicast(LinphoneCore *lc, bool_t yesno) {
lp_config_set_int(lc->config,"rtp","video_multicast_enabled",lc->rtp_conf.video_multicast_enabled=yesno);
}
bool_t linphone_core_video_multicast_enabled(const LinphoneCore *lc) {
return lc->rtp_conf.video_multicast_enabled;
}
#ifdef ANDROID
static int linphone_core_call_void_method(jobject obj, jmethodID id) {
JNIEnv *env=ms_get_jni_env();
if (env && obj) {
(*env)->CallVoidMethod(env,obj,id);
if ((*env)->ExceptionCheck(env)) {
(*env)->ExceptionClear(env);
return -1;
} else
return 0;
} else
return -1;
}
void linphone_core_wifi_lock_acquire(LinphoneCore *lc) {
if (linphone_core_call_void_method(lc->wifi_lock,lc->wifi_lock_acquire_id))
ms_warning("No wifi lock configured or not usable for core [%p]",lc);
}
void linphone_core_wifi_lock_release(LinphoneCore *lc) {
if (linphone_core_call_void_method(lc->wifi_lock,lc->wifi_lock_release_id))
ms_warning("No wifi lock configured or not usable for core [%p]",lc);
}
void linphone_core_multicast_lock_acquire(LinphoneCore *lc) {
if (linphone_core_call_void_method(lc->multicast_lock,lc->multicast_lock_acquire_id))
ms_warning("No multicast lock configured or not usable for core [%p]",lc);
}
void linphone_core_multicast_lock_release(LinphoneCore *lc) {
if (linphone_core_call_void_method(lc->multicast_lock,lc->multicast_lock_release_id))
ms_warning("No wifi lock configured or not usable for core [%p]",lc);
}
#endif

View file

@ -287,7 +287,8 @@ typedef enum _LinphoneAVPFMode LinphoneAVPFMode;
enum _LinphoneMediaEncryption {
LinphoneMediaEncryptionNone, /**< No media encryption is used */
LinphoneMediaEncryptionSRTP, /**< Use SRTP media encryption */
LinphoneMediaEncryptionZRTP /**< Use ZRTP media encryption */
LinphoneMediaEncryptionZRTP, /**< Use ZRTP media encryption */
LinphoneMediaEncryptionDTLS /**< Use DTLS media encryption */
};
/**
@ -396,7 +397,9 @@ LINPHONE_PUBLIC void linphone_address_set_domain(LinphoneAddress *uri, const cha
LINPHONE_PUBLIC void linphone_address_set_port(LinphoneAddress *uri, int port);
/*remove tags, params etc... so that it is displayable to the user*/
LINPHONE_PUBLIC void linphone_address_clean(LinphoneAddress *uri);
LINPHONE_PUBLIC bool_t linphone_address_is_secure(const LinphoneAddress *uri);
LINPHONE_PUBLIC bool_t linphone_address_is_secure(const LinphoneAddress *addr);
LINPHONE_PUBLIC bool_t linphone_address_get_secure(const LinphoneAddress *addr);
LINPHONE_PUBLIC void linphone_address_set_secure(LinphoneAddress *addr, bool_t enabled);
LINPHONE_PUBLIC bool_t linphone_address_is_sip(const LinphoneAddress *uri);
LINPHONE_PUBLIC LinphoneTransportType linphone_address_get_transport(const LinphoneAddress *uri);
LINPHONE_PUBLIC void linphone_address_set_transport(LinphoneAddress *uri,LinphoneTransportType type);
@ -756,6 +759,19 @@ LINPHONE_PUBLIC int linphone_call_send_dtmfs(LinphoneCall *call,char *dtmfs);
**/
LINPHONE_PUBLIC void linphone_call_cancel_dtmfs(LinphoneCall *call);
/**
* Get the native window handle of the video window, casted as an unsigned long.
* @ingroup media_parameters
**/
LINPHONE_PUBLIC unsigned long linphone_call_get_native_video_window_id(const LinphoneCall *call);
/**
* Set the native video window id where the video is to be displayed.
* For MacOS, Linux, Windows: if not set or 0 a window will be automatically created, unless the special id -1 is given.
* @ingroup media_parameters
**/
LINPHONE_PUBLIC void linphone_call_set_native_video_window_id(LinphoneCall *call, unsigned long id);
/**
* Return TRUE if this call is currently part of a conference
* @param call #LinphoneCall
@ -2277,6 +2293,10 @@ LINPHONE_PUBLIC const MSList *linphone_core_get_video_codecs(const LinphoneCore
LINPHONE_PUBLIC int linphone_core_set_video_codecs(LinphoneCore *lc, MSList *codecs);
LINPHONE_PUBLIC void linphone_core_enable_generic_confort_noise(LinphoneCore *lc, bool_t enabled);
LINPHONE_PUBLIC bool_t linphone_core_generic_confort_noise_enabled(const LinphoneCore *lc);
/**
* Tells whether the specified payload type is enabled.
* @param[in] lc #LinphoneCore object.
@ -3048,6 +3068,22 @@ LINPHONE_PUBLIC void linphone_core_set_zrtp_secrets_file(LinphoneCore *lc, const
*/
LINPHONE_PUBLIC const char *linphone_core_get_zrtp_secrets_file(LinphoneCore *lc);
/**
* Set the path to the directory storing the user's x509 certificates (used by dtls)
* @param[in] lc #LinphoneCore object
* @param[in] path The path to the directory to use to store the user's certificates.
* @ingroup initializing
*/
LINPHONE_PUBLIC void linphone_core_set_user_certificates_path(LinphoneCore *lc, const char* path);
/**
* Get the path to the directory storing the user's certificates.
* @param[in] lc #LinphoneCore object.
* @returns The path to the directory storing the user's certificates.
* @ingroup initializing
*/
LINPHONE_PUBLIC const char *linphone_core_get_user_certificates_path(LinphoneCore *lc);
/**
* Search from the list of current calls if a remote address match uri
* @ingroup call_control
@ -3269,6 +3305,108 @@ LINPHONE_PUBLIC void linphone_core_set_avpf_rr_interval(LinphoneCore *lc, int in
LINPHONE_PUBLIC int linphone_core_get_avpf_rr_interval(const LinphoneCore *lc);
/**
* Use to set multicast address to be used for audio stream.
* @param core #LinphoneCore
* @param ip an ipv4/6 multicast address
* @return 0 in case of success
* @ingroup media_parameters
**/
LINPHONE_PUBLIC int linphone_core_set_audio_multicast_addr(LinphoneCore *core, const char* ip);
/**
* Use to set multicast address to be used for video stream.
* @param core #LinphoneCore
* @param ip an ipv4/6 multicast address
* @return 0 in case of success
* @ingroup media_parameters
**/
LINPHONE_PUBLIC int linphone_core_set_video_multicast_addr(LinphoneCore *lc, const char *ip);
/**
* Use to get multicast address to be used for audio stream.
* @param core #LinphoneCore
* @return an ipv4/6 multicast address or default value
* @ingroup media_parameters
**/
LINPHONE_PUBLIC const char* linphone_core_get_audio_multicast_addr(const LinphoneCore *core);
/**
* Use to get multicast address to be used for video stream.
* @param core #LinphoneCore
* @return an ipv4/6 multicast address, or default value
* @ingroup media_parameters
**/
LINPHONE_PUBLIC const char* linphone_core_get_video_multicast_addr(const LinphoneCore *core);
/**
* Use to set multicast ttl to be used for audio stream.
* @param core #LinphoneCore
* @param ttl value or -1 if not used. [0..255] default value is 1
* @return 0 in case of success
* @ingroup media_parameters
**/
LINPHONE_PUBLIC int linphone_core_set_audio_multicast_ttl(LinphoneCore *core, int ttl);
/**
* Use to set multicast ttl to be used for video stream.
* @param core #LinphoneCore
* @param ttl value or -1 if not used. [0..255] default value is 1
* @return 0 in case of success
* @ingroup media_parameters
**/
LINPHONE_PUBLIC int linphone_core_set_video_multicast_ttl(LinphoneCore *lc, int ttl);
/**
* Use to get multicast ttl to be used for audio stream.
* @param core #LinphoneCore
* @return a time to leave value
* @ingroup media_parameters
**/
LINPHONE_PUBLIC int linphone_core_get_audio_multicast_ttl(const LinphoneCore *core);
/**
* Use to get multicast ttl to be used for video stream.
* @param core #LinphoneCore
* @return a time to leave value
* @ingroup media_parameters
**/
LINPHONE_PUBLIC int linphone_core_get_video_multicast_ttl(const LinphoneCore *core);
/**
* Use to enable multicast rtp for audio stream.
* * If enabled, outgoing calls put a multicast address from #linphone_core_get_video_multicast_addr into audio cline. In case of outgoing call audio stream is sent to this multicast address.
* <br> For incoming calls behavior is unchanged.
* @param core #LinphoneCore
* @param yesno if yes, subsequent calls will propose multicast ip set by #linphone_core_set_audio_multicast_addr
* @ingroup media_parameters
**/
LINPHONE_PUBLIC void linphone_core_enable_audio_multicast(LinphoneCore *core, bool_t yesno);
/**
* Use to get multicast state of audio stream.
* @param core #LinphoneCore
* @return true if subsequent calls will propose multicast ip set by #linphone_core_set_audio_multicast_addr
* @ingroup media_parameters
**/
LINPHONE_PUBLIC bool_t linphone_core_audio_multicast_enabled(const LinphoneCore *core);
/**
* Use to enable multicast rtp for video stream.
* If enabled, outgoing calls put a multicast address from #linphone_core_get_video_multicast_addr into video cline. In case of outgoing call video stream is sent to this multicast address.
* <br> For incoming calls behavior is unchanged.
* @param core #LinphoneCore
* @param yesno if yes, subsequent outgoing calls will propose multicast ip set by #linphone_core_set_video_multicast_addr
* @ingroup media_parameters
**/
LINPHONE_PUBLIC void linphone_core_enable_video_multicast(LinphoneCore *core, bool_t yesno);
/**
* Use to get multicast state of video stream.
* @param core #LinphoneCore
* @return true if subsequent calls will propose multicast ip set by #linphone_core_set_video_multicast_addr
* @ingroup media_parameters
**/
LINPHONE_PUBLIC bool_t linphone_core_video_multicast_enabled(const LinphoneCore *core);
#ifdef __cplusplus
}
#endif

View file

@ -27,8 +27,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
extern "C" {
#include "mediastreamer2/mediastream.h"
#include "mediastreamer2/mscommon.h"
#include "mediastreamer2/dsptools.h"
#include "mediastreamer2/msmediaplayer.h"
#include "mediastreamer2/msutils.h"
}
#include "mediastreamer2/msjava.h"
#include "private.h"
@ -264,7 +264,6 @@ public:
/*displayStatus(LinphoneCore lc,String message);*/
displayStatusId = env->GetMethodID(listenerClass,"displayStatus","(Lorg/linphone/core/LinphoneCore;Ljava/lang/String;)V");
env->ExceptionClear();
if (displayStatusId) {
vTable->display_status = displayStatusCb;
}
@ -273,7 +272,6 @@ public:
globalStateClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneCore$GlobalState"));
globalStateFromIntId = env->GetStaticMethodID(globalStateClass,"fromInt","(I)Lorg/linphone/core/LinphoneCore$GlobalState;");
globalStateId = env->GetMethodID(listenerClass,"globalState","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCore$GlobalState;Ljava/lang/String;)V");
env->ExceptionClear();
if (globalStateId) {
vTable->global_state_changed = globalStateChange;
}
@ -282,7 +280,6 @@ public:
registrationStateClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneCore$RegistrationState"));
registrationStateFromIntId = env->GetStaticMethodID(registrationStateClass,"fromInt","(I)Lorg/linphone/core/LinphoneCore$RegistrationState;");
registrationStateId = env->GetMethodID(listenerClass,"registrationState","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneProxyConfig;Lorg/linphone/core/LinphoneCore$RegistrationState;Ljava/lang/String;)V");
env->ExceptionClear();
if (registrationStateId) {
vTable->registration_state_changed = registrationStateChange;
}
@ -291,27 +288,23 @@ public:
callStateClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneCall$State"));
callStateFromIntId = env->GetStaticMethodID(callStateClass,"fromInt","(I)Lorg/linphone/core/LinphoneCall$State;");
callStateId = env->GetMethodID(listenerClass,"callState","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCall;Lorg/linphone/core/LinphoneCall$State;Ljava/lang/String;)V");
env->ExceptionClear();
if (callStateId) {
vTable->call_state_changed = callStateChange;
}
transferStateId = env->GetMethodID(listenerClass,"transferState","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCall;Lorg/linphone/core/LinphoneCall$State;)V");
env->ExceptionClear();
if (transferStateId) {
vTable->transfer_state_changed = transferStateChanged;
}
/*callStatsUpdated(LinphoneCore lc, LinphoneCall call, LinphoneCallStats stats);*/
callStatsUpdatedId = env->GetMethodID(listenerClass, "callStatsUpdated", "(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCall;Lorg/linphone/core/LinphoneCallStats;)V");
env->ExceptionClear();
if (callStatsUpdatedId) {
vTable->call_stats_updated = callStatsUpdated;
}
/*callEncryption(LinphoneCore lc, LinphoneCall call, boolean encrypted,String auth_token);*/
callEncryptionChangedId = env->GetMethodID(listenerClass,"callEncryptionChanged","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCall;ZLjava/lang/String;)V");
env->ExceptionClear();
if (callEncryptionChangedId) {
vTable->call_encryption_changed = callEncryptionChange;
}
@ -320,55 +313,46 @@ public:
ecCalibratorStatusClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneCore$EcCalibratorStatus"));
ecCalibratorStatusFromIntId = env->GetStaticMethodID(ecCalibratorStatusClass,"fromInt","(I)Lorg/linphone/core/LinphoneCore$EcCalibratorStatus;");
ecCalibrationStatusId = env->GetMethodID(listenerClass,"ecCalibrationStatus","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCore$EcCalibratorStatus;ILjava/lang/Object;)V");
env->ExceptionClear();
/*void newSubscriptionRequest(LinphoneCore lc, LinphoneFriend lf, String url)*/
newSubscriptionRequestId = env->GetMethodID(listenerClass,"newSubscriptionRequest","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneFriend;Ljava/lang/String;)V");
env->ExceptionClear();
if (newSubscriptionRequestId) {
vTable->new_subscription_requested = new_subscription_requested;
}
authInfoRequestedId = env->GetMethodID(listenerClass,"authInfoRequested","(Lorg/linphone/core/LinphoneCore;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
env->ExceptionClear();
if (authInfoRequestedId) {
vTable->auth_info_requested = authInfoRequested;
}
/*void notifyPresenceReceived(LinphoneCore lc, LinphoneFriend lf);*/
notifyPresenceReceivedId = env->GetMethodID(listenerClass,"notifyPresenceReceived","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneFriend;)V");
env->ExceptionClear();
if (notifyPresenceReceivedId) {
vTable->notify_presence_received = notify_presence_received;
}
/*void textReceived(LinphoneCore lc, LinphoneChatRoom cr,LinphoneAddress from,String message);*/
textReceivedId = env->GetMethodID(listenerClass,"textReceived","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneChatRoom;Lorg/linphone/core/LinphoneAddress;Ljava/lang/String;)V");
env->ExceptionClear();
if (textReceivedId) {
vTable->text_received = text_received;
}
messageReceivedId = env->GetMethodID(listenerClass,"messageReceived","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneChatRoom;Lorg/linphone/core/LinphoneChatMessage;)V");
env->ExceptionClear();
if (messageReceivedId) {
vTable->message_received = message_received;
}
isComposingReceivedId = env->GetMethodID(listenerClass,"isComposingReceived","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneChatRoom;)V");
env->ExceptionClear();
if (isComposingReceivedId) {
vTable->is_composing_received = is_composing_received;
}
dtmfReceivedId = env->GetMethodID(listenerClass,"dtmfReceived","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCall;I)V");
env->ExceptionClear();
if (dtmfReceivedId) {
vTable->dtmf_received = dtmf_received;
}
infoReceivedId = env->GetMethodID(listenerClass,"infoReceived", "(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCall;Lorg/linphone/core/LinphoneInfoMessage;)V");
env->ExceptionClear();
if (infoReceivedId) {
vTable->info_received = infoReceived;
}
@ -376,7 +360,6 @@ public:
subscriptionStateClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/SubscriptionState"));
subscriptionStateFromIntId = env->GetStaticMethodID(subscriptionStateClass,"fromInt","(I)Lorg/linphone/core/SubscriptionState;");
subscriptionStateId = env->GetMethodID(listenerClass,"subscriptionStateChanged", "(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneEvent;Lorg/linphone/core/SubscriptionState;)V");
env->ExceptionClear();
if (subscriptionStateId) {
vTable->subscription_state_changed = subscriptionStateChanged;
}
@ -384,13 +367,11 @@ public:
publishStateClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/PublishState"));
publishStateFromIntId = env->GetStaticMethodID(publishStateClass,"fromInt","(I)Lorg/linphone/core/PublishState;");
publishStateId = env->GetMethodID(listenerClass,"publishStateChanged", "(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneEvent;Lorg/linphone/core/PublishState;)V");
env->ExceptionClear();
if (publishStateId) {
vTable->publish_state_changed = publishStateChanged;
}
notifyRecvId = env->GetMethodID(listenerClass,"notifyReceived", "(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneEvent;Ljava/lang/String;Lorg/linphone/core/LinphoneContent;)V");
env->ExceptionClear();
if (notifyRecvId) {
vTable->notify_received = notifyReceived;
}
@ -398,38 +379,32 @@ public:
configuringStateClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneCore$RemoteProvisioningState"));
configuringStateFromIntId = env->GetStaticMethodID(configuringStateClass,"fromInt","(I)Lorg/linphone/core/LinphoneCore$RemoteProvisioningState;");
configuringStateId = env->GetMethodID(listenerClass,"configuringStatus","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCore$RemoteProvisioningState;Ljava/lang/String;)V");
env->ExceptionClear();
if (configuringStateId) {
vTable->configuring_status = configuringStatus;
}
fileTransferProgressIndicationId = env->GetMethodID(listenerClass, "fileTransferProgressIndication", "(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneChatMessage;Lorg/linphone/core/LinphoneContent;I)V");
env->ExceptionClear();
if (fileTransferProgressIndicationId) {
vTable->file_transfer_progress_indication = fileTransferProgressIndication;
}
fileTransferSendId = env->GetMethodID(listenerClass, "fileTransferSend", "(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneChatMessage;Lorg/linphone/core/LinphoneContent;Ljava/nio/ByteBuffer;I)I");
env->ExceptionClear();
if (fileTransferSendId) {
vTable->file_transfer_send = fileTransferSend;
}
fileTransferRecvId = env->GetMethodID(listenerClass, "fileTransferRecv", "(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneChatMessage;Lorg/linphone/core/LinphoneContent;[BI)V");
env->ExceptionClear();
if (fileTransferRecvId) {
vTable->file_transfer_recv = fileTransferRecv;
}
logCollectionUploadStateClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneCore$LogCollectionUploadState"));
logCollectionUploadStateFromIntId = env->GetStaticMethodID(logCollectionUploadStateClass, "fromInt", "(I)Lorg/linphone/core/LinphoneCore$LogCollectionUploadState;");
logCollectionUploadProgressId = env->GetMethodID(listenerClass, "uploadProgressIndication", "(Lorg/linphone/core/LinphoneCore;II)V");
env->ExceptionClear();
if (logCollectionUploadProgressId) {
vTable->log_collection_upload_progress_indication = logCollectionUploadProgressIndication;
}
logCollectionUploadStateId = env->GetMethodID(listenerClass, "uploadStateChanged", "(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCore$LogCollectionUploadState;Ljava/lang/String;)V");
env->ExceptionClear();
if (logCollectionUploadStateId) {
vTable->log_collection_upload_state_changed = logCollectionUploadStateChange;
}
@ -810,7 +785,7 @@ public:
ms_error("cannot attach VM");
return;
}
LinphoneCoreVTable *table = (LinphoneCoreVTable*) data;
if (table) {
LinphoneCoreData* lcData = (LinphoneCoreData*) linphone_core_v_table_get_user_data(table);
@ -1120,19 +1095,20 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_addListener(JNIEnv* env,
extern "C" void Java_org_linphone_core_LinphoneCoreImpl_removeListener(JNIEnv* env, jobject thiz, jlong lc, jobject jlistener) {
MSList* iterator;
LinphoneCore *core = (LinphoneCore*)lc;
jobject listener = env->NewGlobalRef(jlistener);
for (iterator = core->vtables; iterator != NULL; iterator = iterator->next) {
//jobject listener = env->NewGlobalRef(jlistener);
for (iterator = core->vtables; iterator != NULL; ) {
LinphoneCoreVTable *vTable = (LinphoneCoreVTable*)(iterator->data);
iterator = iterator->next; //Because linphone_core_remove_listener may change the list
if (vTable) {
LinphoneCoreData *data = (LinphoneCoreData*) linphone_core_v_table_get_user_data(vTable);
if (data && env->IsSameObject(data->listener, listener)) {
if (data && env->IsSameObject(data->listener, jlistener)) {
linphone_core_remove_listener(core, vTable);
delete data;
linphone_core_v_table_destroy(vTable);
break;
}
}
}
env->DeleteGlobalRef(listener);
//env->DeleteGlobalRef(listener);
}
@ -1812,6 +1788,16 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setRootCA(JNIEnv* env
linphone_core_set_root_ca((LinphoneCore*)lc,path);
if (path) env->ReleaseStringUTFChars(jpath, path);
}
extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setRingback(JNIEnv* env
,jobject thiz
,jlong lc
,jstring jpath) {
const char* path = jpath?env->GetStringUTFChars(jpath, NULL):NULL;
linphone_core_set_ringback((LinphoneCore*)lc,path);
if (path) env->ReleaseStringUTFChars(jpath, path);
}
extern "C" void Java_org_linphone_core_LinphoneCoreImpl_enableKeepAlive(JNIEnv* env
,jobject thiz
,jlong lc
@ -1832,7 +1818,7 @@ extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_startEchoCalibration(JNI
LinphoneCoreVTable *vTable = linphone_core_v_table_new();
LinphoneCoreData* ldata = new LinphoneCoreData(env, thiz, vTable, data);
linphone_core_v_table_set_user_data(vTable, ldata);
return (jint)linphone_core_start_echo_calibration((LinphoneCore*)lc, ldata->ecCalibrationStatus, NULL, NULL, vTable);
}
@ -3395,6 +3381,14 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setPreferredVideoSize(JN
linphone_core_set_preferred_video_size((LinphoneCore *)lc, vsize);
}
extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setPreferredFramerate(JNIEnv *env, jobject thiz, jlong lc, jfloat framerate){
linphone_core_set_preferred_framerate((LinphoneCore *)lc, framerate);
}
extern "C" float Java_org_linphone_core_LinphoneCoreImpl_getPreferredFramerate(JNIEnv *env, jobject thiz, jlong lc){
return linphone_core_get_preferred_framerate((LinphoneCore *)lc);
}
JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneCoreImpl_setPreferredVideoSizeByName(JNIEnv *env, jobject thiz, jlong lc, jstring jName) {
const char* cName = env->GetStringUTFChars(jName, NULL);
linphone_core_set_preferred_video_size_by_name((LinphoneCore *)lc, cName);
@ -3977,6 +3971,37 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setAndroidPowerManager(J
#endif
}
extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setAndroidWifiLock(JNIEnv *env, jobject thiz, jlong ptr, jobject wifi_lock) {
#ifdef ANDROID
LinphoneCore *lc=(LinphoneCore*)ptr;
if (lc->wifi_lock)
env->DeleteGlobalRef(lc->wifi_lock);
if (wifi_lock != NULL) {
lc->wifi_lock=env->NewGlobalRef(wifi_lock);
jclass wifiLockClass = env->FindClass("android/net/wifi/WifiManager$WifiLock");
lc->wifi_lock_acquire_id = env->GetMethodID(wifiLockClass, "acquire", "()V");
lc->wifi_lock_release_id = env->GetMethodID(wifiLockClass, "release", "()V");
} else {
lc->wifi_lock=NULL;
}
#endif
}
extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setAndroidMulticastLock(JNIEnv *env, jobject thiz, jlong ptr, jobject multicast_lock) {
#ifdef ANDROID
LinphoneCore *lc=(LinphoneCore*)ptr;
if (lc->multicast_lock)
env->DeleteGlobalRef(lc->multicast_lock);
if (multicast_lock != NULL) {
lc->multicast_lock=env->NewGlobalRef(multicast_lock);
jclass multicastLockClass = env->FindClass("android/net/wifi/WifiManager$MulticastLock");
lc->multicast_lock_acquire_id = env->GetMethodID(multicastLockClass, "acquire", "()V");
lc->multicast_lock_release_id = env->GetMethodID(multicastLockClass, "release", "()V");
} else {
lc->multicast_lock=NULL;
}
#endif
}
extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_getAudioDscp(JNIEnv* env,jobject thiz,jlong ptr){
return linphone_core_get_audio_dscp((LinphoneCore*)ptr);
}
@ -5570,3 +5595,142 @@ extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_createLocalPlayer(JNIEn
return (jlong)player;
}
}
/*
* Class: org_linphone_core_LinphoneCoreImpl
* Method: setAudioMulticastAddr
* Signature: (JLjava/lang/String;)I
*/
extern "C" jint JNICALL Java_org_linphone_core_LinphoneCoreImpl_setAudioMulticastAddr
(JNIEnv * env , jobject, jlong ptr, jstring value) {
const char *char_value = value ? env->GetStringUTFChars(value, NULL) : NULL;
LinphoneCore *lc=(LinphoneCore*)ptr;
int result = linphone_core_set_audio_multicast_addr(lc,char_value);
if (char_value) env->ReleaseStringUTFChars(value, char_value);
return result;
}
/*
* Class: org_linphone_core_LinphoneCoreImpl
* Method: setVideoMulticastAddr
* Signature: (JLjava/lang/String;)I
*/
extern "C" jint JNICALL Java_org_linphone_core_LinphoneCoreImpl_setVideoMulticastAddr
(JNIEnv * env, jobject, jlong ptr, jstring value) {
const char *char_value = value ? env->GetStringUTFChars(value, NULL) : NULL;
LinphoneCore *lc=(LinphoneCore*)ptr;
int result = linphone_core_set_video_multicast_addr(lc,char_value);
if (char_value) env->ReleaseStringUTFChars(value, char_value);
return result;
}
/*
* Class: org_linphone_core_LinphoneCoreImpl
* Method: getAudioMulticastAddr
* Signature: (J)Ljava/lang/String;
*/
extern "C" jstring JNICALL Java_org_linphone_core_LinphoneCoreImpl_getAudioMulticastAddr
(JNIEnv *, jobject, jlong) {
ms_error("Java_org_linphone_core_LinphoneCoreImpl_getAudioMulticastAddr not implemented yet");
return NULL;
}
/*
* Class: org_linphone_core_LinphoneCoreImpl
* Method: getVideoMulticastAddr
* Signature: (J)Ljava/lang/String;
*/
extern "C" jstring JNICALL Java_org_linphone_core_LinphoneCoreImpl_getVideoMulticastAddr
(JNIEnv *, jobject, jlong) {
ms_error("Java_org_linphone_core_LinphoneCoreImpl_getVideoMulticastAddr not implemented yet");
return NULL;
}
/*
* Class: org_linphone_core_LinphoneCoreImpl
* Method: setAudioMulticastTtl
* Signature: (JI)I
*/
extern "C" jint JNICALL Java_org_linphone_core_LinphoneCoreImpl_setAudioMulticastTtl
(JNIEnv *, jobject, jlong, jint) {
ms_error("Java_org_linphone_core_LinphoneCoreImpl_setAudioMulticastTtl not implemented yet");
return -1;
}
/*
* Class: org_linphone_core_LinphoneCoreImpl
* Method: setVideoMulticastTtl
* Signature: (JI)I
*/
extern "C" jint JNICALL Java_org_linphone_core_LinphoneCoreImpl_setVideoMulticastTtl
(JNIEnv *, jobject, jlong, jint) {
ms_error("Java_org_linphone_core_LinphoneCoreImpl_setVideoMulticastTtl not implemented yet");
return -1;
}
/*
* Class: org_linphone_core_LinphoneCoreImpl
* Method: getAudioMulticastTtl
* Signature: (J)I
*/
extern "C" jint JNICALL Java_org_linphone_core_LinphoneCoreImpl_getAudioMulticastTtl
(JNIEnv *, jobject, jlong) {
ms_error("Java_org_linphone_core_LinphoneCoreImpl_getAudioMulticastTtl not implemented yet");
return -1;
}
/*
* Class: org_linphone_core_LinphoneCoreImpl
* Method: getVideoMulticastTtl
* Signature: (J)I
*/
extern "C" jint JNICALL Java_org_linphone_core_LinphoneCoreImpl_getVideoMulticastTtl
(JNIEnv *, jobject, jlong) {
ms_error("Java_org_linphone_core_LinphoneCoreImpl_getVideoMulticastTtl not implemented yet");
return -1;
}
/*
* Class: org_linphone_core_LinphoneCoreImpl
* Method: enableAudioMulticast
* Signature: (JZ)V
*/
extern "C" void JNICALL Java_org_linphone_core_LinphoneCoreImpl_enableAudioMulticast
(JNIEnv *, jobject, jlong, jboolean) {
ms_error("Java_org_linphone_core_LinphoneCoreImpl_enableAudioMulticast not implemented yet");
}
/*
* Class: org_linphone_core_LinphoneCoreImpl
* Method: audioMulticastEnabled
* Signature: (J)Z
*/
extern "C" jboolean JNICALL Java_org_linphone_core_LinphoneCoreImpl_audioMulticastEnabled
(JNIEnv *, jobject, jlong) {
ms_error("Java_org_linphone_core_LinphoneCoreImpl_audioMulticastEnabled not implemented yet");
return false;
}
/*
* Class: org_linphone_core_LinphoneCoreImpl
* Method: enableVideoMulticast
* Signature: (JZ)V
*/
extern "C" void JNICALL Java_org_linphone_core_LinphoneCoreImpl_enableVideoMulticast
(JNIEnv *, jobject, jlong, jboolean) {
ms_error("Java_org_linphone_core_LinphoneCoreImpl_enableVideoMulticast not implemented yet");
}
/*
* Class: org_linphone_core_LinphoneCoreImpl
* Method: videoMulticastEnabled
* Signature: (J)Z
*/
extern "C" jboolean JNICALL Java_org_linphone_core_LinphoneCoreImpl_videoMulticastEnabled
(JNIEnv *, jobject, jlong) {
ms_error("Java_org_linphone_core_LinphoneCoreImpl_videoMulticastEnabled not implemented yet");
return false;
}

View file

@ -41,7 +41,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#endif /*_WIN32_WCE*/
#undef snprintf
#include <ortp/stun.h>
#include <mediastreamer2/stun.h>
#ifdef HAVE_GETIFADDRS
#include <net/if.h>
@ -891,8 +891,8 @@ void linphone_call_update_ice_from_remote_media_description(LinphoneCall *call,
if (cl && (stream->ice_pwd[0] != '\0') && (stream->ice_ufrag[0] != '\0')) {
if (ice_check_list_remote_credentials_changed(cl, stream->ice_ufrag, stream->ice_pwd)) {
if (ice_restarted == FALSE
&& ice_check_list_remote_ufrag(cl)
&& ice_check_list_remote_pwd(cl)) {
&& ice_check_list_get_remote_ufrag(cl)
&& ice_check_list_get_remote_pwd(cl)) {
/* restart onlu if remote ufrag/paswd was already set*/
ice_session_restart(call->ice_session);
ice_restarted = TRUE;

View file

@ -127,7 +127,9 @@ static PayloadTypeMatcher matchers[]={
};
/*
* Returns a PayloadType from the local list that matches a PayloadType offered or answered in the remote list
*/
static PayloadType * find_payload_type_best_match(const MSList *l, const PayloadType *refpt){
PayloadTypeMatcher *m;
for(m=matchers;m->mime_type!=NULL;++m){
@ -162,8 +164,9 @@ static MSList *match_payloads(const MSList *local, const MSList *remote, bool_t
}
newp=payload_type_clone(matched);
if (p2->send_fmtp)
payload_type_set_send_fmtp(newp,p2->send_fmtp);
if (p2->send_fmtp){
payload_type_append_send_fmtp(newp,p2->send_fmtp);
}
newp->flags|=PAYLOAD_TYPE_FLAG_CAN_RECV|PAYLOAD_TYPE_FLAG_CAN_SEND;
if (p2->flags & PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED) {
newp->flags |= PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED;
@ -296,9 +299,81 @@ static void initiate_outgoing(const SalStreamDescription *local_offer,
SalStreamDescription *result){
if (remote_answer->rtp_port!=0)
result->payloads=match_payloads(local_offer->payloads,remote_answer->payloads,TRUE,FALSE);
else {
ms_message("Local stream description [%p] rejected by peer",local_offer);
result->rtp_port=0;
return;
}
result->proto=remote_answer->proto;
result->type=local_offer->type;
result->dir=compute_dir_outgoing(local_offer->dir,remote_answer->dir);
if (local_offer->rtp_addr[0]!='\0' && ms_is_multicast(local_offer->rtp_addr)) {
/*6.2 Multicast Streams
...
If a multicast stream is accepted, the address and port information
in the answer MUST match that of the offer. Similarly, the
directionality information in the answer (sendonly, recvonly, or
sendrecv) MUST equal that of the offer. This is because all
participants in a multicast session need to have equivalent views of
the parameters of the session, an underlying assumption of the
multicast bias of RFC 2327.*/
if (strcmp(local_offer->rtp_addr,remote_answer->rtp_addr) !=0 ) {
ms_message("Remote answered IP [%s] does not match offered [%s] for local stream description [%p]"
,remote_answer->rtp_addr
,local_offer->rtp_addr
,local_offer);
result->rtp_port=0;
return;
}
if (local_offer->rtp_port!=remote_answer->rtp_port) {
ms_message("Remote answered rtp port [%i] does not match offered [%i] for local stream description [%p]"
,remote_answer->rtp_port
,local_offer->rtp_port
,local_offer);
result->rtp_port=0;
return;
}
if (local_offer->dir!=remote_answer->dir) {
ms_message("Remote answered dir [%s] does not match offered [%s] for local stream description [%p]"
,sal_stream_dir_to_string(remote_answer->dir)
,sal_stream_dir_to_string(local_offer->dir)
,local_offer);
result->rtp_port=0;
return;
}
if (local_offer->bandwidth!=remote_answer->bandwidth) {
ms_message("Remote answered bandwidth [%i] does not match offered [%i] for local stream description [%p]"
,remote_answer->bandwidth
,local_offer->bandwidth
,local_offer);
result->rtp_port=0;
return;
}
if (local_offer->ptime > 0 && local_offer->ptime!=remote_answer->ptime) {
ms_message("Remote answered ptime [%i] does not match offered [%i] for local stream description [%p]"
,remote_answer->ptime
,local_offer->ptime
,local_offer);
result->rtp_port=0;
return;
}
if (local_offer->ttl > 0 && local_offer->ttl!=remote_answer->ttl) {
ms_message("Remote answered ttl [%i] does not match offered [%i] for local stream description [%p]"
,remote_answer->ttl
,local_offer->ttl
,local_offer);
result->rtp_port=0;
return;
}
result->ttl=local_offer->ttl;
result->dir=local_offer->dir;
result->multicast_role = SalMulticastSender;
} else {
result->dir=compute_dir_outgoing(local_offer->dir,remote_answer->dir);
}
if (result->payloads && !only_telephone_event(result->payloads)){
strcpy(result->rtp_addr,remote_answer->rtp_addr);
@ -316,6 +391,9 @@ static void initiate_outgoing(const SalStreamDescription *local_offer,
if (!match_crypto_algo(local_offer->crypto, remote_answer->crypto, &result->crypto[0], &result->crypto_local_tag, FALSE))
result->rtp_port = 0;
}
result->rtp_ssrc=local_offer->rtp_ssrc;
strncpy(result->rtcp_cname,local_offer->rtcp_cname,sizeof(result->rtcp_cname));
}
@ -326,15 +404,33 @@ static void initiate_incoming(const SalStreamDescription *local_cap,
result->proto=remote_offer->proto;
result->type=local_cap->type;
result->dir=compute_dir_incoming(local_cap->dir,remote_offer->dir);
if (result->payloads && !only_telephone_event(result->payloads) && (remote_offer->rtp_port!=0 || remote_offer->rtp_port==SalStreamSendOnly)){
if (!result->payloads || only_telephone_event(result->payloads) || remote_offer->rtp_port==0 || remote_offer->dir==SalStreamRecvOnly){
result->rtp_port=0;
return;
}
if (remote_offer->rtp_addr[0]!='\0' && ms_is_multicast(remote_offer->rtp_addr)) {
if (sal_stream_description_has_srtp(result) == TRUE) {
ms_message("SAVP not supported for multicast address for remote stream [%p]",remote_offer);
result->rtp_port=0;
return;
}
result->dir=remote_offer->dir;
strcpy(result->rtp_addr,remote_offer->rtp_addr);
strcpy(result->rtcp_addr,remote_offer->rtcp_addr);
result->rtp_port=remote_offer->rtp_port;
/*result->rtcp_port=remote_offer->rtcp_port;*/
result->rtcp_port=0; /* rtcp not supported yet*/
result->bandwidth=remote_offer->bandwidth;
result->ptime=remote_offer->ptime;
result->ttl=remote_offer->ttl;
result->multicast_role = SalMulticastReceiver;
} else {
strcpy(result->rtp_addr,local_cap->rtp_addr);
strcpy(result->rtcp_addr,local_cap->rtcp_addr);
result->rtp_port=local_cap->rtp_port;
result->rtcp_port=local_cap->rtcp_port;
result->bandwidth=local_cap->bandwidth;
result->ptime=local_cap->ptime;
}else{
result->rtp_port=0;
}
if (sal_stream_description_has_srtp(result) == TRUE) {
/* select crypto algo */
@ -350,8 +446,12 @@ static void initiate_incoming(const SalStreamDescription *local_cap,
memcpy(result->ice_candidates, local_cap->ice_candidates, sizeof(result->ice_candidates));
memcpy(result->ice_remote_candidates, local_cap->ice_remote_candidates, sizeof(result->ice_remote_candidates));
strcpy(result->name,local_cap->name);
result->rtp_ssrc=local_cap->rtp_ssrc;
strncpy(result->rtcp_cname,local_cap->rtcp_cname,sizeof(result->rtcp_cname));
}
/**
* Returns a media description to run the streams with, based on a local offer
* and the returned response (remote).
@ -384,6 +484,21 @@ int offer_answer_initiate_outgoing(const SalMediaDescription *local_offer,
result->rtcp_xr.enabled = FALSE;
}
// Handle dtls session attribute: if both local and remote have a dtls fingerprint and a dtls setup, get the remote fingerprint into the result
if ((local_offer->dtls_role!=SalDtlsRoleInvalid) && (remote_answer->dtls_role!=SalDtlsRoleInvalid)
&&(strlen(local_offer->dtls_fingerprint)>0) && (strlen(remote_answer->dtls_fingerprint)>0)) {
strcpy(result->dtls_fingerprint, remote_answer->dtls_fingerprint);
if (remote_answer->dtls_role==SalDtlsRoleIsClient) {
result->dtls_role = SalDtlsRoleIsServer;
} else {
result->dtls_role = SalDtlsRoleIsClient;
}
} else {
result->dtls_fingerprint[0] = '\0';
result->dtls_role = SalDtlsRoleInvalid;
}
return 0;
}
@ -403,7 +518,9 @@ static bool_t local_stream_not_already_used(const SalMediaDescription *result, c
static bool_t proto_compatible(SalMediaProto local, SalMediaProto remote) {
if (local == remote) return TRUE;
if ((remote == SalProtoRtpAvp) && ((local == SalProtoRtpSavp) || (local == SalProtoRtpSavpf))) return TRUE;
if ((remote == SalProtoRtpAvp) && ((local == SalProtoUdpTlsRtpSavp) || (local == SalProtoUdpTlsRtpSavpf))) return TRUE;
if ((remote == SalProtoRtpAvpf) && (local == SalProtoRtpSavpf)) return TRUE;
if ((remote == SalProtoRtpAvpf) && (local == SalProtoUdpTlsRtpSavpf)) return TRUE;
return FALSE;
}
@ -437,6 +554,23 @@ int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities
if (ls){
initiate_incoming(ls,rs,&result->streams[i],one_matching_codec);
// Handle dtls stream attribute: if both local and remote have a dtls fingerprint and a dtls setup, add the local fingerprint to the answer
// Note: local description usually stores dtls config at session level which means it apply to all streams, check this too
if (((ls->dtls_role!=SalDtlsRoleInvalid) || (local_capabilities->dtls_role!=SalDtlsRoleInvalid)) && (rs->dtls_role!=SalDtlsRoleInvalid)
&& ((strlen(ls->dtls_fingerprint)>0) || (strlen(local_capabilities->dtls_fingerprint)>0)) && (strlen(rs->dtls_fingerprint)>0)) {
if (strlen(ls->dtls_fingerprint)>0) { /* get the fingerprint in stream description */
strcpy(result->streams[i].dtls_fingerprint, ls->dtls_fingerprint);
} else { /* get the fingerprint in session description */
strcpy(result->streams[i].dtls_fingerprint, local_capabilities->dtls_fingerprint);
}
if (rs->dtls_role==SalDtlsRoleUnset) {
result->streams[i].dtls_role = SalDtlsRoleIsClient;
}
} else {
result->streams[i].dtls_fingerprint[0] = '\0';
result->streams[i].dtls_role = SalDtlsRoleInvalid;
}
// Handle media RTCP XR attribute
memset(&result->streams[i].rtcp_xr, 0, sizeof(result->streams[i].rtcp_xr));
if (rs->rtcp_xr.enabled == TRUE) {
@ -477,6 +611,18 @@ int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities
strcpy(result->name,local_capabilities->name);
// Handle dtls session attribute: if both local and remote have a dtls fingerprint and a dtls setup, add the local fingerprint to the answer
if ((local_capabilities->dtls_role!=SalDtlsRoleInvalid) && (remote_offer->dtls_role!=SalDtlsRoleInvalid)
&&(strlen(local_capabilities->dtls_fingerprint)>0) && (strlen(remote_offer->dtls_fingerprint)>0)) {
strcpy(result->dtls_fingerprint, local_capabilities->dtls_fingerprint);
if (remote_offer->dtls_role==SalDtlsRoleUnset) {
result->dtls_role = SalDtlsRoleIsClient;
}
} else {
result->dtls_fingerprint[0] = '\0';
result->dtls_role = SalDtlsRoleInvalid;
}
// Handle session RTCP XR attribute
memset(&result->rtcp_xr, 0, sizeof(result->rtcp_xr));
if (remote_offer->rtcp_xr.enabled == TRUE) {

View file

@ -1796,6 +1796,8 @@ void linphone_notify_convert_presence_to_xml(SalOp *op, SalPresenceModel *presen
return;
}
xmlTextWriterSetIndent(writer,1);
err = xmlTextWriterStartDocument(writer, "1.0", "UTF-8", NULL);
if (err >= 0) {
err = xmlTextWriterStartElementNS(writer, NULL, (const xmlChar *)"presence", (const xmlChar *)"urn:ietf:params:xml:ns:pidf");

View file

@ -78,6 +78,9 @@ extern "C" {
#define ngettext(singular, plural, number) (((number)==1)?(singular):(plural))
#endif
#endif
#ifdef ANDROID
#include <jni.h>
#endif
struct _LinphoneCallParams{
belle_sip_object_t base;
@ -105,6 +108,9 @@ struct _LinphoneCallParams{
bool_t no_user_consent;/*when set to TRUE an UPDATE request will be used instead of reINVITE*/
uint16_t avpf_rr_interval; /*in milliseconds*/
LinphonePrivacyMask privacy;
LinphoneCallParamsMediaDirection audio_dir;
LinphoneCallParamsMediaDirection video_dir;
};
BELLE_SIP_DECLARE_VPTR(LinphoneCallParams);
@ -196,6 +202,7 @@ typedef struct StunCandidate{
typedef struct _PortConfig{
char multicast_ip[LINPHONE_IPADDR_SIZE];
int rtp_port;
int rtcp_port;
}PortConfig;
@ -213,6 +220,7 @@ struct _LinphoneCall{
struct _RtpProfile *audio_profile;
struct _RtpProfile *video_profile;
struct _LinphoneCallLog *log;
LinphoneAddress *me; /*Either from or to based on call dir*/
SalOp *op;
SalOp *ping_op;
char localip[LINPHONE_IPADDR_SIZE]; /* our best guess for local ipaddress for this call */
@ -225,7 +233,7 @@ struct _LinphoneCall{
StunCandidate ac,vc; /*audio video ip/port discovered by STUN*/
struct _AudioStream *audiostream; /**/
struct _VideoStream *videostream;
unsigned long video_window_id;
MSAudioEndpoint *endpoint; /*used for conferencing*/
char *refer_to;
LinphoneCallParams *params;
@ -253,6 +261,7 @@ struct _LinphoneCall{
char *dtmf_sequence; /*DTMF sequence needed to be sent using #dtmfs_timer*/
belle_sip_source_t *dtmfs_timer; /*DTMF timer needed to send a DTMF sequence*/
char *dtls_certificate_fingerprint; /**> This fingerprint is computed during stream init and is stored in call to be used when making local media description */
bool_t refer_pending;
bool_t expect_media_in_ack;
bool_t audio_muted;
@ -296,20 +305,6 @@ void linphone_core_update_proxy_register(LinphoneCore *lc);
void linphone_core_refresh_subscribes(LinphoneCore *lc);
int linphone_core_abort_call(LinphoneCore *lc, LinphoneCall *call, const char *error);
const char *linphone_core_get_nat_address_resolved(LinphoneCore *lc);
/**
* @brief Equivalent to _linphone_core_get_firewall_policy_with_lie(lc, TRUE)
* @param lc LinphoneCore instance
* @return Fairewall policy
*/
LinphoneFirewallPolicy _linphone_core_get_firewall_policy(const LinphoneCore *lc);
/**
* @brief Get the firwall policy which has been set.
* @param lc Instance of LinphoneCore
* @param lie If true, the configured firewall policy will be returned only if no tunnel are enabled.
* Otherwise, NoFirewallPolicy value will be returned.
* @return The firewall policy
*/
LinphoneFirewallPolicy _linphone_core_get_firewall_policy_with_lie(const LinphoneCore *lc, bool_t lie);
int linphone_proxy_config_send_publish(LinphoneProxyConfig *cfg, LinphonePresenceModel *presence);
void linphone_proxy_config_set_state(LinphoneProxyConfig *cfg, LinphoneRegistrationState rstate, const char *message);
@ -601,6 +596,12 @@ typedef struct rtp_config
bool_t audio_adaptive_jitt_comp_enabled;
bool_t video_adaptive_jitt_comp_enabled;
bool_t pad;
char* audio_multicast_addr;
bool_t audio_multicast_enabled;
int audio_multicast_ttl;
char* video_multicast_addr;
int video_multicast_ttl;
bool_t video_multicast_enabled;
}rtp_config_t;
@ -757,6 +758,7 @@ struct _LinphoneCore
MSList *hooks;
LinphoneConference conf_ctx;
char* zrtp_secrets_cache;
char* user_certificates_path;
LinphoneVideoPolicy video_policy;
bool_t use_files;
bool_t apply_nat_settings;
@ -795,6 +797,14 @@ struct _LinphoneCore
const char **supported_formats;
LinphoneContent *log_collection_upload_information;
LinphoneCoreVTable *current_vtable; // the latest vtable to call a callback, see linphone_core_get_current_vtable
#ifdef ANDROID
jobject wifi_lock;
jmethodID wifi_lock_acquire_id;
jmethodID wifi_lock_release_id;
jobject multicast_lock;
jmethodID multicast_lock_acquire_id;
jmethodID multicast_lock_release_id;
#endif
};
@ -1091,6 +1101,13 @@ void linphone_core_notify_log_collection_upload_progress_indication(LinphoneCore
void set_mic_gain_db(AudioStream *st, float gain);
void set_playback_gain_db(AudioStream *st, float gain);
#ifdef ANDROID
void linphone_core_wifi_lock_acquire(LinphoneCore *lc);
void linphone_core_wifi_lock_release(LinphoneCore *lc);
void linphone_core_multicast_lock_acquire(LinphoneCore *lc);
void linphone_core_multicast_lock_release(LinphoneCore *lc);
#endif
#ifdef __cplusplus
}
#endif

View file

@ -121,7 +121,9 @@ SalStreamDescription * sal_media_description_find_secure_stream_of_type(SalMedia
}
SalStreamDescription * sal_media_description_find_best_stream(SalMediaDescription *md, SalStreamType type) {
SalStreamDescription *desc = sal_media_description_find_stream(md, SalProtoRtpSavpf, type);
SalStreamDescription *desc = sal_media_description_find_stream(md, SalProtoUdpTlsRtpSavpf, type);
if (desc == NULL) desc = sal_media_description_find_stream(md, SalProtoUdpTlsRtpSavp, type);
if (desc == NULL) desc = sal_media_description_find_stream(md, SalProtoRtpSavpf, type);
if (desc == NULL) desc = sal_media_description_find_stream(md, SalProtoRtpSavp, type);
if (desc == NULL) desc = sal_media_description_find_stream(md, SalProtoRtpAvpf, type);
if (desc == NULL) desc = sal_media_description_find_stream(md, SalProtoRtpAvp, type);
@ -195,13 +197,17 @@ bool_t sal_stream_description_active(const SalStreamDescription *sd) {
}
bool_t sal_stream_description_has_avpf(const SalStreamDescription *sd) {
return ((sd->proto == SalProtoRtpAvpf) || (sd->proto == SalProtoRtpSavpf));
return ((sd->proto == SalProtoRtpAvpf) || (sd->proto == SalProtoRtpSavpf) || (sd->proto == SalProtoUdpTlsRtpSavpf));
}
bool_t sal_stream_description_has_srtp(const SalStreamDescription *sd) {
return ((sd->proto == SalProtoRtpSavp) || (sd->proto == SalProtoRtpSavpf));
}
bool_t sal_stream_description_has_dtls(const SalStreamDescription *sd) {
return ((sd->proto == SalProtoUdpTlsRtpSavp) || (sd->proto == SalProtoUdpTlsRtpSavpf));
}
bool_t sal_media_description_has_avpf(const SalMediaDescription *md) {
int i;
if (md->nb_streams == 0) return FALSE;
@ -222,6 +228,16 @@ bool_t sal_media_description_has_srtp(const SalMediaDescription *md) {
return TRUE;
}
bool_t sal_media_description_has_dtls(const SalMediaDescription *md) {
int i;
if (md->nb_streams == 0) return FALSE;
for (i = 0; i < md->nb_streams; i++) {
if (!sal_stream_description_active(&md->streams[i])) continue;
if (sal_stream_description_has_dtls(&md->streams[i]) != TRUE) return FALSE;
}
return TRUE;
}
/*
static bool_t fmtp_equals(const char *p1, const char *p2){
if (p1 && p2 && strcmp(p1,p2)==0) return TRUE;
@ -608,8 +624,10 @@ const char* sal_media_proto_to_string(SalMediaProto type) {
switch (type) {
case SalProtoRtpAvp:return "RTP/AVP";
case SalProtoRtpSavp:return "RTP/SAVP";
case SalProtoUdpTlsRtpSavp:return "UDP/TLS/RTP/SAVP";
case SalProtoRtpAvpf:return "RTP/AVPF";
case SalProtoRtpSavpf:return "RTP/SAVPF";
case SalProtoUdpTlsRtpSavpf:return "UDP/TLS/RTP/SAVPF";
default: return "unknown";
}
}

View file

@ -466,10 +466,17 @@ static void prepare(GtkAssistant *w){
}
void linphone_gtk_close_audio_assistant(GtkWidget *w){
gchar *path = g_object_get_data(G_OBJECT(audio_assistant),"path");
gchar *path;
AudioStream *stream;
path = g_object_get_data(G_OBJECT(audio_assistant),"path");
if(path != NULL){
g_unlink(path);
}
stream = (AudioStream *)g_object_get_data(G_OBJECT(audio_assistant), "stream");
if(stream) {
audio_stream_stop(stream);
}
gtk_widget_destroy(w);
if(linphone_gtk_get_audio_assistant_option()){
gtk_main_quit();

View file

@ -680,6 +680,12 @@ void linphone_gtk_in_call_view_show_encryption(LinphoneCall *call){
gtk_widget_hide(status_icon);
gtk_widget_hide(verify_button);
break;
case LinphoneMediaEncryptionDTLS:
gtk_widget_show_all(encryption_box);
gtk_label_set_markup(GTK_LABEL(label),_("Secured by DTLS"));
gtk_widget_hide(status_icon);
gtk_widget_hide(verify_button);
break;
case LinphoneMediaEncryptionZRTP:
{
gchar *text=g_strdup_printf(_("Secured by ZRTP - [auth token: %s]"),linphone_call_get_authentication_token(call));

View file

@ -181,9 +181,11 @@ static GOptionEntry linphone_options[]={
#ifndef WIN32
#define CONFIG_FILE ".linphonerc"
#define SECRETS_FILE ".linphone-zidcache"
#define CERTIFICATES_PATH ".linphone-usr-crt"
#else
#define CONFIG_FILE "linphonerc"
#define SECRETS_FILE "linphone-zidcache"
#define CERTIFICATES_PATH "linphone-usr-crt"
#endif
char *linphone_gtk_get_config_file(const char *filename){
@ -288,6 +290,7 @@ static void linphone_gtk_init_liblinphone(const char *config_file,
const char *factory_config_file, const char *db_file) {
LinphoneCoreVTable vtable={0};
gchar *secrets_file=linphone_gtk_get_config_file(SECRETS_FILE);
gchar *user_certificates_dir=linphone_gtk_get_config_file(CERTIFICATES_PATH);
vtable.global_state_changed=linphone_gtk_global_state_changed;
vtable.call_state_changed=linphone_gtk_call_state_changed;
@ -325,6 +328,8 @@ static void linphone_gtk_init_liblinphone(const char *config_file,
linphone_core_set_waiting_callback(the_core,linphone_gtk_wait,NULL);
linphone_core_set_zrtp_secrets_file(the_core,secrets_file);
g_free(secrets_file);
linphone_core_set_user_certificates_path(the_core,user_certificates_dir);
g_free(user_certificates_dir);
linphone_core_enable_video_capture(the_core, TRUE);
linphone_core_enable_video_display(the_core, TRUE);
linphone_core_set_native_video_window_id(the_core,-1);/*don't create the window*/

View file

@ -1199,11 +1199,13 @@ static void linphone_gtk_media_encryption_changed(GtkWidget *combo){
if (strcasecmp(selected,"SRTP")==0){
linphone_core_set_media_encryption(lc,LinphoneMediaEncryptionSRTP);
linphone_gtk_set_media_encryption_mandatory_sensitive(toplevel,TRUE);
}else if (strcasecmp(selected,"DTLS")==0){
linphone_core_set_media_encryption(lc,LinphoneMediaEncryptionDTLS);
linphone_gtk_set_media_encryption_mandatory_sensitive(toplevel,FALSE);
}else if (strcasecmp(selected,"ZRTP")==0){
linphone_core_set_media_encryption(lc,LinphoneMediaEncryptionZRTP);
linphone_gtk_set_media_encryption_mandatory_sensitive(toplevel,FALSE);
}
else {
} else {
linphone_core_set_media_encryption(lc,LinphoneMediaEncryptionNone);
linphone_gtk_set_media_encryption_mandatory_sensitive(toplevel,FALSE);
}
@ -1219,7 +1221,7 @@ static void linphone_gtk_show_media_encryption(GtkWidget *pb){
LinphoneCore *lc=linphone_gtk_get_core();
GtkWidget *combo=linphone_gtk_get_widget(pb,"media_encryption_combo");
bool_t no_enc=TRUE;
int srtp_id=-1,zrtp_id=-1;
int srtp_id=-1,zrtp_id=-1,dtls_id=-1;
GtkTreeModel *model;
GtkListStore *store;
GtkTreeIter iter;
@ -1239,12 +1241,26 @@ static void linphone_gtk_show_media_encryption(GtkWidget *pb){
srtp_id=1;
no_enc=FALSE;
}
if (linphone_core_media_encryption_supported(lc,LinphoneMediaEncryptionDTLS)){
gtk_list_store_append(store,&iter);
gtk_list_store_set(store,&iter,0,_("DTLS"),-1);
if (srtp_id!=-1) dtls_id=2;
else dtls_id=1;
no_enc=FALSE;
}
if (linphone_core_media_encryption_supported(lc,LinphoneMediaEncryptionZRTP)){
gtk_list_store_append(store,&iter);
gtk_list_store_set(store,&iter,0,_("ZRTP"),-1);
no_enc=FALSE;
if (srtp_id!=-1) zrtp_id=2;
else zrtp_id=1;
if (srtp_id!=-1) {
if (dtls_id!=-1)
zrtp_id=3;
else zrtp_id=2;
} else {
if (dtls_id!=-1)
zrtp_id=2;
else zrtp_id=1;
}
}
if (no_enc){
/*hide this setting*/
@ -1264,6 +1280,12 @@ static void linphone_gtk_show_media_encryption(GtkWidget *pb){
linphone_gtk_set_media_encryption_mandatory_sensitive(pb,TRUE);
}
break;
case LinphoneMediaEncryptionDTLS:
if (dtls_id!=-1) {
gtk_combo_box_set_active(GTK_COMBO_BOX(combo),dtls_id);
linphone_gtk_set_media_encryption_mandatory_sensitive(pb,TRUE);
}
break;
case LinphoneMediaEncryptionZRTP:
if (zrtp_id!=-1) {
gtk_combo_box_set_active(GTK_COMBO_BOX(combo),zrtp_id);

View file

@ -92,6 +92,7 @@ const char *sal_address_get_username(const SalAddress *addr);
const char *sal_address_get_domain(const SalAddress *addr);
int sal_address_get_port(const SalAddress *addr);
bool_t sal_address_is_secure(const SalAddress *addr);
void sal_address_set_secure(SalAddress *addr, bool_t enabled);
SalTransport sal_address_get_transport(const SalAddress* addr);
const char* sal_address_get_transport_name(const SalAddress* addr);
@ -133,6 +134,8 @@ typedef enum{
SalProtoRtpSavp,
SalProtoRtpAvpf,
SalProtoRtpSavpf,
SalProtoUdpTlsRtpSavp,
SalProtoUdpTlsRtpSavpf,
SalProtoOther
}SalMediaProto;
const char* sal_media_proto_to_string(SalMediaProto type);
@ -163,7 +166,7 @@ typedef struct SalIceCandidate {
int rport;
} SalIceCandidate;
#define SAL_MEDIA_DESCRIPTION_MAX_ICE_CANDIDATES 10
#define SAL_MEDIA_DESCRIPTION_MAX_ICE_CANDIDATES 20
typedef struct SalIceRemoteCandidate {
char addr[SAL_MEDIA_DESCRIPTION_MAX_ICE_ADDR_LEN];
@ -186,6 +189,21 @@ typedef struct SalSrtpCryptoAlgo {
#define SAL_CRYPTO_ALGO_MAX 4
typedef enum {
SalDtlsRoleInvalid,
SalDtlsRoleIsServer,
SalDtlsRoleIsClient,
SalDtlsRoleUnset
} SalDtlsRole;
typedef enum {
SalMulticastInactive=0,
SalMulticastSender,
SalMulticastReceiver,
SalMulticastSenderReceiver
} SalMulticastRole;
typedef struct SalStreamDescription{
char name[16]; /*unique name of stream, in order to ease offer/answer model algorithm*/
SalMediaProto proto;
@ -194,6 +212,8 @@ typedef struct SalStreamDescription{
char proto_other[32];
char rtp_addr[64];
char rtcp_addr[64];
unsigned int rtp_ssrc;
char rtcp_cname[255];
int rtp_port;
int rtcp_port;
MSList *payloads; /*<list of PayloadType */
@ -212,6 +232,10 @@ typedef struct SalStreamDescription{
bool_t ice_mismatch;
bool_t ice_completed;
bool_t pad[2];
char dtls_fingerprint[256];
SalDtlsRole dtls_role;
int ttl; /*for multicast -1 to disable*/
SalMulticastRole multicast_role;
} SalStreamDescription;
const char *sal_stream_description_get_type_as_string(const SalStreamDescription *desc);
@ -236,6 +260,8 @@ typedef struct SalMediaDescription{
bool_t ice_lite;
bool_t ice_completed;
bool_t pad[2];
char dtls_fingerprint[256];
SalDtlsRole dtls_role;
} SalMediaDescription;
typedef struct SalMessage{
@ -270,8 +296,10 @@ void sal_media_description_set_dir(SalMediaDescription *md, SalStreamDir stream_
bool_t sal_stream_description_active(const SalStreamDescription *sd);
bool_t sal_stream_description_has_avpf(const SalStreamDescription *sd);
bool_t sal_stream_description_has_srtp(const SalStreamDescription *sd);
bool_t sal_stream_description_has_dtls(const SalStreamDescription *sd);
bool_t sal_media_description_has_avpf(const SalMediaDescription *md);
bool_t sal_media_description_has_srtp(const SalMediaDescription *md);
bool_t sal_media_description_has_dtls(const SalMediaDescription *md);
int sal_media_description_get_nb_active_streams(const SalMediaDescription *md);
@ -515,6 +543,18 @@ void sal_certificates_chain_parse_file(SalAuthInfo* auth_info, const char* path,
*/
void sal_signing_key_parse_file(SalAuthInfo* auth_info, const char* path, const char *passwd);
/**
* Parse a directory for files containing certificate with the given subject CNAME
* @param[out] certificate_pem the address of a string to store the certificate in PEM format. To be freed by caller
* @param[out] key_pem the address of a string to store the key in PEM format. To be freed by caller
* @param[in] path directory to parse
* @param[in] subject subject CNAME
* @param[in] format either PEM or DER
* @param[in] generate_certificate if true, if matching certificate and key can't be found, generate it and store it into the given dir, filename will be subject.pem
* @param[in] generate_dtls_fingerprint if true and we have a certificate, generate the dtls fingerprint as described in rfc4572
*/
void sal_certificates_chain_parse_directory(char **certificate_pem, char **key_pem, char **fingerprint, const char* path, const char *subject, SalCertificateRawFormat format, bool_t generate_certificate, bool_t generate_dtls_fingerprint);
void sal_certificates_chain_delete(SalCertificatesChain *chain);
void sal_signing_key_delete(SalSigningKey *key);

View file

@ -20,7 +20,7 @@ package org.linphone.core;
import java.util.Vector;
import org.linphone.core.LinphoneCoreListener.LinphoneEchoCalibrationListener;
import org.linphone.core.LinphoneCoreListener;
import org.linphone.mediastream.video.AndroidVideoWindowImpl;
import org.linphone.mediastream.video.capture.hwconf.AndroidCameraConfiguration;
@ -1025,6 +1025,15 @@ public interface LinphoneCore {
*/
void setRootCA(String path);
/**
* Sets the path to a wav file used for for ringing back.
*
* Ringback means the ring that is heard when it's ringing at the remote party.
*
* @param path The file must be a wav 16bit linear.
*/
void setRingback(String path);
void setUploadBandwidth(int bw);
/**
* Sets maximum available download bandwidth
@ -1075,6 +1084,20 @@ public interface LinphoneCore {
**/
VideoSize getPreferredVideoSize();
/**
* Set the preferred frame rate for video.
* Based on the available bandwidth constraints and network conditions, the video encoder
* remains free to lower the framerate. There is no warranty that the preferred frame rate be the actual framerate.
* used during a call. Default value is 0, which means "use encoder's default fps value".
* @param fps the target frame rate in number of frames per seconds.
**/
void setPreferredFramerate(float fps);
/**
* Returns the preferred video framerate, previously set by setPreferredFramerate().
* @return frame rate in number of frames per seconds.
**/
float getPreferredFramerate();
/**
* Returns the currently supported audio codecs, as PayloadType elements
* @return
@ -1100,7 +1123,7 @@ public interface LinphoneCore {
* @param listener the LinphoneEchoCalibrationListener to call when the calibration is done
* @throws LinphoneCoreException if operation is still in progress;
**/
void startEchoCalibration(LinphoneEchoCalibrationListener listener) throws LinphoneCoreException;
void startEchoCalibration(LinphoneCoreListener listener) throws LinphoneCoreException;
/**
* Returns true if echo calibration is recommended.
@ -1856,4 +1879,89 @@ public interface LinphoneCore {
* Upload the log collection to the configured server url.
*/
public void uploadLogCollection();
/**
* Use to set multicast address to be used for audio stream.
* @param ip an ipv4/6 multicast address
* @return
* @thow LinphoneCoreException
**/
public void setAudioMulticastAddr(String ip) throws LinphoneCoreException;
/**
* Use to set multicast address to be used for video stream.
* @param ip an ipv4/6 multicast address
* @thow LinphoneCoreException
**/
public void setVideoMulticastAddr(String ip) throws LinphoneCoreException;
/**
* Use to get multicast address to be used for audio stream.
* @return an ipv4/6 multicast address or default value
**/
public String getAudioMulticastAddr();
/**
* Use to get multicast address to be used for video stream.
* @return an ipv4/6 multicast address, or default value
**/
public String getVideoMulticastAddr();
/**
* Use to set multicast ttl to be used for audio stream.
* @param ttl value or -1 if not used. [0..255] default value is 1
* @thow LinphoneCoreException
**/
public void setAudioMulticastTtl(int ttl) throws LinphoneCoreException;
/**
* Use to set multicast ttl to be used for video stream.
* @param ttl value or -1 if not used. [0..255] default value is 1
* @thow LinphoneCoreException
**/
public void setVideoMulticastTtl(int ttl) throws LinphoneCoreException;
/**
* Use to get multicast ttl to be used for audio stream.
* @return a time to leave value
* @thow LinphoneCoreException
* **/
public int getAudioMulticastTtl();
/**
* Use to get multicast ttl to be used for video stream.
* @return a time to leave value
* @thow LinphoneCoreException
**/
public int getVideoMulticastTtl();
/**
* Use to enable multicast rtp for audio stream.
* * If enabled, outgoing calls put a multicast address from {@link linphone_core_get_video_multicast_addr} into audio cline. In case of outgoing call audio stream is sent to this multicast address.
* <br> For incoming calls behavior is unchanged.
* @param yesno if yes, subsequent calls will propose multicast ip set by {@link linphone_core_set_audio_multicast_addr}
**/
public void enableAudioMulticast(boolean yesno);
/**
* Use to get multicast state of audio stream.
* @return true if subsequent calls will propose multicast ip set by {@link linphone_core_set_audio_multicast_addr}
**/
public boolean audioMulticastEnabled();
/**
* Use to enable multicast rtp for video stream.
* If enabled, outgoing calls put a multicast address from {@link linphone_core_get_video_multicast_addr} into video cline. In case of outgoing call video stream is sent to this multicast address.
* <br> For incoming calls behavior is unchanged.
* @param yesno if yes, subsequent outgoing calls will propose multicast ip set by {@link linphone_core_set_video_multicast_addr}
**/
public void enableVideoMulticast(boolean yesno);
/**
* Use to get multicast state of video stream.
* @return true if subsequent calls will propose multicast ip set by {@link linphone_core_set_video_multicast_addr}
**/
public boolean videoMulticastEnabled();
}

View file

@ -26,238 +26,214 @@ import java.nio.ByteBuffer;
*This interface holds all callbacks that the application should implement. None is mandatory.
*/
public interface LinphoneCoreListener {
public interface LinphoneListener extends LinphoneCoreListener,
LinphoneRemoteProvisioningListener, LinphoneMessageListener, LinphoneCallStateListener,
LinphoneCallEncryptionStateListener, LinphoneNotifyListener, LinphoneComposingListener,
LinphoneGlobalStateListener, LinphoneRegistrationStateListener, LinphoneLogCollectionUploadListener {
/**< Ask the application some authentication information
* @return */
void authInfoRequested(LinphoneCore lc, String realm, String username, String Domain);
/**
* Call stats notification
*/
void callStatsUpdated(LinphoneCore lc, LinphoneCall call, LinphoneCallStats stats);
/**< Ask the application some authentication information
* @return */
void authInfoRequested(LinphoneCore lc, String realm, String username, String Domain);
/**
* Reports that a new subscription request has been received and wait for a decision.
*Status on this subscription request is notified by changing policy for this friend
*@param lc LinphoneCore
*@param lf LinphoneFriend corresponding to the subscriber
*@param url of the subscriber
*
*/
void newSubscriptionRequest(LinphoneCore lc, LinphoneFriend lf, String url);
/**
* Call stats notification
*/
void callStatsUpdated(LinphoneCore lc, LinphoneCall call, LinphoneCallStats stats);
/**
* Report status change for a friend previously added to LinphoneCore.
* @param lc LinphoneCore
* @param lf updated LinphoneFriend
*/
void notifyPresenceReceived(LinphoneCore lc, LinphoneFriend lf);
/**
* Reports that a new subscription request has been received and wait for a decision.
*Status on this subscription request is notified by changing policy for this friend
*@param lc LinphoneCore
*@param lf LinphoneFriend corresponding to the subscriber
*@param url of the subscriber
*
*/
void newSubscriptionRequest(LinphoneCore lc, LinphoneFriend lf, String url);
/**
* invoked when a new text message is received
* @param lc LinphoneCore
* @param room LinphoneChatRoom involved in this conversation. Can be be created by the framework in case the from is not present in any chat room.
* @param from LinphoneAddress from
* @param message incoming message
*/
void textReceived(LinphoneCore lc, LinphoneChatRoom cr, LinphoneAddress from, String message);
/**
* invoked when a new dtmf is received
* @param lc LinphoneCore
* @param call LinphoneCall involved in the dtmf sending
* @param dtmf value of the dtmf sent
*/
void dtmfReceived(LinphoneCore lc, LinphoneCall call, int dtmf);
/**
* Report Notified message received for this identity.
* @param lc LinphoneCore
* @param call LinphoneCall in case the notify is part of a dialog, may be null
* @param from LinphoneAddress the message comes from
* @param event String the raw body of the notify event.
*
*/
void notifyReceived(LinphoneCore lc, LinphoneCall call, LinphoneAddress from, byte[] event);
/**
* Report status change for a friend previously added to LinphoneCore.
* @param lc LinphoneCore
* @param lf updated LinphoneFriend
*/
void notifyPresenceReceived(LinphoneCore lc, LinphoneFriend lf);
/**
* Notifies progress of a call transfer.
* @param lc the LinphoneCore
* @param call the call through which the transfer was sent.
* @param new_call_state the state of the call resulting of the transfer, at the other party.
**/
void transferState(LinphoneCore lc, LinphoneCall call, LinphoneCall.State new_call_state);
/**
* Notifies an incoming INFO message.
* @param lc the LinphoneCore.
* @param info the info message
*/
void infoReceived(LinphoneCore lc, LinphoneCall call, LinphoneInfoMessage info);
/**
* Notifies of subscription requests state changes, including new incoming subscriptions.
* @param lc the LinphoneCore
* @param ev LinphoneEvent object representing the subscription context.
* @param state actual state of the subscription.
*/
void subscriptionStateChanged(LinphoneCore lc, LinphoneEvent ev, SubscriptionState state);
/**
* Notifies about outgoing generic publish states.
* @param lc the LinphoneCore
* @param ev a LinphoneEvent representing the publish, typically created by {@link LinphoneCore#publish}
* @param state the publish state
*/
void publishStateChanged(LinphoneCore lc, LinphoneEvent ev, PublishState state);
/**< @Deprecated Notifies the application that it should show up
* @return */
void show(LinphoneCore lc);
/**< @Deprecated Callback that notifies various events with human readable text.
* @return */
void displayStatus(LinphoneCore lc,String message);
/**
* invoked when a new text message is received
* @param lc LinphoneCore
* @param room LinphoneChatRoom involved in this conversation. Can be be created by the framework in case the from is not present in any chat room.
* @param from LinphoneAddress from
* @param message incoming message
*/
void textReceived(LinphoneCore lc, LinphoneChatRoom cr, LinphoneAddress from, String message);
/**< @Deprecated Callback to display a message to the user
* @return */
void displayMessage(LinphoneCore lc,String message);
/**
* invoked when a new dtmf is received
* @param lc LinphoneCore
* @param call LinphoneCall involved in the dtmf sending
* @param dtmf value of the dtmf sent
*/
void dtmfReceived(LinphoneCore lc, LinphoneCall call, int dtmf);
/** @Deprecated Callback to display a warning to the user
* @return */
void displayWarning(LinphoneCore lc,String message);
/**
* Callback to be notified about the transfer progress.
* @param lc the LinphoneCore
* @param message the LinphoneChatMessage
* @param content the LinphoneContent
* @param progress percentage of the transfer done
*/
void fileTransferProgressIndication(LinphoneCore lc, LinphoneChatMessage message, LinphoneContent content, int progress);
/**
* Callback to be notified when new data has been received
* @param lc the LinphoneCore
* @param message the LinphoneChatMessage
* @param content the LinphoneContent
* @param buffer
* @param size
*/
void fileTransferRecv(LinphoneCore lc, LinphoneChatMessage message, LinphoneContent content, byte[] buffer, int size);
/**
* Callback to be notified when new data needs to be sent
* @param lc the LinphoneCore
* @param message the LinphoneChatMessage
* @param content the LinphoneContent
* @param buffer
* @param size
* @return the number of bytes written into buffer
*/
int fileTransferSend(LinphoneCore lc, LinphoneChatMessage message, LinphoneContent content, ByteBuffer buffer, int size);
}
public interface LinphoneGlobalStateListener extends LinphoneCoreListener {
/** General State notification
* @param state LinphoneCore.State
* @return
* */
void globalState(LinphoneCore lc,LinphoneCore.GlobalState state, String message);
}
public interface LinphoneRegistrationStateListener extends LinphoneCoreListener {
/**
* Registration state notification
* */
void registrationState(LinphoneCore lc, LinphoneProxyConfig cfg, LinphoneCore.RegistrationState state, String smessage);
}
public interface LinphoneRemoteProvisioningListener extends LinphoneCoreListener {
/**
* Notifies the changes about the remote provisioning step
* @param lc the LinphoneCore
* @param state the RemoteProvisioningState
* @param message the error message if state == Failed
*/
void configuringStatus(LinphoneCore lc, LinphoneCore.RemoteProvisioningState state, String message);
}
public interface LinphoneMessageListener extends LinphoneCoreListener {
/**
* invoked when a new linphone chat message is received
* @param lc LinphoneCore
* @param room LinphoneChatRoom involved in this conversation. Can be be created by the framework in case the from is not present in any chat room.
* @param message incoming linphone chat message message
*/
void messageReceived(LinphoneCore lc, LinphoneChatRoom cr, LinphoneChatMessage message);
}
public interface LinphoneCallStateListener extends LinphoneCoreListener {
/** Call State notification
* @param state LinphoneCall.State
* @return
* */
void callState(LinphoneCore lc, LinphoneCall call, LinphoneCall.State state, String message);
}
public interface LinphoneCallEncryptionStateListener extends LinphoneCoreListener {
/**
* Callback to display change in encryption state.
* @param encrypted true if all streams of the call are encrypted
* @param authenticationToken token like ZRTP SAS that may be displayed to user
*/
void callEncryptionChanged(LinphoneCore lc, LinphoneCall call, boolean encrypted, String authenticationToken);
}
public interface LinphoneNotifyListener extends LinphoneCoreListener {
/**
* Notifies of an incoming NOTIFY received.
* @param lc the linphoneCore
* @param ev a LinphoneEvent representing the subscription context for which this notify belongs, or null if it is a NOTIFY out of of any subscription.
* @param eventName the event name
* @param content content of the NOTIFY request.
*/
void notifyReceived(LinphoneCore lc, LinphoneEvent ev, String eventName, LinphoneContent content);
}
/**
* Report Notified message received for this identity.
* @param lc LinphoneCore
* @param call LinphoneCall in case the notify is part of a dialog, may be null
* @param from LinphoneAddress the message comes from
* @param event String the raw body of the notify event.
*
*/
void notifyReceived(LinphoneCore lc, LinphoneCall call, LinphoneAddress from, byte[] event);
public interface LinphoneComposingListener extends LinphoneCoreListener {
/**
* invoked when a composing notification is received
* @param lc LinphoneCore
* @param room LinphoneChatRoom involved in the conversation.
*/
void isComposingReceived(LinphoneCore lc, LinphoneChatRoom cr);
}
public interface LinphoneEchoCalibrationListener extends LinphoneCoreListener {
/**
* Invoked when echo cancalation calibration is completed
* @param lc LinphoneCore
* @param status
* @param delay_ms echo delay
* @param data
*/
void ecCalibrationStatus(LinphoneCore lc, LinphoneCore.EcCalibratorStatus status, int delay_ms, Object data);
}
public interface LinphoneLogCollectionUploadListener extends LinphoneCoreListener {
/**
* Callback prototype for reporting log collection upload progress indication.
*/
void uploadProgressIndication(LinphoneCore lc, int offset, int total);
/**
* Callback prototype for reporting log collection upload state change.
* @param lc LinphoneCore object
* @param state The state of the log collection upload
* @param info Additional information: error message in case of error state, URL of uploaded file in case of success.
*/
void uploadStateChanged(LinphoneCore lc, LinphoneCore.LogCollectionUploadState state, String info);
}
/**
* Notifies progress of a call transfer.
* @param lc the LinphoneCore
* @param call the call through which the transfer was sent.
* @param new_call_state the state of the call resulting of the transfer, at the other party.
**/
void transferState(LinphoneCore lc, LinphoneCall call, LinphoneCall.State new_call_state);
/**
* Notifies an incoming INFO message.
* @param lc the LinphoneCore.
* @param info the info message
*/
void infoReceived(LinphoneCore lc, LinphoneCall call, LinphoneInfoMessage info);
/**
* Notifies of subscription requests state changes, including new incoming subscriptions.
* @param lc the LinphoneCore
* @param ev LinphoneEvent object representing the subscription context.
* @param state actual state of the subscription.
*/
void subscriptionStateChanged(LinphoneCore lc, LinphoneEvent ev, SubscriptionState state);
/**
* Notifies about outgoing generic publish states.
* @param lc the LinphoneCore
* @param ev a LinphoneEvent representing the publish, typically created by {@link LinphoneCore#publish}
* @param state the publish state
*/
void publishStateChanged(LinphoneCore lc, LinphoneEvent ev, PublishState state);
/**< @Deprecated Notifies the application that it should show up
* @return */
void show(LinphoneCore lc);
/**< @Deprecated Callback that notifies various events with human readable text.
* @return */
void displayStatus(LinphoneCore lc,String message);
/**< @Deprecated Callback to display a message to the user
* @return */
void displayMessage(LinphoneCore lc,String message);
/** @Deprecated Callback to display a warning to the user
* @return */
void displayWarning(LinphoneCore lc,String message);
/**
* Callback to be notified about the transfer progress.
* @param lc the LinphoneCore
* @param message the LinphoneChatMessage
* @param content the LinphoneContent
* @param progress percentage of the transfer done
*/
void fileTransferProgressIndication(LinphoneCore lc, LinphoneChatMessage message, LinphoneContent content, int progress);
/**
* Callback to be notified when new data has been received
* @param lc the LinphoneCore
* @param message the LinphoneChatMessage
* @param content the LinphoneContent
* @param buffer
* @param size
*/
void fileTransferRecv(LinphoneCore lc, LinphoneChatMessage message, LinphoneContent content, byte[] buffer, int size);
/**
* Callback to be notified when new data needs to be sent
* @param lc the LinphoneCore
* @param message the LinphoneChatMessage
* @param content the LinphoneContent
* @param buffer
* @param size
* @return the number of bytes written into buffer
*/
int fileTransferSend(LinphoneCore lc, LinphoneChatMessage message, LinphoneContent content, ByteBuffer buffer, int size);
/** General State notification
* @param state LinphoneCore.State
* @return
* */
void globalState(LinphoneCore lc,LinphoneCore.GlobalState state, String message);
/**
* Registration state notification
* */
void registrationState(LinphoneCore lc, LinphoneProxyConfig cfg, LinphoneCore.RegistrationState state, String smessage);
/**
* Notifies the changes about the remote provisioning step
* @param lc the LinphoneCore
* @param state the RemoteProvisioningState
* @param message the error message if state == Failed
*/
void configuringStatus(LinphoneCore lc, LinphoneCore.RemoteProvisioningState state, String message);
/**
* invoked when a new linphone chat message is received
* @param lc LinphoneCore
* @param room LinphoneChatRoom involved in this conversation. Can be be created by the framework in case the from is not present in any chat room.
* @param message incoming linphone chat message message
*/
void messageReceived(LinphoneCore lc, LinphoneChatRoom cr, LinphoneChatMessage message);
/** Call State notification
* @param state LinphoneCall.State
* @return
* */
void callState(LinphoneCore lc, LinphoneCall call, LinphoneCall.State state, String message);
/**
* Callback to display change in encryption state.
* @param encrypted true if all streams of the call are encrypted
* @param authenticationToken token like ZRTP SAS that may be displayed to user
*/
void callEncryptionChanged(LinphoneCore lc, LinphoneCall call, boolean encrypted, String authenticationToken);
/**
* Notifies of an incoming NOTIFY received.
* @param lc the linphoneCore
* @param ev a LinphoneEvent representing the subscription context for which this notify belongs, or null if it is a NOTIFY out of of any subscription.
* @param eventName the event name
* @param content content of the NOTIFY request.
*/
void notifyReceived(LinphoneCore lc, LinphoneEvent ev, String eventName, LinphoneContent content);
/**
* invoked when a composing notification is received
* @param lc LinphoneCore
* @param room LinphoneChatRoom involved in the conversation.
*/
void isComposingReceived(LinphoneCore lc, LinphoneChatRoom cr);
/**
* Invoked when echo cancalation calibration is completed
* @param lc LinphoneCore
* @param status
* @param delay_ms echo delay
* @param data
*/
void ecCalibrationStatus(LinphoneCore lc, LinphoneCore.EcCalibratorStatus status, int delay_ms, Object data);
/**
* Callback prototype for reporting log collection upload progress indication.
*/
void uploadProgressIndication(LinphoneCore lc, int offset, int total);
/**
* Callback prototype for reporting log collection upload state change.
* @param lc LinphoneCore object
* @param state The state of the log collection upload
* @param info Additional information: error message in case of error state, URL of uploaded file in case of success.
*/
void uploadStateChanged(LinphoneCore lc, LinphoneCore.LogCollectionUploadState state, String info);
}

View file

@ -0,0 +1,208 @@
package org.linphone.core;
import java.nio.ByteBuffer;
import org.linphone.core.LinphoneCall.State;
import org.linphone.core.LinphoneCore.EcCalibratorStatus;
import org.linphone.core.LinphoneCore.GlobalState;
import org.linphone.core.LinphoneCore.LogCollectionUploadState;
import org.linphone.core.LinphoneCore.RegistrationState;
import org.linphone.core.LinphoneCore.RemoteProvisioningState;
public class LinphoneCoreListenerBase implements LinphoneCoreListener {
@Override
public void authInfoRequested(LinphoneCore lc, String realm,
String username, String Domain) {
// TODO Auto-generated method stub
}
@Override
public void callStatsUpdated(LinphoneCore lc, LinphoneCall call,
LinphoneCallStats stats) {
// TODO Auto-generated method stub
}
@Override
public void newSubscriptionRequest(LinphoneCore lc, LinphoneFriend lf,
String url) {
// TODO Auto-generated method stub
}
@Override
public void notifyPresenceReceived(LinphoneCore lc, LinphoneFriend lf) {
// TODO Auto-generated method stub
}
@Override
public void textReceived(LinphoneCore lc, LinphoneChatRoom cr,
LinphoneAddress from, String message) {
// TODO Auto-generated method stub
}
@Override
public void dtmfReceived(LinphoneCore lc, LinphoneCall call, int dtmf) {
// TODO Auto-generated method stub
}
@Override
public void notifyReceived(LinphoneCore lc, LinphoneCall call,
LinphoneAddress from, byte[] event) {
// TODO Auto-generated method stub
}
@Override
public void transferState(LinphoneCore lc, LinphoneCall call,
State new_call_state) {
// TODO Auto-generated method stub
}
@Override
public void infoReceived(LinphoneCore lc, LinphoneCall call,
LinphoneInfoMessage info) {
// TODO Auto-generated method stub
}
@Override
public void subscriptionStateChanged(LinphoneCore lc, LinphoneEvent ev,
SubscriptionState state) {
// TODO Auto-generated method stub
}
@Override
public void publishStateChanged(LinphoneCore lc, LinphoneEvent ev,
PublishState state) {
// TODO Auto-generated method stub
}
@Override
public void show(LinphoneCore lc) {
// TODO Auto-generated method stub
}
@Override
public void displayStatus(LinphoneCore lc, String message) {
// TODO Auto-generated method stub
}
@Override
public void displayMessage(LinphoneCore lc, String message) {
// TODO Auto-generated method stub
}
@Override
public void displayWarning(LinphoneCore lc, String message) {
// TODO Auto-generated method stub
}
@Override
public void fileTransferProgressIndication(LinphoneCore lc,
LinphoneChatMessage message, LinphoneContent content, int progress) {
// TODO Auto-generated method stub
}
@Override
public void fileTransferRecv(LinphoneCore lc, LinphoneChatMessage message,
LinphoneContent content, byte[] buffer, int size) {
// TODO Auto-generated method stub
}
@Override
public int fileTransferSend(LinphoneCore lc, LinphoneChatMessage message,
LinphoneContent content, ByteBuffer buffer, int size) {
// TODO Auto-generated method stub
return 0;
}
@Override
public void globalState(LinphoneCore lc, GlobalState state, String message) {
// TODO Auto-generated method stub
}
@Override
public void registrationState(LinphoneCore lc, LinphoneProxyConfig cfg,
RegistrationState state, String smessage) {
// TODO Auto-generated method stub
}
@Override
public void configuringStatus(LinphoneCore lc,
RemoteProvisioningState state, String message) {
// TODO Auto-generated method stub
}
@Override
public void messageReceived(LinphoneCore lc, LinphoneChatRoom cr,
LinphoneChatMessage message) {
// TODO Auto-generated method stub
}
@Override
public void callState(LinphoneCore lc, LinphoneCall call, State state,
String message) {
// TODO Auto-generated method stub
}
@Override
public void callEncryptionChanged(LinphoneCore lc, LinphoneCall call,
boolean encrypted, String authenticationToken) {
// TODO Auto-generated method stub
}
@Override
public void notifyReceived(LinphoneCore lc, LinphoneEvent ev,
String eventName, LinphoneContent content) {
// TODO Auto-generated method stub
}
@Override
public void isComposingReceived(LinphoneCore lc, LinphoneChatRoom cr) {
// TODO Auto-generated method stub
}
@Override
public void ecCalibrationStatus(LinphoneCore lc, EcCalibratorStatus status,
int delay_ms, Object data) {
// TODO Auto-generated method stub
}
@Override
public void uploadProgressIndication(LinphoneCore lc, int offset, int total) {
// TODO Auto-generated method stub
}
@Override
public void uploadStateChanged(LinphoneCore lc,
LogCollectionUploadState state, String info) {
// TODO Auto-generated method stub
}
}

View file

@ -88,7 +88,9 @@ public class LinphoneCoreFactoryImpl extends LinphoneCoreFactory {
MediastreamerAndroidContext.setContext(context);
File user = userConfig == null ? null : new File(userConfig);
File factory = factoryConfig == null ? null : new File(factoryConfig);
return new LinphoneCoreImpl(listener, user, factory, userdata);
LinphoneCore lc = new LinphoneCoreImpl(listener, user, factory, userdata);
if(context!=null) lc.setContext(context);
return lc;
} catch (IOException e) {
throw new LinphoneCoreException("Cannot create LinphoneCore",e);
}

View file

@ -24,13 +24,17 @@ import java.io.File;
import java.io.IOException;
import org.linphone.core.LinphoneCall.State;
import org.linphone.core.LinphoneCoreListener.LinphoneEchoCalibrationListener;
import org.linphone.core.LinphoneCoreListener;
import org.linphone.mediastream.Log;
import org.linphone.mediastream.Version;
import org.linphone.mediastream.video.AndroidVideoWindowImpl;
import org.linphone.mediastream.video.capture.hwconf.Hacks;
import android.content.Context;
import android.media.AudioManager;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiManager.MulticastLock;
import android.net.wifi.WifiManager.WifiLock;
public class LinphoneCoreImpl implements LinphoneCore {
@ -110,6 +114,7 @@ public class LinphoneCoreImpl implements LinphoneCore {
private native void setRing(long nativePtr, String path);
private native String getRing(long nativePtr);
private native void setRootCA(long nativePtr, String path);
private native void setRingback(long nativePtr, String path);
private native long[] listVideoPayloadTypes(long nativePtr);
private native LinphoneProxyConfig[] getProxyConfigList(long nativePtr);
private native long[] getAuthInfosList(long nativePtr);
@ -156,6 +161,8 @@ public class LinphoneCoreImpl implements LinphoneCore {
private native boolean isSdp200AckEnabled(long nativePtr);
private native void stopRinging(long nativePtr);
private native static void setAndroidPowerManager(Object pm);
private native void setAndroidWifiLock(long nativePtr,Object wifi_lock);
private native void setAndroidMulticastLock(long nativePtr,Object multicast_lock);
LinphoneCoreImpl(LinphoneCoreListener listener, File userConfig, File factoryConfig, Object userdata) throws IOException {
mListener = listener;
@ -183,6 +190,18 @@ public class LinphoneCoreImpl implements LinphoneCore {
mContext = (Context)context;
mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
setAndroidPowerManager(mContext.getSystemService(Context.POWER_SERVICE));
if (Version.sdkAboveOrEqual(Version.API12_HONEYCOMB_MR1_31X)) {
WifiManager wifiManager=(WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
WifiLock lock = wifiManager.createWifiLock(WifiManager.WIFI_MODE_FULL_HIGH_PERF, "linphonecore ["+ nativePtr+"] wifi-lock");
lock.setReferenceCounted(true);
setAndroidWifiLock(nativePtr,lock);
}
if (Version.sdkAboveOrEqual(Version.API14_ICE_CREAM_SANDWICH_40)) {
WifiManager wifiManager=(WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
MulticastLock lock = wifiManager.createMulticastLock("linphonecore ["+ nativePtr+"] multicast-lock");
lock.setReferenceCounted(true);
setAndroidMulticastLock(nativePtr,lock);
}
}
public synchronized void addAuthInfo(LinphoneAuthInfo info) {
@ -519,6 +538,10 @@ public class LinphoneCoreImpl implements LinphoneCore {
setRootCA(nativePtr, path);
}
public synchronized void setRingback(String path) {
setRingback(nativePtr, path);
}
public synchronized LinphoneProxyConfig[] getProxyConfigList() {
return getProxyConfigList(nativePtr);
}
@ -558,7 +581,7 @@ public class LinphoneCoreImpl implements LinphoneCore {
public synchronized boolean isKeepAliveEnabled() {
return isKeepAliveEnabled(nativePtr);
}
public synchronized void startEchoCalibration(LinphoneEchoCalibrationListener listener) throws LinphoneCoreException {
public synchronized void startEchoCalibration(LinphoneCoreListener listener) throws LinphoneCoreException {
startEchoCalibration(nativePtr, listener);
}
@ -1330,4 +1353,83 @@ public class LinphoneCoreImpl implements LinphoneCore {
* @param path The path where the log files will be written.
*/
public native static void setLogCollectionPath(String path);
private native void setPreferredFramerate(long nativePtr, float fps);
@Override
public void setPreferredFramerate(float fps) {
setPreferredFramerate(nativePtr,fps);
}
private native float getPreferredFramerate(long nativePtr);
@Override
public float getPreferredFramerate() {
return getPreferredFramerate(nativePtr);
}
private native int setAudioMulticastAddr(long nativePtr, String ip);
@Override
public void setAudioMulticastAddr(String ip) throws LinphoneCoreException {
if (setAudioMulticastAddr(nativePtr, ip)!=0)
throw new LinphoneCoreException("bad ip address ["+ip+"]");
}
private native int setVideoMulticastAddr(long nativePtr, String ip);
@Override
public void setVideoMulticastAddr(String ip) throws LinphoneCoreException {
if (setVideoMulticastAddr(nativePtr, ip)!=0)
throw new LinphoneCoreException("bad ip address ["+ip+"]");
}
private native String getAudioMulticastAddr(long ptr);
@Override
public String getAudioMulticastAddr() {
return getAudioMulticastAddr() ;
}
private native String getVideoMulticastAddr(long ptr);
@Override
public String getVideoMulticastAddr() {
return getVideoMulticastAddr();
}
private native int setAudioMulticastTtl(long ptr,int ttl);
@Override
public void setAudioMulticastTtl(int ttl) throws LinphoneCoreException {
if (setAudioMulticastTtl(nativePtr, ttl)!=0)
throw new LinphoneCoreException("bad ttl value ["+ttl+"]");
}
private native int setVideoMulticastTtl(long ptr,int ttl);
@Override
public void setVideoMulticastTtl(int ttl) throws LinphoneCoreException {
if (setVideoMulticastTtl(nativePtr, ttl)!=0)
throw new LinphoneCoreException("bad ttl value ["+ttl+"]");
}
private native int getAudioMulticastTtl(long ptr);
@Override
public int getAudioMulticastTtl() {
return getAudioMulticastTtl(nativePtr);
}
private native int getVideoMulticastTtl(long ptr);
@Override
public int getVideoMulticastTtl() {
return getVideoMulticastTtl(nativePtr);
}
private native void enableAudioMulticast(long ptr,boolean yesno);
@Override
public void enableAudioMulticast(boolean yesno) {
enableAudioMulticast(nativePtr,yesno);
}
private native boolean audioMulticastEnabled(long ptr);
@Override
public boolean audioMulticastEnabled() {
return audioMulticastEnabled(nativePtr);
}
private native void enableVideoMulticast(long ptr,boolean yesno);
@Override
public void enableVideoMulticast(boolean yesno) {
enableVideoMulticast(nativePtr,yesno);
}
private native boolean videoMulticastEnabled(long ptr);
@Override
public boolean videoMulticastEnabled() {
return videoMulticastEnabled(nativePtr);
}
}

View file

@ -2,9 +2,9 @@
./bin/libspeex-1.dll
./bin/libspeexdsp-1.dll
./bin/avutil-51.dll
./bin/libpolarssl-0.dll
./bin/libbellesip-0.dll
./bin/libantlr3c.dll
./lib/libpolarssl.dll
./bin/libogg-0.dll
./bin/libtheora-0.dll
./bin/libxml2-2.dll

@ -1 +1 @@
Subproject commit 7d2a30214b8010224eed26bc1f239907618b9674
Subproject commit 034131e3b566438df8445ca7f97c19f3c3774f28

2
oRTP

@ -1 +1 @@
Subproject commit e5470e271d5be74f425db9221cd35a60ce4cf52e
Subproject commit 327cec466a5d39e716664325ae6d604e228b3fed

View file

@ -20,6 +20,8 @@
#
############################################################################
find_package(GTK2 2.18 COMPONENTS gtk)
set(SOURCE_FILES
accountmanager.c
call_tester.c
@ -29,6 +31,7 @@ set(SOURCE_FILES
liblinphone_tester.c
log_collection_tester.c
message_tester.c
offeranswer_tester.c
player_tester.c
presence_tester.c
quality_reporting_tester.c
@ -39,8 +42,14 @@ set(SOURCE_FILES
tester.c
transport_tester.c
upnp_tester.c
video_tester.c
)
add_executable(liblinphone_tester ${SOURCE_FILES})
target_include_directories(liblinphone_tester PUBLIC ${CUNIT_INCLUDE_DIRS})
target_link_libraries(liblinphone_tester linphone ${CUNIT_LIBRARIES})
if (GTK2_FOUND)
target_compile_definitions(liblinphone_tester PRIVATE HAVE_GTK)
target_include_directories(liblinphone_tester PUBLIC ${GTK2_INCLUDE_DIRS})
target_link_libraries(liblinphone_tester linphone ${GTK2_LIBRARIES})
endif()

View file

@ -15,6 +15,7 @@ liblinphonetester_la_SOURCES = tester.c \
register_tester.c \
message_tester.c \
call_tester.c \
multicast_call_tester.c \
presence_tester.c \
upnp_tester.c \
eventapi_tester.c \
@ -27,7 +28,8 @@ liblinphonetester_la_SOURCES = tester.c \
player_tester.c \
dtmf_tester.c \
accountmanager.c \
offeranswer_tester.c
offeranswer_tester.c \
video_tester.c
liblinphonetester_la_LDFLAGS= -no-undefined
liblinphonetester_la_LIBADD= ../coreapi/liblinphone.la $(CUNIT_LIBS)
@ -35,6 +37,13 @@ liblinphonetester_la_LIBADD= ../coreapi/liblinphone.la $(CUNIT_LIBS)
AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/coreapi
AM_CFLAGS = $(STRICT_OPTIONS) $(STRICT_OPTIONS_CC) -DIN_LINPHONE $(ORTP_CFLAGS) $(MEDIASTREAMER_CFLAGS) $(CUNIT_CFLAGS) $(BELLESIP_CFLAGS) $(LIBXML2_CFLAGS) $(SQLITE3_CFLAGS)
if BUILD_GTK_UI
liblinphonetester_la_LIBADD += $(LIBGTK_LIBS) $(LIBGTKMAC_LIBS)
AM_CFLAGS += $(LIBGTK_CFLAGS) $(LIBGTKMAC_CFLAGS) -DHAVE_GTK
endif
if !BUILD_IOS
noinst_PROGRAMS = liblinphone_tester

View file

@ -130,6 +130,7 @@ void account_create_on_server(Account *account, const LinphoneProxyConfig *refcf
linphone_core_set_sip_transports(lc,&tr);
cfg=linphone_core_create_proxy_config(lc);
linphone_address_set_secure(tmp_identity, FALSE);
linphone_address_set_password(tmp_identity,account->password);
linphone_address_set_header(tmp_identity,"X-Create-Account","yes");
tmp=linphone_address_as_string(tmp_identity);
@ -138,7 +139,8 @@ void account_create_on_server(Account *account, const LinphoneProxyConfig *refcf
linphone_address_unref(tmp_identity);
server_addr=linphone_address_new(linphone_proxy_config_get_server_addr(refcfg));
linphone_address_set_transport(server_addr,LinphoneTransportTcp); /*use tcp for account creation*/
linphone_address_set_secure(server_addr, FALSE);
linphone_address_set_transport(server_addr,LinphoneTransportTcp); /*use tcp for account creation, we may not have certificates configured at this stage*/
linphone_address_set_port(server_addr,0);
tmp=linphone_address_as_string(server_addr);
linphone_proxy_config_set_server_addr(cfg,tmp);
@ -152,8 +154,11 @@ void account_create_on_server(Account *account, const LinphoneProxyConfig *refcf
ms_fatal("Account for %s could not be created on server.", linphone_proxy_config_get_identity(refcfg));
}
linphone_proxy_config_edit(cfg);
tmp=linphone_address_as_string(account->modified_identity);
tmp_identity=linphone_address_clone(account->modified_identity);
linphone_address_set_secure(tmp_identity, FALSE);
tmp=linphone_address_as_string(tmp_identity);
linphone_proxy_config_set_identity(cfg,tmp); /*remove the X-Create-Account header*/
linphone_address_unref(tmp_identity);
ms_free(tmp);
linphone_proxy_config_done(cfg);

View file

@ -25,7 +25,7 @@
#include "lpconfig.h"
#include "private.h"
#include "liblinphone_tester.h"
#include "mediastreamer2/dsptools.h"
#include "mediastreamer2/msutils.h"
#include "belle-sip/sipstack.h"
#ifdef WIN32
@ -33,7 +33,6 @@
#endif
static void srtp_call(void);
static void call_base(LinphoneMediaEncryption mode, bool_t enable_video,bool_t enable_relay,LinphoneFirewallPolicy policy);
static char *create_filepath(const char *dir, const char *filename, const char *ext);
// prototype definition for call_recording()
@ -105,6 +104,7 @@ void linphone_call_encryption_changed(LinphoneCore *lc, LinphoneCall *call, bool
else
counters->number_of_LinphoneCallEncryptedOff++;
}
void linphone_transfer_state_changed(LinphoneCore *lc, LinphoneCall *transfered, LinphoneCallState new_call_state) {
char* to=linphone_address_as_string(linphone_call_get_call_log(transfered)->to);
char* from=linphone_address_as_string(linphone_call_get_call_log(transfered)->from);
@ -127,8 +127,8 @@ void linphone_transfer_state_changed(LinphoneCore *lc, LinphoneCall *transfered,
}
}
#ifdef VIDEO_ENABLED
static void linphone_call_cb(LinphoneCall *call,void * user_data) {
void linphone_call_cb(LinphoneCall *call,void * user_data) {
char* to=linphone_address_as_string(linphone_call_get_call_log(call)->to);
char* from=linphone_address_as_string(linphone_call_get_call_log(call)->from);
stats* counters;
@ -139,7 +139,6 @@ static void linphone_call_cb(LinphoneCall *call,void * user_data) {
counters = (stats*)get_stats(lc);
counters->number_of_IframeDecoded++;
}
#endif
void liblinphone_tester_check_rtcp(LinphoneCoreManager* caller, LinphoneCoreManager* callee) {
LinphoneCall *c1,*c2;
@ -266,10 +265,10 @@ bool_t call_with_params2(LinphoneCoreManager* caller_mgr
if (linphone_core_get_media_encryption(caller_mgr->lc) != LinphoneMediaEncryptionNone
&& linphone_core_get_media_encryption(callee_mgr->lc) != LinphoneMediaEncryptionNone) {
/*wait for encryption to be on, in case of zrtp, it can take a few seconds*/
if (linphone_core_get_media_encryption(caller_mgr->lc) == LinphoneMediaEncryptionZRTP)
/*wait for encryption to be on, in case of zrtp or dtls, it can take a few seconds*/
if ((linphone_core_get_media_encryption(caller_mgr->lc) == LinphoneMediaEncryptionZRTP) || (linphone_core_get_media_encryption(caller_mgr->lc) == LinphoneMediaEncryptionDTLS))
wait_for(callee_mgr->lc,caller_mgr->lc,&caller_mgr->stat.number_of_LinphoneCallEncryptedOn,initial_caller.number_of_LinphoneCallEncryptedOn+1);
if (linphone_core_get_media_encryption(callee_mgr->lc) == LinphoneMediaEncryptionZRTP)
if ((linphone_core_get_media_encryption(callee_mgr->lc) == LinphoneMediaEncryptionZRTP) || (linphone_core_get_media_encryption(callee_mgr->lc) == LinphoneMediaEncryptionDTLS))
wait_for(callee_mgr->lc,caller_mgr->lc,&callee_mgr->stat.number_of_LinphoneCallEncryptedOn,initial_callee.number_of_LinphoneCallEncryptedOn+1);
{
const LinphoneCallParams* call_param = linphone_call_get_current_params(linphone_core_get_current_call(callee_mgr->lc));
@ -314,7 +313,7 @@ void end_call(LinphoneCoreManager *m1, LinphoneCoreManager *m2){
CU_ASSERT_TRUE(wait_for(m1->lc,m2->lc,&m2->stat.number_of_LinphoneCallReleased,1));
}
static void simple_call(void) {
void simple_call_base(bool_t enable_multicast_recv_side) {
int begin;
int leaked_objects;
LinphoneCoreManager* marie;
@ -347,6 +346,8 @@ static void simple_call(void) {
linphone_address_unref(marie_addr);
}
linphone_core_enable_audio_multicast(pauline->lc,enable_multicast_recv_side);
CU_ASSERT_TRUE(call(marie,pauline));
pauline_call=linphone_core_get_current_call(pauline->lc);
CU_ASSERT_PTR_NOT_NULL(pauline_call);
@ -375,7 +376,9 @@ static void simple_call(void) {
belle_sip_object_dump_active_objects();
}
}
static void simple_call() {
simple_call_base(FALSE);
}
static void call_with_timeouted_bye(void) {
int begin;
int leaked_objects;
@ -740,7 +743,7 @@ void disable_all_audio_codecs_except_one(LinphoneCore *lc, const char *mime, int
}
#ifdef VIDEO_ENABLED
static void disable_all_video_codecs_except_one(LinphoneCore *lc, const char *mime) {
void disable_all_video_codecs_except_one(LinphoneCore *lc, const char *mime) {
const MSList *codecs = linphone_core_get_video_codecs(lc);
const MSList *it = NULL;
PayloadType *pt = NULL;
@ -1131,12 +1134,14 @@ static void call_with_custom_headers(void) {
linphone_core_manager_destroy(pauline);
}
static void call_paused_resumed(void) {
void call_paused_resumed_base(bool_t multicast) {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc");
LinphoneCall* call_pauline;
const rtp_stats_t * stats;
linphone_core_enable_audio_multicast(pauline->lc,multicast);
CU_ASSERT_TRUE(call(pauline,marie));
call_pauline = linphone_core_get_current_call(pauline->lc);
@ -1170,7 +1175,9 @@ static void call_paused_resumed(void) {
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
}
static void call_paused_resumed(void) {
call_paused_resumed_base(FALSE);
}
#define CHECK_CURRENT_LOSS_RATE() \
rtcp_count_current = pauline->stat.number_of_rtcp_sent; \
/*wait for an RTCP packet to have an accurate cumulative lost value*/ \
@ -2045,14 +2052,18 @@ static void simple_conference_with_ice(void) {
}
static void srtp_call() {
call_base(LinphoneMediaEncryptionSRTP,FALSE,FALSE,LinphonePolicyNoFirewall);
call_base(LinphoneMediaEncryptionSRTP,FALSE,FALSE,LinphonePolicyNoFirewall,FALSE);
}
static void zrtp_call() {
call_base(LinphoneMediaEncryptionZRTP,FALSE,FALSE,LinphonePolicyNoFirewall);
call_base(LinphoneMediaEncryptionZRTP,FALSE,FALSE,LinphonePolicyNoFirewall,FALSE);
}
static void zrtp_video_call() {
call_base(LinphoneMediaEncryptionZRTP,TRUE,FALSE,LinphonePolicyNoFirewall);
call_base(LinphoneMediaEncryptionZRTP,TRUE,FALSE,LinphonePolicyNoFirewall,FALSE);
}
static void dtls_srtp_call() {
call_base(LinphoneMediaEncryptionDTLS,FALSE,FALSE,LinphonePolicyNoFirewall,FALSE);
}
static void call_with_declined_srtp(void) {
@ -2209,17 +2220,38 @@ end:
}
static void call_base(LinphoneMediaEncryption mode, bool_t enable_video,bool_t enable_relay,LinphoneFirewallPolicy policy) {
void call_base(LinphoneMediaEncryption mode, bool_t enable_video,bool_t enable_relay,LinphoneFirewallPolicy policy,bool_t enable_tunnel) {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc");
if (enable_relay) {
linphone_core_set_user_agent(marie->lc,"Natted Linphone",NULL);
linphone_core_set_user_agent(pauline->lc,"Natted Linphone",NULL);
}
if (enable_tunnel) {
int i;
LinphoneTunnelConfig * tunnel_config = linphone_tunnel_config_new();
linphone_tunnel_config_set_host(tunnel_config,"tunnel.linphone.org");
linphone_tunnel_config_set_port(tunnel_config,443);
linphone_tunnel_add_server(linphone_core_get_tunnel(marie->lc),tunnel_config);
linphone_tunnel_enable_sip(linphone_core_get_tunnel(marie->lc),FALSE);
linphone_tunnel_set_mode(linphone_core_get_tunnel(marie->lc),LinphoneTunnelModeEnable);
for (i=0;i<10;i++) {
if (linphone_tunnel_connected(linphone_core_get_tunnel(marie->lc))) {
break;
}
linphone_core_iterate(marie->lc);
ms_usleep(200000);
}
CU_ASSERT_TRUE(linphone_tunnel_connected(linphone_core_get_tunnel(marie->lc)));
}
if (linphone_core_media_encryption_supported(marie->lc,mode)) {
linphone_core_set_media_encryption(marie->lc,mode);
linphone_core_set_media_encryption(pauline->lc,mode);
if (mode==LinphoneMediaEncryptionDTLS) { /* for DTLS we must access certificates or at least have a directory to store them */
marie->lc->user_certificates_path = ms_strdup_printf("%s/certificates/marie", liblinphone_tester_file_prefix);
pauline->lc->user_certificates_path = ms_strdup_printf("%s/certificates/pauline", liblinphone_tester_file_prefix);
}
linphone_core_set_firewall_policy(marie->lc,policy);
linphone_core_set_stun_server(marie->lc,"stun.linphone.org");
@ -2250,7 +2282,7 @@ static void call_base(LinphoneMediaEncryption mode, bool_t enable_video,bool_t e
}
if (policy == LinphonePolicyUseIce)
CU_ASSERT_TRUE(check_ice(pauline,marie,LinphoneIceStateHostConnection));
CU_ASSERT_TRUE(check_ice(pauline,marie,enable_tunnel?LinphoneIceStateReflexiveConnection:LinphoneIceStateHostConnection));
#ifdef VIDEO_ENABLED
if (enable_video) {
int i=0;
@ -2263,7 +2295,7 @@ static void call_base(LinphoneMediaEncryption mode, bool_t enable_video,bool_t e
add_video(pauline,marie);
if (policy == LinphonePolicyUseIce)
CU_ASSERT_TRUE(check_ice(pauline,marie,LinphoneIceStateHostConnection));
CU_ASSERT_TRUE(check_ice(pauline,marie,enable_tunnel?LinphoneIceStateReflexiveConnection:LinphoneIceStateHostConnection));
liblinphone_tester_check_rtcp(marie,pauline);
/*wait for ice to found the direct path*/
@ -2286,25 +2318,24 @@ static void call_base(LinphoneMediaEncryption mode, bool_t enable_video,bool_t e
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
}
#ifdef VIDEO_ENABLED
static void srtp_video_ice_call(void) {
call_base(LinphoneMediaEncryptionSRTP,TRUE,FALSE,LinphonePolicyUseIce);
call_base(LinphoneMediaEncryptionSRTP,TRUE,FALSE,LinphonePolicyUseIce,FALSE);
}
static void zrtp_video_ice_call(void) {
call_base(LinphoneMediaEncryptionZRTP,TRUE,FALSE,LinphonePolicyUseIce);
call_base(LinphoneMediaEncryptionZRTP,TRUE,FALSE,LinphonePolicyUseIce,FALSE);
}
#endif
static void srtp_ice_call(void) {
call_base(LinphoneMediaEncryptionSRTP,FALSE,FALSE,LinphonePolicyUseIce);
call_base(LinphoneMediaEncryptionSRTP,FALSE,FALSE,LinphonePolicyUseIce,FALSE);
}
static void zrtp_ice_call(void) {
call_base(LinphoneMediaEncryptionZRTP,FALSE,FALSE,LinphonePolicyUseIce);
call_base(LinphoneMediaEncryptionZRTP,FALSE,FALSE,LinphonePolicyUseIce,FALSE);
}
static void zrtp_ice_call_with_relay(void) {
call_base(LinphoneMediaEncryptionZRTP,FALSE,TRUE,LinphonePolicyUseIce);
call_base(LinphoneMediaEncryptionZRTP,FALSE,TRUE,LinphonePolicyUseIce,FALSE);
}
static void early_media_call(void) {
@ -3381,6 +3412,118 @@ static void outgoing_reinvite_without_ack_sdp() {
#endif
}
static void call_with_paused_no_sdp_on_resume() {
int begin;
int leaked_objects;
int dummy=0;
LinphoneCoreManager* marie;
LinphoneCoreManager* pauline;
LinphoneCall* call_marie = NULL;
belle_sip_object_enable_leak_detector(TRUE);
begin=belle_sip_object_get_object_count();
marie = linphone_core_manager_new( "marie_rc");
pauline = linphone_core_manager_new( "pauline_rc");
CU_ASSERT_TRUE(call(pauline,marie));
liblinphone_tester_check_rtcp(marie,pauline);
call_marie = linphone_core_get_current_call(marie->lc);
CU_ASSERT_PTR_NOT_NULL(call_marie);
ms_message("== Call is OK ==");
/* the called party pause the call */
wait_for_until(pauline->lc, marie->lc, NULL, 5, 3000);
linphone_core_pause_call(marie->lc,call_marie);
ms_message("== Call pausing ==");
CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallPausing,1));
CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallPausedByRemote,1));
CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallPaused,1));
/*stay in pause a little while in order to generate traffic*/
wait_for_until(pauline->lc, marie->lc, NULL, 5, 2000);
ms_message("== Call paused, marie call: %p ==", call_marie);
linphone_core_enable_sdp_200_ack(marie->lc,TRUE);
linphone_core_resume_call(marie->lc,call_marie);
CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,2));
CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2));
wait_for_until(marie->lc, pauline->lc, &dummy, 1, 3000);
CU_ASSERT_TRUE(linphone_call_get_audio_stats(call_marie)->download_bandwidth>70);
CU_ASSERT_TRUE(linphone_call_get_audio_stats(linphone_core_get_current_call(pauline->lc))->download_bandwidth>70);
end_call(marie,pauline);
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
leaked_objects=belle_sip_object_get_object_count()-begin;
CU_ASSERT_TRUE(leaked_objects==0);
if (leaked_objects>0){
belle_sip_object_dump_active_objects();
}
}
static void call_with_generic_cn(void) {
int begin;
int leaked_objects;
LinphoneCoreManager* marie;
LinphoneCoreManager* pauline;
LinphoneCall *pauline_call;
char *audio_file_with_silence=ms_strdup_printf("%s/%s",liblinphone_tester_file_prefix,"sounds/ahbahouaismaisbon.wav");
char *recorded_file=ms_strdup_printf("%s/%s",liblinphone_tester_writable_dir_prefix,"result.wav");
belle_sip_object_enable_leak_detector(TRUE);
begin=belle_sip_object_get_object_count();
marie = linphone_core_manager_new( "marie_rc");
pauline = linphone_core_manager_new( "pauline_rc");
remove(recorded_file);
linphone_core_use_files(marie->lc,TRUE);
linphone_core_use_files(pauline->lc,TRUE);
linphone_core_set_play_file(marie->lc, audio_file_with_silence);
/*linphone_core_set_play_file(pauline->lc, NULL);*/
linphone_core_set_record_file(pauline->lc, recorded_file);
linphone_core_enable_generic_confort_noise(marie->lc, TRUE);
linphone_core_enable_generic_confort_noise(pauline->lc, TRUE);
CU_ASSERT_TRUE(call(marie,pauline));
pauline_call=linphone_core_get_current_call(pauline->lc);
CU_ASSERT_PTR_NOT_NULL(pauline_call);
if (pauline_call){
const rtp_stats_t *rtps;
struct stat stbuf;
int err;
wait_for_until(marie->lc, pauline->lc, NULL, 0, 8000);
rtps=rtp_session_get_stats(pauline_call->audiostream->ms.sessions.rtp_session);
CU_ASSERT_TRUE(rtps->packet_recv<=300 && rtps->packet_recv>=200);
CU_ASSERT_EQUAL((err=stat(recorded_file,&stbuf)), 0);
if (err==0){
CU_ASSERT_TRUE(stbuf.st_size>120000);
}
}
end_call(marie,pauline);
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
leaked_objects=belle_sip_object_get_object_count()-begin;
CU_ASSERT_TRUE(leaked_objects==0);
if (leaked_objects>0){
belle_sip_object_dump_active_objects();
}
ms_free(audio_file_with_silence);
ms_free(recorded_file);
}
test_t call_tests[] = {
{ "Early declined call", early_declined_call },
{ "Call declined", call_declined },
@ -3412,6 +3555,7 @@ test_t call_tests[] = {
{ "Call paused resumed from callee", call_paused_resumed_from_callee },
{ "SRTP call", srtp_call },
{ "ZRTP call",zrtp_call},
{ "DTLS SRTP call",dtls_srtp_call},
{ "ZRTP video call",zrtp_video_call},
{ "SRTP call with declined srtp", call_with_declined_srtp },
{ "Call with file player", call_with_file_player},
@ -3467,12 +3611,14 @@ test_t call_tests[] = {
{ "Call with in-dialog UPDATE request", call_with_in_dialog_update },
{ "Call with in-dialog codec change", call_with_in_dialog_codec_change },
{ "Call with in-dialog codec change no sdp", call_with_in_dialog_codec_change_no_sdp },
{ "Call with pause no SDP on resume", call_with_paused_no_sdp_on_resume },
{ "Call with custom supported tags", call_with_custom_supported_tags },
{ "Call log from taken from asserted id",call_log_from_taken_from_p_asserted_id},
{ "Incoming INVITE without SDP",incoming_invite_without_sdp},
{ "Outgoing INVITE without ACK SDP",outgoing_invite_without_sdp},
{ "Incoming REINVITE without SDP",incoming_reinvite_without_ack_sdp},
{ "Outgoing REINVITE without ACK SDP",outgoing_reinvite_without_ack_sdp},
{ "Call with generic CN", call_with_generic_cn }
};
test_suite_t call_test_suite = {

View file

@ -583,6 +583,116 @@ static void early_media_call_forking(void) {
linphone_core_manager_destroy(pauline);
}
static void call_with_sips(void){
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_sips_rc");
LinphoneCoreManager* pauline1 = linphone_core_manager_new( "pauline_sips_rc");
LinphoneCoreManager* pauline2 = linphone_core_manager_new( "pauline_tcp_rc");
MSList* lcs=ms_list_append(NULL,marie->lc);
lcs=ms_list_append(lcs,pauline1->lc);
lcs=ms_list_append(lcs,pauline2->lc);
linphone_core_set_user_agent(marie->lc,"Natted Linphone",NULL);
linphone_core_set_user_agent(pauline1->lc,"Natted Linphone",NULL);
linphone_core_set_user_agent(pauline2->lc,"Natted Linphone",NULL);
linphone_core_invite_address(marie->lc,pauline1->identity);
/*marie should hear ringback*/
CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallOutgoingRinging,1,3000));
/*Only the sips registered device from pauline should ring*/
CU_ASSERT_TRUE(wait_for_list(lcs,&pauline1->stat.number_of_LinphoneCallIncomingReceived,1,1000));
/*pauline accepts the call */
linphone_core_accept_call(pauline1->lc,linphone_core_get_current_call(pauline1->lc));
CU_ASSERT_TRUE(wait_for_list(lcs,&pauline1->stat.number_of_LinphoneCallConnected,1,1000));
CU_ASSERT_TRUE(wait_for_list(lcs,&pauline1->stat.number_of_LinphoneCallStreamsRunning,1,1000));
CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallConnected,1,1000));
CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallStreamsRunning,1,1000));
/*pauline2 should not have ring*/
CU_ASSERT_TRUE(pauline2->stat.number_of_LinphoneCallIncomingReceived==0);
linphone_core_terminate_call(pauline1->lc,linphone_core_get_current_call(pauline1->lc));
CU_ASSERT_TRUE(wait_for_list(lcs,&pauline1->stat.number_of_LinphoneCallEnd,1,3000));
CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,1,3000));
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline1);
linphone_core_manager_destroy(pauline2);
ms_list_free(lcs);
}
static void call_with_sips_not_achievable(void){
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_sips_rc");
LinphoneCoreManager* pauline1 = linphone_core_manager_new( "pauline_rc");
LinphoneCoreManager* pauline2 = linphone_core_manager_new( "pauline_tcp_rc");
MSList* lcs=ms_list_append(NULL,marie->lc);
LinphoneAddress *dest;
LinphoneCall *call;
const LinphoneErrorInfo *ei;
lcs=ms_list_append(lcs,pauline1->lc);
lcs=ms_list_append(lcs,pauline2->lc);
dest=linphone_address_clone(pauline1->identity);
linphone_address_set_secure(dest,TRUE);
call=linphone_core_invite_address(marie->lc,dest);
linphone_call_ref(call);
linphone_address_unref(dest);
/*Call should be rejected by server with 480*/
CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallError,1,3000));
ei=linphone_call_get_error_info(call);
CU_ASSERT_PTR_NOT_NULL(ei);
if (ei){
CU_ASSERT_EQUAL(linphone_error_info_get_reason(ei), LinphoneReasonTemporarilyUnavailable);
}
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline1);
linphone_core_manager_destroy(pauline2);
ms_list_free(lcs);
}
static void call_with_ipv6(void) {
int begin;
int leaked_objects;
LinphoneCoreManager* marie;
LinphoneCoreManager* pauline;
LinphoneCall *pauline_call;
if (!liblinphone_tester_ipv6_available()){
ms_warning("Call with ipv6 not tested, no ipv6 connectivity");
return;
}
belle_sip_object_enable_leak_detector(TRUE);
begin=belle_sip_object_get_object_count();
liblinphone_tester_enable_ipv6(TRUE);
marie = linphone_core_manager_new( "marie_rc");
pauline = linphone_core_manager_new( "pauline_rc");
linphone_core_set_user_agent(marie->lc,"Natted Linphone",NULL);
linphone_core_set_user_agent(pauline->lc,"Natted Linphone",NULL);
CU_ASSERT_TRUE(call(marie,pauline));
pauline_call=linphone_core_get_current_call(pauline->lc);
CU_ASSERT_PTR_NOT_NULL(pauline_call);
liblinphone_tester_check_rtcp(marie,pauline);
end_call(marie,pauline);
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
liblinphone_tester_enable_ipv6(FALSE);
leaked_objects=belle_sip_object_get_object_count()-begin;
CU_ASSERT_TRUE(leaked_objects==0);
if (leaked_objects>0){
belle_sip_object_dump_active_objects();
}
}
test_t flexisip_tests[] = {
{ "Subscribe forking", subscribe_forking },
@ -598,6 +708,9 @@ test_t flexisip_tests[] = {
{ "Call forking with push notification (multiple)", call_forking_with_push_notification_multiple },
{ "Call forking not responded", call_forking_not_responded },
{ "Early-media call forking", early_media_call_forking },
{ "Call with sips", call_with_sips },
{ "Call with sips not achievable", call_with_sips_not_achievable },
{ "Call with ipv6", call_with_ipv6 }
};

View file

@ -24,6 +24,9 @@
#if HAVE_CU_CURSES
#include "CUnit/CUCurses.h"
#endif
#ifdef HAVE_GTK
#include <gtk/gtk.h>
#endif
extern int liblinphone_tester_use_log_file;
@ -143,7 +146,7 @@ void helper(const char *name) {
#if HAVE_CU_CURSES
"\t\t\t--curses\n"
#endif
"\t\t\t--xml\n"
"\t\t\t--xml\n"
"\t\t\t--xml-file <xml file prefix (will be suffixed by '-Results.xml')>\n"
, name);
}
@ -163,9 +166,16 @@ int main (int argc, char *argv[])
int ret;
const char *suite_name=NULL;
const char *test_name=NULL;
const char *xml_file=NULL;
const char *xml_file="CUnitAutomated-Results.xml";
char *xml_tmp_file=NULL;
int xml = 0;
FILE* log_file=NULL;
#ifdef HAVE_GTK
gdk_threads_init();
gtk_init(&argc, &argv);
#endif
#if defined(ANDROID)
linphone_core_set_log_handler(linphone_android_ortp_log_handler);
#elif defined(__QNX__)
@ -213,6 +223,7 @@ int main (int argc, char *argv[])
} else if (strcmp(argv[i], "--xml-file") == 0){
CHECK_ARG("--xml-file", ++i, argc);
xml_file = argv[i];
xml = 1;
} else if (strcmp(argv[i], "--xml") == 0){
xml = 1;
} else if (strcmp(argv[i],"--log-file")==0){
@ -238,14 +249,21 @@ int main (int argc, char *argv[])
return -1;
}
if( xml_file != NULL ){
liblinphone_tester_set_xml_output(xml_file);
if( xml ){
xml_tmp_file = ms_strdup_printf("%s.tmp", xml_file);
liblinphone_tester_set_xml_output(xml_tmp_file);
}
liblinphone_tester_enable_xml(xml);
ret = liblinphone_tester_run_tests(suite_name, test_name);
liblinphone_tester_uninit();
if ( xml ) {
/*create real xml file only if tester did not crash*/
ms_strcat_printf(xml_tmp_file, "-Results.xml");
rename(xml_tmp_file, xml_file);
ms_free(xml_tmp_file);
}
return ret;
}
#endif /* WINAPI_FAMILY_PHONE_APP */

View file

@ -24,6 +24,9 @@
#include "CUnit/Basic.h"
#include "linphonecore.h"
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
typedef void (*test_function_t)(void);
typedef int (*test_suite_function_t)(const char *name);
@ -63,6 +66,8 @@ extern test_suite_t transport_test_suite;
extern test_suite_t player_test_suite;
extern test_suite_t dtmf_test_suite;
extern test_suite_t offeranswer_test_suite;
extern test_suite_t video_test_suite;
extern test_suite_t multicast_call_test_suite;
extern int liblinphone_tester_nb_test_suites(void);
@ -295,6 +300,7 @@ bool_t call_with_test_params(LinphoneCoreManager* caller_mgr
bool_t call(LinphoneCoreManager* caller_mgr,LinphoneCoreManager* callee_mgr);
void end_call(LinphoneCoreManager *m1, LinphoneCoreManager *m2);
void disable_all_audio_codecs_except_one(LinphoneCore *lc, const char *mime, int rate);
void disable_all_video_codecs_except_one(LinphoneCore *lc, const char *mime);
stats * get_stats(LinphoneCore *lc);
LinphoneCoreManager *get_manager(LinphoneCore *lc);
const char *liblinphone_tester_get_subscribe_content(void);
@ -307,10 +313,14 @@ bool_t liblinphone_tester_clock_elapsed(const MSTimeSpec *start, int value_ms);
void linphone_core_manager_check_accounts(LinphoneCoreManager *m);
void account_manager_destroy(void);
LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* path, const char* file, void* user_data);
void liblinphone_tester_enable_ipv6(bool_t enabled);
#ifdef ANDROID
void cunit_android_trace_handler(int level, const char *fmt, va_list args) ;
#endif
int liblinphone_tester_fprintf(FILE * stream, const char * format, ...);
void linphone_call_cb(LinphoneCall *call,void * user_data);
void call_paused_resumed_base(bool_t multicast);
void simple_call_base(bool_t enable_multicast_recv_side);
void call_base(LinphoneMediaEncryption mode, bool_t enable_video,bool_t enable_relay,LinphoneFirewallPolicy policy,bool_t enable_tunnel);
#endif /* LIBLINPHONE_TESTER_H_ */

View file

@ -32,8 +32,8 @@
#endif
/*getline is not available on android...*/
#ifdef ANDROID
/*getline is POSIX 2008, not available on many systems.*/
#if defined(ANDROID) || defined(WIN32)
/* This code is public domain -- Will Hartung 4/9/09 */
size_t getline(char **lineptr, size_t *n, FILE *stream) {
char *bufptr = NULL;
@ -153,8 +153,10 @@ time_t check_file(LinphoneCoreManager* mgr) {
int line_count = 0;
char *line = NULL;
size_t line_size = 256;
struct tm tm_curr;
#ifndef WIN32
struct tm tm_curr = {0};
time_t time_prev = -1;
#endif
#if HAVE_ZLIB
// 0) if zlib is enabled, we must decompress the file first
@ -170,6 +172,7 @@ time_t check_file(LinphoneCoreManager* mgr) {
while (getline(&line, &line_size, file) != -1) {
// a) there should be at least 25 lines
++line_count;
#ifndef WIN32
// b) logs should be ordered by date (format: 2014-11-04 15:22:12:606)
if (strlen(line) > 24) {
char date[24] = {'\0'};
@ -180,6 +183,9 @@ time_t check_file(LinphoneCoreManager* mgr) {
time_prev = time_curr;
}
}
#else
ms_warning("strptime() not available for this platform, test is incomplete.");
#endif
}
CU_ASSERT_TRUE(line_count > 25);
free(line);
@ -190,7 +196,7 @@ time_t check_file(LinphoneCoreManager* mgr) {
CU_ASSERT_TRUE( timediff <= 1 );
if( !(timediff <= 1) ){
ms_error("time_curr: %ld, last_log: %ld timediff: %d", time_curr, last_log, timediff );
ms_error("time_curr: %ld, last_log: %ld timediff: %u", (long int)time_curr, (long int)last_log, timediff );
}
}
// return latest time in file

View file

@ -1006,7 +1006,7 @@ message_tester_copy_file(const char *from, const char *to)
size_t n;
/* Open "from" file for reading */
in=fopen(from, "r");
in=fopen(from, "rb");
if ( in == NULL )
{
ms_error("Can't open %s for reading: %s\n",from,strerror(errno));
@ -1014,7 +1014,7 @@ message_tester_copy_file(const char *from, const char *to)
}
/* Open "to" file for writing (will truncate existing files) */
out=fopen(to, "w");
out=fopen(to, "wb");
if ( out == NULL )
{
ms_error("Can't open %s for writing: %s\n",to,strerror(errno));

View file

@ -0,0 +1,230 @@
/*
liblinphone_tester - liblinphone test suite
Copyright (C) 2014 Belledonne Communications SARL
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "liblinphone_tester.h"
#include "linphonecore.h"
#include "belle-sip/belle-sip.h"
static void call_multicast_base(bool_t video) {
LinphoneCoreManager *marie, *pauline;
int begin;
int leaked_objects;
LinphoneVideoPolicy marie_policy, pauline_policy;
belle_sip_object_enable_leak_detector(TRUE);
begin=belle_sip_object_get_object_count();
marie = linphone_core_manager_new( "marie_rc");
pauline = linphone_core_manager_new( "pauline_rc");
if (video) {
linphone_core_enable_video_capture(marie->lc, TRUE);
linphone_core_enable_video_display(marie->lc, TRUE);
linphone_core_enable_video_capture(pauline->lc, TRUE);
linphone_core_enable_video_display(pauline->lc, FALSE);
marie_policy.automatically_initiate=TRUE;
marie_policy.automatically_accept=TRUE;
pauline_policy.automatically_initiate=TRUE;
pauline_policy.automatically_accept=TRUE;
linphone_core_set_video_policy(marie->lc,&marie_policy);
linphone_core_set_video_policy(pauline->lc,&pauline_policy);
linphone_core_set_video_multicast_addr(pauline->lc,"224.1.2.3");
linphone_core_enable_video_multicast(pauline->lc,TRUE);
}
linphone_core_set_audio_multicast_addr(pauline->lc,"224.1.2.3");
linphone_core_enable_audio_multicast(pauline->lc,TRUE);
CU_ASSERT_TRUE(call(pauline,marie));
wait_for_until(marie->lc, pauline->lc, NULL, 1, 3000);
if (linphone_core_get_current_call(marie->lc)) {
CU_ASSERT_TRUE(linphone_call_get_audio_stats(linphone_core_get_current_call(marie->lc))->download_bandwidth>70);
if (video) {
/*check video path*/
linphone_call_set_next_video_frame_decoded_callback(linphone_core_get_current_call(marie->lc),linphone_call_cb,marie->lc);
linphone_call_send_vfu_request(linphone_core_get_current_call(marie->lc));
CU_ASSERT_TRUE( wait_for(marie->lc,pauline->lc,&marie->stat.number_of_IframeDecoded,1));
}
end_call(marie,pauline);
}
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
leaked_objects=belle_sip_object_get_object_count()-begin;
CU_ASSERT_TRUE(leaked_objects==0);
if (leaked_objects>0){
belle_sip_object_dump_active_objects();
}
belle_sip_object_enable_leak_detector(FALSE);
}
static void call_multicast(void) {
call_multicast_base(FALSE);
}
static void multicast_audio_with_pause_resume() {
call_paused_resumed_base(TRUE);
}
#ifdef VIDEO_ENABLED
static void call_multicast_video(void) {
call_multicast_base(TRUE);
}
#endif
static void early_media_with_multicast_base(bool_t video) {
LinphoneCoreManager *marie, *pauline, *pauline2;
MSList* lcs = NULL;
int dummy=0;
int leaked_objects;
int begin;
LinphoneVideoPolicy marie_policy, pauline_policy;
LpConfig *marie_lp;
belle_sip_object_enable_leak_detector(TRUE);
begin=belle_sip_object_get_object_count();
marie = linphone_core_manager_new("marie_rc");
pauline = linphone_core_manager_new("pauline_rc");
pauline2 = linphone_core_manager_new("pauline_rc");
marie_lp=linphone_core_get_config(marie->lc);
lp_config_set_int(marie_lp,"misc","real_early_media",1);
if (video) {
linphone_core_enable_video_capture(pauline->lc, FALSE);
linphone_core_enable_video_display(pauline->lc, TRUE);
linphone_core_enable_video_capture(pauline2->lc, FALSE);
linphone_core_enable_video_display(pauline2->lc, TRUE);
linphone_core_enable_video_capture(marie->lc, TRUE);
linphone_core_enable_video_display(marie->lc, FALSE);
marie_policy.automatically_initiate=TRUE;
marie_policy.automatically_accept=TRUE;
pauline_policy.automatically_initiate=TRUE;
pauline_policy.automatically_accept=TRUE;
linphone_core_set_video_policy(marie->lc,&marie_policy);
linphone_core_set_video_policy(pauline->lc,&pauline_policy);
linphone_core_set_video_policy(pauline2->lc,&pauline_policy);
linphone_core_set_video_multicast_addr(marie->lc,"224.1.2.3");
linphone_core_enable_video_multicast(marie->lc,TRUE);
}
linphone_core_set_audio_multicast_addr(marie->lc,"224.1.2.3");
linphone_core_enable_audio_multicast(marie->lc,TRUE);
lcs = ms_list_append(lcs,marie->lc);
lcs = ms_list_append(lcs,pauline->lc);
lcs = ms_list_append(lcs,pauline2->lc);
/*
Marie calls Pauline, and after the call has rung, transitions to an early_media session
*/
linphone_core_invite_address(marie->lc, pauline->identity);
CU_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallIncomingReceived,1,3000));
CU_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallOutgoingRinging,1,1000));
if (linphone_core_inc_invite_pending(pauline->lc)) {
/* send a 183 to initiate the early media */
if (video) {
/*check video path*/
linphone_call_set_next_video_frame_decoded_callback(linphone_core_get_current_call(pauline->lc),linphone_call_cb,pauline->lc);
}
linphone_core_accept_early_media(pauline->lc, linphone_core_get_current_call(pauline->lc));
CU_ASSERT_TRUE( wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallIncomingEarlyMedia,1,2000) );
CU_ASSERT_TRUE( wait_for_list(lcs, &marie->stat.number_of_LinphoneCallOutgoingEarlyMedia,1,2000) );
if (linphone_core_inc_invite_pending(pauline2->lc)) {
/* send a 183 to initiate the early media */
if (video) {
/*check video path*/
linphone_call_set_next_video_frame_decoded_callback(linphone_core_get_current_call(pauline2->lc),linphone_call_cb,pauline2->lc);
}
linphone_core_accept_early_media(pauline2->lc, linphone_core_get_current_call(pauline2->lc));
CU_ASSERT_TRUE( wait_for_list(lcs, &pauline2->stat.number_of_LinphoneCallIncomingEarlyMedia,1,2000) );
}
wait_for_list(lcs, &dummy, 1, 3000);
CU_ASSERT_TRUE(linphone_call_get_audio_stats(linphone_core_get_current_call(pauline->lc))->download_bandwidth>70);
CU_ASSERT_TRUE(linphone_call_get_audio_stats(linphone_core_get_current_call(pauline->lc))->download_bandwidth<90);
CU_ASSERT_TRUE(linphone_call_get_audio_stats(linphone_core_get_current_call(pauline2->lc))->download_bandwidth>70);
CU_ASSERT_TRUE(linphone_call_get_audio_stats(linphone_core_get_current_call(pauline2->lc))->download_bandwidth<90);
if (video) {
CU_ASSERT_TRUE( wait_for_list(lcs,&pauline->stat.number_of_IframeDecoded,1,2000));
CU_ASSERT_TRUE( wait_for_list(lcs,&pauline2->stat.number_of_IframeDecoded,1,2000));
}
linphone_core_accept_call(pauline->lc, linphone_core_get_current_call(pauline->lc));
CU_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallConnected, 1,1000));
CU_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 1,1000));
end_call(marie,pauline);
}
ms_free(lcs);
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
linphone_core_manager_destroy(pauline2);
leaked_objects=belle_sip_object_get_object_count()-begin;
CU_ASSERT_EQUAL(leaked_objects,0);
if (leaked_objects>0){
belle_sip_object_dump_active_objects();
}
belle_sip_object_enable_leak_detector(FALSE);
}
static void early_media_with_multicast_audio() {
early_media_with_multicast_base(FALSE);
}
static void unicast_incoming_with_multicast_audio_on() {
simple_call_base(TRUE);
}
#ifdef VIDEO_ENABLED
static void early_media_with_multicast_video() {
early_media_with_multicast_base(TRUE);
}
#endif
test_t multicast_call_tests[] = {
{ "Multicast audio call",call_multicast},
{ "Multicast call with pause/resume",multicast_audio_with_pause_resume},
{ "Early media multicast audio call",early_media_with_multicast_audio},
{ "Unicast incoming call with multicast activated",unicast_incoming_with_multicast_audio_on},
#ifdef VIDEO_ENABLED
{ "Multicast video call",call_multicast_video},
{ "Early media multicast video call",early_media_with_multicast_video},
#endif
};
test_suite_t multicast_call_test_suite = {
"Multicast Call",
NULL,
NULL,
sizeof(multicast_call_tests) / sizeof(multicast_call_tests[0]),
multicast_call_tests
};

View file

@ -347,7 +347,7 @@ static void presence_information(void) {
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
}
#define USE_PRESENCE_SERVER 0
#define USE_PRESENCE_SERVER 1
#if USE_PRESENCE_SERVER
static void test_subscribe_notify_publish(void) {
@ -382,25 +382,90 @@ static void test_subscribe_notify_publish(void) {
wait_for_until(pauline->lc,marie->lc,&pauline->stat.number_of_NotifyReceived,2,2000);
CU_ASSERT_EQUAL(LinphoneStatusOnline,linphone_friend_get_status(lf));
presence =linphone_presence_model_new_with_activity(LinphonePresenceActivityOffline,NULL);
presence =linphone_presence_model_new_with_activity(LinphonePresenceActivityBusy,NULL);
linphone_core_set_presence_model(marie->lc,presence);
/*wait for new status*/
wait_for_until(pauline->lc,marie->lc,&pauline->stat.number_of_NotifyReceived,3,2000);
CU_ASSERT_EQUAL(LinphonePresenceActivityOffline,linphone_friend_get_status(lf));
CU_ASSERT_EQUAL(LinphoneStatusBusy,linphone_friend_get_status(lf));
/*wait for refresh*/
wait_for_until(pauline->lc,marie->lc,&pauline->stat.number_of_NotifyReceived,4,5000);
CU_ASSERT_EQUAL(LinphonePresenceActivityOffline,linphone_friend_get_status(lf));
CU_ASSERT_EQUAL(LinphoneStatusBusy,linphone_friend_get_status(lf));
//linphone_core_remove_friend(pauline->lc,lf);
/*linphone_core_remove_friend(pauline->lc,lf);*/
/*wait for final notify*/
//wait_for_until(pauline->lc,marie->lc,&pauline->stat.number_of_NotifyReceived,4,5000);
//CU_ASSERT_EQUAL(LinphonePresenceActivityOffline,linphone_friend_get_status(lf));
/*wait_for_until(pauline->lc,marie->lc,&pauline->stat.number_of_NotifyReceived,4,5000);
CU_ASSERT_EQUAL(LinphonePresenceActivityOffline,linphone_friend_get_status(lf));
*/
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
}
static void test_forked_subscribe_notify_publish(void) {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* marie2 = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc");
LinphoneProxyConfig* proxy;
LinphonePresenceModel* presence;
LpConfig *pauline_lp;
char* lf_identity;
LinphoneFriend *lf;
MSList* lcs=ms_list_append(NULL,pauline->lc);
lcs=ms_list_append(lcs,marie->lc);
lcs=ms_list_append(lcs,marie->lc);
lcs=ms_list_append(lcs,marie2->lc);
pauline_lp = linphone_core_get_config(pauline->lc);
lf_identity=linphone_address_as_string_uri_only(marie->identity);
lf = linphone_core_create_friend_with_address(pauline->lc,lf_identity);
lp_config_set_int(pauline_lp,"sip","subscribe_expires",5);
linphone_core_add_friend(pauline->lc,lf);
/*wait for subscribe acknowledgment*/
wait_for_list(lcs,&pauline->stat.number_of_NotifyReceived,1,2000);
CU_ASSERT_EQUAL(LinphoneStatusOffline,linphone_friend_get_status(lf));
/*enable publish*/
linphone_core_get_default_proxy(marie->lc,&proxy);
linphone_proxy_config_edit(proxy);
linphone_proxy_config_enable_publish(proxy,TRUE);
linphone_proxy_config_set_publish_expires(proxy,3);
linphone_proxy_config_done(proxy);
linphone_core_get_default_proxy(marie2->lc,&proxy);
linphone_proxy_config_edit(proxy);
linphone_proxy_config_enable_publish(proxy,TRUE);
linphone_proxy_config_set_publish_expires(proxy,3);
linphone_proxy_config_done(proxy);
/*wait for marie status*/
wait_for_list(lcs,&pauline->stat.number_of_NotifyReceived,3,2000);
CU_ASSERT_EQUAL(LinphoneStatusOnline,linphone_friend_get_status(lf));
presence =linphone_presence_model_new_with_activity(LinphonePresenceActivityBusy,NULL);
linphone_core_set_presence_model(marie->lc,presence);
/*wait for new status*/
wait_for_list(lcs,&pauline->stat.number_of_NotifyReceived,4,2000);
CU_ASSERT_EQUAL(LinphoneStatusBusy,linphone_friend_get_status(lf));
presence =linphone_presence_model_new_with_activity( LinphonePresenceActivityMeeting,NULL);
linphone_core_set_presence_model(marie2->lc,presence);
/*wait for new status*/
wait_for_list(lcs,&pauline->stat.number_of_NotifyReceived,5,2000);
CU_ASSERT_EQUAL(LinphoneStatusBusy,linphone_friend_get_status(lf)); /*because liblinphone compositor is very simple for now (I.E only take first occurence)*/
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(marie2);
linphone_core_manager_destroy(pauline);
}
#endif
@ -414,6 +479,7 @@ test_t presence_tests[] = {
{ "App managed presence failure", subscribe_failure_handle_by_app },
#if USE_PRESENCE_SERVER
{ "Subscribe with late publish", test_subscribe_notify_publish },
{ "Forked subscribe with late publish", test_forked_subscribe_notify_publish },
#endif
};

View file

@ -30,8 +30,8 @@ subscribe=0
[rtp]
audio_rtp_port=18070
video_rtp_port=19072
audio_rtp_port=18070-28000
video_rtp_port=39072-49000
[video]
display=0

View file

@ -0,0 +1,53 @@
[sip]
sip_port=-1
sip_tcp_port=-1
sip_tls_port=-1
default_proxy=0
ping_with_options=0
register_only_when_network_is_up=0
composing_idle_timeout=1
[auth_info_0]
username=marie
userid=marie
passwd=secret
realm=sip2.linphone.org
[proxy_0]
reg_proxy=sips:sip2.linphone.org
reg_route=sips:sip2.linphone.org
reg_identity="Super Marie" <sips:marie@sip.example.org>
reg_expires=3600
reg_sendregister=1
publish=0
dial_escape_plus=0
quality_reporting_collector=sip:collector@sip2.linphone.org
quality_reporting_enabled=1
[friend_0]
url="Paupoche" <sip:pauline@sip2.linphone.org>
pol=accept
subscribe=0
[rtp]
audio_rtp_port=8070
video_rtp_port=9072
[video]
display=0
capture=0
show_local=0
size=vga
enabled=0
self_view=0
automatically_initiate=0
automatically_accept=0
device=StaticImage: Static picture
[sound]
echocancellation=0 #to not overload cpu in case of VG
[net]
dns_srv_enabled=0 #no srv needed in general

View file

@ -29,8 +29,8 @@ dial_escape_plus=0
#subscribe=0
[rtp]
audio_rtp_port=8090
video_rtp_port=9092
audio_rtp_port=18070-28000
video_rtp_port=39072-49000
[video]
display=0

View file

@ -0,0 +1,50 @@
[sip]
sip_port=-1
sip_tcp_port=-1
sip_tls_port=-1
default_proxy=0
ping_with_options=0
register_only_when_network_is_up=0
composing_idle_timeout=1
[auth_info_0]
username=pauline
userid=pauline
passwd=secret
realm=sip.example.org
[proxy_0]
reg_proxy=sips:sip2.linphone.org
reg_route=sips:sip2.linphone.org
reg_identity=sips:pauline@sip.example.org
reg_expires=3600
reg_sendregister=1
publish=0
dial_escape_plus=0
#[friend_0]
#url="Mariette" <sip:marie@sip.example.org>
#pol=accept
#subscribe=0
[rtp]
audio_rtp_port=8090
video_rtp_port=9092
[video]
display=0
capture=0
show_local=0
size=vga
enabled=0
self_view=0
automatically_initiate=0
automatically_accept=0
device=StaticImage: Static picture
[sound]
echocancellation=0 #to not overload cpu in case of VG
[net]
dns_srv_enabled=0 #no srv needed in general

Binary file not shown.

View file

@ -21,7 +21,7 @@
#include "linphonecore.h"
#include "private.h"
#include "liblinphone_tester.h"
#include "ortp/stun.h"
#include "mediastreamer2/stun.h"
#include "ortp/port.h"

View file

@ -25,6 +25,9 @@
#if HAVE_CU_CURSES
#include "CUnit/CUCurses.h"
#endif
#ifdef HAVE_GTK
#include <gtk/gtk.h>
#endif
static test_suite_t **test_suite = NULL;
static int nb_test_suites = 0;
@ -41,6 +44,7 @@ const char* test_password="secret";
const char* test_route="sip2.linphone.org";
int liblinphone_tester_use_log_file=0;
static int liblinphone_tester_keep_accounts_flag = 0;
static bool_t liblinphone_tester_ipv6_enabled=FALSE;
static int manager_count = 0;
static const char* liblinphone_tester_xml_file = NULL;
@ -83,6 +87,10 @@ bool_t liblinphone_tester_clock_elapsed(const MSTimeSpec *start, int value_ms){
return FALSE;
}
void liblinphone_tester_enable_ipv6(bool_t enabled){
liblinphone_tester_ipv6_enabled=enabled;
}
LinphoneAddress * create_linphone_address(const char * domain) {
LinphoneAddress *addr = linphone_address_new(NULL);
CU_ASSERT_PTR_NOT_NULL_FATAL(addr);
@ -157,6 +165,7 @@ LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* path, c
sal_set_dns_user_hosts_file(lc->sal, dnsuserhostspath);
linphone_core_set_static_picture(lc,nowebcampath);
linphone_core_enable_ipv6(lc, liblinphone_tester_ipv6_enabled);
ms_free(ringpath);
ms_free(ringbackpath);
@ -195,6 +204,11 @@ bool_t wait_for_list(MSList* lcs,int* counter,int value,int timeout_ms) {
liblinphone_tester_clock_start(&start);
while ((counter==NULL || *counter<value) && !liblinphone_tester_clock_elapsed(&start,timeout_ms)) {
for (iterator=lcs;iterator!=NULL;iterator=iterator->next) {
#ifdef HAVE_GTK
gdk_threads_enter();
gtk_main_iteration_do(FALSE);
gdk_threads_leave();
#endif
linphone_core_iterate((LinphoneCore*)(iterator->data));
}
ms_usleep(20000);
@ -436,6 +450,10 @@ void liblinphone_tester_init(void) {
add_test_suite(&transport_test_suite);
add_test_suite(&player_test_suite);
add_test_suite(&dtmf_test_suite);
#if defined(VIDEO_ENABLED) && defined(HAVE_GTK)
add_test_suite(&video_test_suite);
#endif
add_test_suite(&multicast_call_test_suite);
}
void liblinphone_tester_uninit(void) {

View file

@ -1 +1,2 @@
94.23.19.176 sip2.linphone.org sip.example.org sipopen.example.org auth.example.org auth1.example.org auth2.example.org altname.linphone.org sip.wildcard1.linphone.org altname.wildcard2.linphone.org
2001:41d0:2:14b0::1 sip2.linphone.org sip.example.org sipopen.example.org auth.example.org auth1.example.org auth2.example.org altname.linphone.org sip.wildcard1.linphone.org altname.wildcard2.linphone.org

View file

@ -59,6 +59,8 @@ static char* get_public_contact_ip(LinphoneCore* lc) {
ms_free(contact);
return ms_strdup(contact_host_ip);
}
static void call_with_transport_base(LinphoneTunnelMode tunnel_mode, bool_t with_sip, LinphoneMediaEncryption encryption) {
if (linphone_core_tunnel_available()){
LinphoneCoreManager *pauline = linphone_core_manager_new( "pauline_rc");
@ -131,6 +133,7 @@ static void call_with_transport_base(LinphoneTunnelMode tunnel_mode, bool_t with
}
}
static void call_with_tunnel(void) {
call_with_transport_base(LinphoneTunnelModeEnable, TRUE, LinphoneMediaEncryptionNone);
}
@ -151,12 +154,61 @@ static void call_with_tunnel_auto_without_sip_with_srtp(void) {
call_with_transport_base(LinphoneTunnelModeAuto, FALSE, LinphoneMediaEncryptionSRTP);
}
#ifdef VIDEO_ENABLED
static void tunnel_srtp_video_ice_call(void) {
if (linphone_core_tunnel_available())
call_base(LinphoneMediaEncryptionSRTP,TRUE,FALSE,LinphonePolicyUseIce,TRUE);
else
ms_warning("Could not test %s because tunnel functionality is not available",__FUNCTION__);
}
static void tunnel_zrtp_video_ice_call(void) {
if (linphone_core_tunnel_available())
call_base(LinphoneMediaEncryptionZRTP,TRUE,FALSE,LinphonePolicyUseIce,TRUE);
else
ms_warning("Could not test %s because tunnel functionality is not available",__FUNCTION__);
}
static void tunnel_video_ice_call(void) {
if (linphone_core_tunnel_available())
call_base(LinphoneMediaEncryptionNone,TRUE,FALSE,LinphonePolicyUseIce,TRUE);
else
ms_warning("Could not test %s because tunnel functionality is not available",__FUNCTION__);
}
#endif
static void tunnel_srtp_ice_call(void) {
if (linphone_core_tunnel_available())
call_base(LinphoneMediaEncryptionSRTP,FALSE,FALSE,LinphonePolicyUseIce,TRUE);
else
ms_warning("Could not test %s because tunnel functionality is not available",__FUNCTION__);
}
static void tunnel_zrtp_ice_call(void) {
if (linphone_core_tunnel_available())
call_base(LinphoneMediaEncryptionZRTP,FALSE,FALSE,LinphonePolicyUseIce,TRUE);
else
ms_warning("Could not test %s because tunnel functionality is not available",__FUNCTION__);
}
static void tunnel_ice_call(void) {
if (linphone_core_tunnel_available())
call_base(LinphoneMediaEncryptionNone,FALSE,FALSE,LinphonePolicyUseIce,TRUE);
else
ms_warning("Could not test %s because tunnel functionality is not available",__FUNCTION__);
}
test_t transport_tests[] = {
{ "Tunnel only", call_with_tunnel },
{ "Tunnel with SRTP", call_with_tunnel_srtp },
{ "Tunnel without SIP", call_with_tunnel_without_sip },
{ "Tunnel in automatic mode", call_with_tunnel_auto },
{ "Tunnel in automatic mode with SRTP without SIP", call_with_tunnel_auto_without_sip_with_srtp },
{ "Tunnel ice call", tunnel_ice_call },
{ "Tunnel SRTP ice call", tunnel_srtp_ice_call },
{ "Tunnel ZRTP ice call", tunnel_zrtp_ice_call },
#ifdef VIDEO_ENABLED
{ "Tunnel ice video call", tunnel_video_ice_call },
{ "Tunnel SRTP ice video call", tunnel_srtp_video_ice_call },
{ "Tunnel ZRTP ice video call", tunnel_zrtp_video_ice_call },
#endif
};
test_suite_t transport_test_suite = {

205
tester/video_tester.c Normal file
View file

@ -0,0 +1,205 @@
/*
liblinphone_tester - liblinphone test suite
Copyright (C) 2013 Belledonne Communications SARL
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "private.h"
#if defined(VIDEO_ENABLED) && defined(HAVE_GTK)
#include <stdio.h>
#include "CUnit/Basic.h"
#include "linphonecore.h"
#include "liblinphone_tester.h"
#include "lpconfig.h"
#include <gtk/gtk.h>
#ifdef GDK_WINDOWING_X11
#include <gdk/gdkx.h>
#elif defined(WIN32)
#include <gdk/gdkwin32.h>
#elif defined(__APPLE__)
extern void *gdk_quartz_window_get_nswindow(GdkWindow *window);
extern void *gdk_quartz_window_get_nsview(GdkWindow *window);
#endif
#include <gdk/gdkkeysyms.h>
static unsigned long get_native_handle(GdkWindow *gdkw) {
#ifdef GDK_WINDOWING_X11
return (unsigned long)GDK_WINDOW_XID(gdkw);
#elif defined(WIN32)
return (unsigned long)GDK_WINDOW_HWND(gdkw);
#elif defined(__APPLE__)
return (unsigned long)gdk_quartz_window_get_nsview(gdkw);
#endif
g_warning("No way to get the native handle from gdk window");
return 0;
}
static GtkWidget *create_video_window(LinphoneCall *call) {
GtkWidget *video_window;
GdkDisplay *display;
GdkColor color;
MSVideoSize vsize = MS_VIDEO_SIZE_CIF;
video_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_resize(GTK_WINDOW(video_window), vsize.width, vsize.height);
gdk_color_parse("black", &color);
gtk_widget_modify_bg(video_window, GTK_STATE_NORMAL, &color);
gtk_widget_show(video_window);
g_object_set_data(G_OBJECT(video_window), "call", call);
#if GTK_CHECK_VERSION(2,24,0)
display = gdk_window_get_display(gtk_widget_get_window(video_window));
#else // backward compatibility with Debian 6 and Centos 6
display = gdk_drawable_get_display(gtk_widget_get_window(video_window));
#endif
gdk_display_flush(display);
return video_window;
}
static void show_video_window(LinphoneCall *call) {
GtkWidget *video_window = (GtkWidget *)linphone_call_get_user_data(call);
if (video_window == NULL) {
video_window = create_video_window(call);
linphone_call_set_user_data(call, video_window);
linphone_call_set_native_video_window_id(call, get_native_handle(gtk_widget_get_window(video_window)));
}
}
static void hide_video_video(LinphoneCall *call) {
GtkWidget *video_window = (GtkWidget *)linphone_call_get_user_data(call);
if (video_window != NULL) {
gtk_widget_destroy(video_window);
linphone_call_set_user_data(call, NULL);
linphone_call_set_native_video_window_id(call, 0);
}
}
static void video_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate, const char *msg) {
switch (cstate) {
case LinphoneCallConnected:
show_video_window(call);
break;
case LinphoneCallEnd:
hide_video_video(call);
break;
default:
break;
}
}
static bool_t video_call_with_params(LinphoneCoreManager* caller_mgr, LinphoneCoreManager* callee_mgr, const LinphoneCallParams *caller_params, const LinphoneCallParams *callee_params) {
int retry = 0;
stats initial_caller = caller_mgr->stat;
stats initial_callee = callee_mgr->stat;
bool_t result = FALSE;
bool_t did_received_call;
CU_ASSERT_PTR_NOT_NULL(linphone_core_invite_address_with_params(caller_mgr->lc, callee_mgr->identity, caller_params));
did_received_call = wait_for(callee_mgr->lc, caller_mgr->lc, &callee_mgr->stat.number_of_LinphoneCallIncomingReceived, initial_callee.number_of_LinphoneCallIncomingReceived + 1);
if (!did_received_call) return 0;
CU_ASSERT_TRUE(linphone_core_inc_invite_pending(callee_mgr->lc));
CU_ASSERT_EQUAL(caller_mgr->stat.number_of_LinphoneCallOutgoingProgress, initial_caller.number_of_LinphoneCallOutgoingProgress + 1);
while (caller_mgr->stat.number_of_LinphoneCallOutgoingRinging != (initial_caller.number_of_LinphoneCallOutgoingRinging + 1)
&& caller_mgr->stat.number_of_LinphoneCallOutgoingEarlyMedia != (initial_caller.number_of_LinphoneCallOutgoingEarlyMedia + 1)
&& retry++ < 20) {
linphone_core_iterate(caller_mgr->lc);
linphone_core_iterate(callee_mgr->lc);
ms_usleep(100000);
}
CU_ASSERT_TRUE((caller_mgr->stat.number_of_LinphoneCallOutgoingRinging == initial_caller.number_of_LinphoneCallOutgoingRinging + 1)
|| (caller_mgr->stat.number_of_LinphoneCallOutgoingEarlyMedia == initial_caller.number_of_LinphoneCallOutgoingEarlyMedia + 1));
CU_ASSERT_PTR_NOT_NULL(linphone_core_get_current_call_remote_address(callee_mgr->lc));
if(!linphone_core_get_current_call(caller_mgr->lc) || !linphone_core_get_current_call(callee_mgr->lc) || !linphone_core_get_current_call_remote_address(callee_mgr->lc)) {
return 0;
}
linphone_core_accept_call_with_params(callee_mgr->lc, linphone_core_get_current_call(callee_mgr->lc), callee_params);
CU_ASSERT_TRUE(wait_for(callee_mgr->lc, caller_mgr->lc, &callee_mgr->stat.number_of_LinphoneCallConnected, initial_callee.number_of_LinphoneCallConnected + 1));
CU_ASSERT_TRUE(wait_for(callee_mgr->lc, caller_mgr->lc, &caller_mgr->stat.number_of_LinphoneCallConnected, initial_callee.number_of_LinphoneCallConnected + 1));
result = wait_for(callee_mgr->lc, caller_mgr->lc, &caller_mgr->stat.number_of_LinphoneCallStreamsRunning, initial_caller.number_of_LinphoneCallStreamsRunning + 1)
&& wait_for(callee_mgr->lc, caller_mgr->lc, &callee_mgr->stat.number_of_LinphoneCallStreamsRunning, initial_callee.number_of_LinphoneCallStreamsRunning + 1);
return result;
}
static void early_media_video_during_video_call_test(void) {
LinphoneCoreManager *marie;
LinphoneCoreManager *pauline;
LinphoneCallParams *marie_params;
LinphoneCallParams *pauline_params;
LinphoneCoreVTable *marie_vtable;
LinphoneCoreVTable *pauline_vtable;
int dummy = 0;
marie = linphone_core_manager_new( "marie_rc");
pauline = linphone_core_manager_new( "pauline_rc");
marie_vtable = linphone_core_v_table_new();
marie_vtable->call_state_changed = video_call_state_changed;
linphone_core_add_listener(marie->lc, marie_vtable);
linphone_core_set_video_device(marie->lc, "StaticImage: Static picture");
//linphone_core_set_video_device(marie->lc, "V4L2: /dev/video0");
linphone_core_enable_video_capture(marie->lc, TRUE);
linphone_core_enable_video_display(marie->lc, TRUE);
linphone_core_set_avpf_mode(marie->lc, LinphoneAVPFEnabled);
marie_params = linphone_core_create_default_call_parameters(marie->lc);
linphone_call_params_enable_video(marie_params, TRUE);
disable_all_video_codecs_except_one(marie->lc, "VP8");
pauline_vtable = linphone_core_v_table_new();
pauline_vtable->call_state_changed = video_call_state_changed;
linphone_core_add_listener(pauline->lc, pauline_vtable);
linphone_core_set_video_device(pauline->lc, "StaticImage: Static picture");
linphone_core_enable_video_capture(pauline->lc, TRUE);
linphone_core_enable_video_display(pauline->lc, TRUE);
pauline_params = linphone_core_create_default_call_parameters(pauline->lc);
linphone_call_params_enable_video(pauline_params, TRUE);
disable_all_video_codecs_except_one(pauline->lc, "VP8");
CU_ASSERT_TRUE(video_call_with_params(marie, pauline, marie_params, pauline_params));
/* Wait for 3s. */
wait_for_until(marie->lc, pauline->lc, &dummy, 1, 3000);
linphone_core_terminate_all_calls(marie->lc);
CU_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallEnd, 1));
CU_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallEnd, 1));
CU_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallReleased, 1));
CU_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallReleased, 1));
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
}
test_t video_tests[] = {
{ "Early-media video during video call", early_media_video_during_video_call_test }
};
test_suite_t video_test_suite = {
"Video",
NULL,
NULL,
sizeof(video_tests) / sizeof(video_tests[0]),
video_tests
};
#endif /* VIDEO_ENABLED */