Merge branch 'master' into dev_glade_friendlist

This commit is contained in:
François Grisez 2015-09-11 19:18:58 +02:00
commit 1076333059
78 changed files with 8010 additions and 6156 deletions

64
.clang-format Normal file
View file

@ -0,0 +1,64 @@
---
# BasedOnStyle: LLVM
AccessModifierOffset: -2
AlignAfterOpenBracket: true
AlignEscapedNewlinesLeft: false
AlignOperands: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: false
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: false
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: false
BinPackArguments: true
BinPackParameters: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Attach
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
ColumnLimit: 120
CommentPragmas: '^ IWYU pragma:'
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
IndentCaseLabels: false
IndentFunctionDeclarationAfterType: false
IndentWidth: 4
IndentWrappedFunctionNames: false
KeepEmptyLinesAtTheStartOfBlocks: true
Language: Cpp
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Right
SpaceAfterCStyleCast: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeParens: ControlStatements
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp11
TabWidth: 4
UseTab: Always
...

51
.git-pre-commit Executable file
View file

@ -0,0 +1,51 @@
#!/bin/bash
# This hook purpose is to keep coding style consistent between all developers
# It is automatically installed in .git/hooks folder by cmake on first run.
# From https://github.com/tatsuhiro-t/nghttp2/blob/master/pre-commit
function invalid-format-detected {
cat git-clang-format.diff
echo "*****************"
echo "$0: Invalid coding style detected (see git-clang-format.diff for issues). Please correct it using one of the following:"
echo "1) Apply patch located at git-clang-format.diff using:"
echo " cd $(git rev-parse --show-toplevel) && $1"
echo "2) Use clang-format to correctly format source code using:"
echo " $2"
echo "3) Reformat these lines manually."
echo "*** Aborting commit.***"
exit 1
}
function git-clang-format-diffing {
format_diff=$(which git-clang-format)
format_diff_options="--style=file"
#only diffing commited files, ignored staged one
$format_diff $format_diff_options --diff $(git --no-pager diff --cached --name-status | grep -v '^D' | cut -f2) > git-clang-format.diff
if ! grep -q -E '(no modified files to format|clang-format did not modify any files)' git-clang-format.diff; then
invalid-format-detected "git apply git-clang-format.diff" "clang-format $format_diff_options -i <some_file.c>"
fi
}
function clang-format-diff-diffing {
format_diff=$(find /usr/bin/ -name 'clang-format-diff*' -type f | tail -n1)
format_diff_options="-style file"
git diff-index --cached --diff-filter=ACMR -p HEAD -- | $format_diff $format_diff_options -p1 > git-clang-format.diff
if [ -s git-clang-format.diff ]; then
invalid-format-detected "patch -p0 < git-clang-format.diff" "${format_diff/-diff/} $format_diff_options -i <some_file.cpp>"
fi
}
set -e
if which git-clang-format &>/dev/null; then
git-clang-format-diffing $@
elif [ ! -z "$(find /usr/bin/ /usr/local/bin/ /opt/bin/ -name 'clang-format-diff*' -type f 2>/dev/null)" ]; then
# Warning! We need at least version 1.6...
clang-format-diff-diffing $@
else
echo "$0: Please install clang-format (coding style checker) - could not find git-clang-format nor clang-format-diff in PATH. Skipping code verification..."
exit 0
fi

8
.gitignore vendored
View file

@ -50,8 +50,6 @@ coreapi/help/chatroom
coreapi/help/doc/
coreapi/help/helloworld
coreapi/help/registration
coreapi/test_ecc
coreapi/test_lsd
gtk/version_date.h
specs.c
*.orig
@ -62,7 +60,9 @@ specs.c
*.swp
.deps
.libs
coreapi/test_numbers
tools/test_ecc
tools/test_lsd
tools/test_numbers
coreapi/help/notify
share/fresh-rootca.pem
share/certdata.txt
@ -90,3 +90,5 @@ tester/record-call_with_file_player.wav
tester/ZIDCache*.xml
tester/stereo-record.wav
.dirstamp
git-clang-format.diff

View file

@ -141,6 +141,10 @@ if(ENABLE_NLS)
include_directories(${INTL_INCLUDE_DIRS})
endif()
if(UNIX AND NOT APPLE)
include(CheckIncludeFiles)
check_include_files(libudev.h HAVE_LIBUDEV_H)
endif()
include_directories(
include/

View file

@ -16,19 +16,25 @@ else
AUTOMAKE=automake-${AM_VERSION}
fi
if test -f /opt/local/bin/glibtoolize ; then
# darwin
LIBTOOLIZE=/opt/local/bin/glibtoolize
else
LIBTOOLIZE=libtoolize
fi
LIBTOOLIZE="libtoolize"
for lt in glibtoolize libtoolize15 libtoolize14 libtoolize13 ; do
if test -x /usr/bin/$lt ; then
LIBTOOLIZE=$lt ; break
fi
if test -x /usr/local/bin/$lt ; then
LIBTOOLIZE=$lt ; break
fi
if test -x /opt/local/bin/$lt ; then
LIBTOOLIZE=$lt ; break
fi
done
if test -d /opt/local/share/aclocal ; then
ACLOCAL_ARGS="-I /opt/local/share/aclocal"
ACLOCAL_ARGS="-I /opt/local/share/aclocal"
fi
if test -d /share/aclocal ; then
ACLOCAL_ARGS="$ACLOCAL_ARGS -I /share/aclocal"
ACLOCAL_ARGS="$ACLOCAL_ARGS -I /share/aclocal"
fi
INTLTOOLIZE=$(which intltoolize)
@ -49,6 +55,13 @@ $AUTOMAKE --force-missing --add-missing --copy
autoconf
set +x
#install git pre-commit hooks if possible
if [ -d .git/hooks ] && [ ! -f .git/hooks/pre-commit ]; then
cp .git-pre-commit .git/hooks/pre-commit
chmod +x .git/hooks/pre-commit
fi
if [ "$srcdir" = "." ]; then
if [ -x oRTP/autogen.sh ]; then
echo "Generating build scripts in oRTP..."

View file

@ -173,6 +173,11 @@ LOCAL_CFLAGS += -DHAVE_SILK
LOCAL_STATIC_LIBRARIES += libmssilk
endif
ifeq ($(BUILD_CODEC2),1)
LOCAL_CFLAGS += -DHAVE_CODEC2
LOCAL_STATIC_LIBRARIES += libcodec2 libmscodec2
endif
ifneq ($(BUILD_WEBRTC_AECM)$(BUILD_WEBRTC_ISAC),00)
LOCAL_CFLAGS += -DHAVE_WEBRTC
LOCAL_STATIC_LIBRARIES += libmswebrtc

View file

@ -76,7 +76,7 @@
</binary>
<data>
${prefix}/share/mime/globs
${prefix}/share/mime/mime.cache
</data>
<binary>
@ -136,6 +136,10 @@
${prefix:linphone}/share/images
</data>
<data>
${prefix:linphone}/share/icons
</data>
<!-- Copy in the themes data. You may want to trim this to save space
in your bundle. -->

View file

@ -42,4 +42,5 @@
#cmakedefine HAVE_ZLIB 1
#cmakedefine HAVE_CU_GET_SUITE 1
#cmakedefine HAVE_CU_CURSES 1
#cmakedefine HAVE_LIBUDEV_H 0
#cmakedefine ENABLE_NLS 1

View file

@ -633,7 +633,7 @@ lpc_cmd_chat(LinphoneCore *lc, char *args)
/* missing one parameter */
return 0;
}
cr = linphone_core_create_chat_room(lc,arg1);
cr = linphone_core_get_chat_room_from_uri(lc,arg1);
linphone_chat_room_send_message(cr,arg2);
return 1;
}

View file

@ -144,22 +144,6 @@ liblinphone_la_LIBADD= \
$(ZLIB_LIBS)
if ENABLE_TESTS
noinst_PROGRAMS=test_lsd test_ecc test_numbers
test_lsd_SOURCES=test_lsd.c
test_lsd_LDADD=liblinphone.la $(liblinphone_la_LIBADD)
test_ecc_SOURCES=test_ecc.c
test_ecc_LDADD=liblinphone.la $(liblinphone_la_LIBADD)
test_numbers_SOURCES=test_numbers.c
test_numbers_LDADD=liblinphone.la $(liblinphone_la_LIBADD)
endif
AM_CPPFLAGS=\
-I$(top_srcdir) -I$(top_srcdir)/include -I$(builddir) \
$(ORTP_CFLAGS) \

View file

@ -56,7 +56,7 @@ namespace belledonnecomm {
* @param ip tunnel server ip address
* @param port tunnel server tls port, recommended value is 443
* @param udpMirrorPort remote port on the tunnel server side used to test udp reachability
* @param delay udp packet round trip delay in ms considered as acceptable. recommanded value is 1000 ms.
* @param delay udp packet round trip delay in ms considered as acceptable. recommended value is 1000 ms.
*/
void addServer(const char *ip, int port,unsigned int udpMirrorPort,unsigned int delay);
/**

View file

@ -93,7 +93,6 @@ struct SalOp{
belle_sip_header_referred_by_t *referred_by;
SalMediaDescription *result;
belle_sdp_session_description_t *sdp_answer;
bool_t supports_session_timers;
SalOpState state;
SalOpDir dir;
belle_sip_refresher_t* refresher;
@ -101,14 +100,15 @@ struct SalOp{
SalOpType type;
SalPrivacyMask privacy;
belle_sip_header_t *event; /*used by SalOpSubscribe kinds*/
SalOpSDPHandling sdp_handling;
int auth_requests; /*number of auth requested for this op*/
bool_t cnx_ip_to_0000_if_sendonly_enabled;
bool_t auto_answer_asked;
bool_t sdp_offering;
bool_t call_released;
bool_t manual_refresher;
bool_t has_auth_pending;
SalOpSDPHandling sdp_handling;
int auth_requests; /*number of auth requested for this op*/
bool_t cnx_ip_to_0000_if_sendonly_enabled; /*for */
bool_t supports_session_timers;
};

View file

@ -302,10 +302,10 @@ static void call_process_response(void *op_base, const belle_sip_response_event_
&& (header_content_type = belle_sip_message_get_header_by_type(req,belle_sip_header_content_type_t))
&& strcmp("application",belle_sip_header_content_type_get_type(header_content_type))==0
&& strcmp("media_control+xml",belle_sip_header_content_type_get_subtype(header_content_type))==0) {
unsigned int retry_in =1000*((float)rand()/RAND_MAX);
belle_sip_source_t *s=sal_create_timer(op->base.root,vfu_retry,sal_op_ref(op), retry_in, "vfu request retry");
ms_message("Rejected vfu request on op [%p], just retry in [%ui] ms",op,retry_in);
belle_sip_object_unref(s);
unsigned int retry_in =1000*((float)rand()/RAND_MAX);
belle_sip_source_t *s=sal_create_timer(op->base.root,vfu_retry,sal_op_ref(op), retry_in, "vfu request retry");
ms_message("Rejected vfu request on op [%p], just retry in [%ui] ms",op,retry_in);
belle_sip_object_unref(s);
}else {
/*ignoring*/
}
@ -323,7 +323,7 @@ static void call_process_response(void *op_base, const belle_sip_response_event_
}
break;
case BELLE_SIP_DIALOG_TERMINATED: {
if (code >= 300){
if (strcmp("INVITE",method)==0 && code >= 300){
call_set_error(op,response);
}
}
@ -578,22 +578,27 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t
case BELLE_SIP_DIALOG_CONFIRMED:
/*great ACK received*/
if (strcmp("ACK",method)==0) {
if (op->sdp_offering){
SalReason reason;
if (extract_sdp(op,BELLE_SIP_MESSAGE(req),&sdp,&reason)==0){
if (sdp){
if (op->base.remote_media)
sal_media_description_unref(op->base.remote_media);
op->base.remote_media=sal_media_description_new();
sdp_to_media_description(sdp,op->base.remote_media);
sdp_process(op);
belle_sip_object_unref(sdp);
}else{
ms_warning("SDP expected in ACK but not found.");
if (!op->pending_client_trans ||
!belle_sip_transaction_state_is_transient(belle_sip_transaction_get_state((belle_sip_transaction_t*)op->pending_client_trans))){
if (op->sdp_offering){
SalReason reason;
if (extract_sdp(op,BELLE_SIP_MESSAGE(req),&sdp,&reason)==0){
if (sdp){
if (op->base.remote_media)
sal_media_description_unref(op->base.remote_media);
op->base.remote_media=sal_media_description_new();
sdp_to_media_description(sdp,op->base.remote_media);
sdp_process(op);
belle_sip_object_unref(sdp);
}else{
ms_warning("SDP expected in ACK but not found.");
}
}
}
op->base.root->callbacks.call_ack(op);
}else{
ms_message("Ignored received ack since a new client transaction has been started since.");
}
op->base.root->callbacks.call_ack(op);
} else if(strcmp("BYE",method)==0) {
resp=sal_op_create_response_from_request(op,req,200);
belle_sip_server_transaction_send_response(server_transaction,resp);

View file

@ -43,6 +43,9 @@ SalStreamDir sal_dir_from_call_params_dir(LinphoneMediaDirection cpdir) {
return SalStreamRecvOnly;
case LinphoneMediaDirectionSendRecv:
return SalStreamSendRecv;
case LinphoneMediaDirectionInvalid:
ms_error("LinphoneMediaDirectionInvalid shall not be used.");
return SalStreamInactive;
}
return SalStreamSendRecv;
}

View file

@ -34,11 +34,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
* Indicates for a given media the stream direction
* */
enum _LinphoneMediaDirection {
LinphoneMediaDirectionInvalid = -1,
LinphoneMediaDirectionInactive, /** No active media not supported yet*/
LinphoneMediaDirectionSendOnly, /** Send only mode*/
LinphoneMediaDirectionRecvOnly, /** recv only mode*/
LinphoneMediaDirectionSendRecv, /** send receive*/
};
/**
* Typedef for enum

View file

@ -117,10 +117,8 @@ void linphone_call_update_frozen_payloads(LinphoneCall *call, SalMediaDescriptio
}
}
void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMediaDescription *new_md){
void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMediaDescription *new_md, LinphoneCallState target_state){
SalMediaDescription *oldmd=call->resultdesc;
bool_t all_muted=FALSE;
bool_t send_ringbacktone=FALSE;
int md_changed=0;
@ -144,7 +142,6 @@ void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMedia
call->biggestdesc=sal_media_description_ref(sal_call_get_remote_media_description(call->op));
}
sal_media_description_ref(new_md);
call->expect_media_in_ack=FALSE;
call->resultdesc=new_md;
if ((call->audiostream && call->audiostream->ms.state==MSStreamStarted) || (call->videostream && call->videostream->ms.state==MSStreamStarted)){
clear_early_media_destinations(call);
@ -201,25 +198,11 @@ void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMedia
/*this happens after pausing the call locally. The streams are destroyed and then we wait the 200Ok to recreate them*/
linphone_call_init_media_streams (call);
}
if (call->state==LinphoneCallIncomingEarlyMedia && linphone_core_get_remote_ringback_tone (lc)!=NULL){
send_ringbacktone=TRUE;
}
if ((call->state==LinphoneCallIncomingEarlyMedia || call->state==LinphoneCallOutgoingEarlyMedia) && !call->params->real_early_media){
all_muted=TRUE;
}
if (call->params->real_early_media && call->state==LinphoneCallOutgoingEarlyMedia){
prepare_early_media_forking(call);
}
#ifdef VIDEO_ENABLED
if (call->state==LinphoneCallPausing) {
/*change cam to noweb cam*/
call->cam = get_nowebcam_device();
} else if (call->state != LinphoneCallPaused) {
/*restaure web cam*/
call->cam = lc->video_conf.device;
}
#endif /*VIDEO*/
linphone_call_start_media_streams(call,all_muted,send_ringbacktone);
linphone_call_start_media_streams(call, target_state);
if (call->state==LinphoneCallPausing && call->paused_by_app && ms_list_size(lc->calls)==1){
linphone_core_play_named_tone(lc,LinphoneToneCallOnHold);
}
@ -346,7 +329,7 @@ static void call_received(SalOp *h){
call=linphone_call_new_incoming(lc,from_addr,to_addr,h);
linphone_call_make_local_media_description(lc,call);
linphone_call_make_local_media_description(call);
sal_call_set_local_media_description(call->op,call->localdesc);
md=sal_call_get_final_media_description(call->op);
if (md){
@ -476,7 +459,7 @@ static void call_ringing(SalOp *h){
linphone_call_set_state(call,LinphoneCallOutgoingEarlyMedia,"Early media");
linphone_core_stop_ringing(lc);
ms_message("Doing early media...");
linphone_core_update_streams(lc,call,md);
linphone_core_update_streams(lc,call,md, call->state);
if ((linphone_call_params_get_audio_direction(linphone_call_get_current_params(call)) == LinphoneMediaDirectionInactive) && call->audiostream) {
if (lc->ringstream != NULL) return; /* Already ringing! */
start_remote_ring(lc, call);
@ -484,24 +467,41 @@ static void call_ringing(SalOp *h){
}
}
/*
* could be reach :
* - when the call is accepted
* - when a request is accepted (pause, resume)
*/
static void call_accepted(SalOp *op){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
SalMediaDescription *md, *rmd;
bool_t update_state=TRUE;
static void start_pending_refer(LinphoneCall *call){
linphone_core_start_refered_call(call->core, call,NULL);
}
if (call==NULL){
ms_warning("No call to accept.");
return ;
static void process_call_accepted(LinphoneCore *lc, LinphoneCall *call, SalOp *op){
SalMediaDescription *md, *rmd;
LinphoneCallState next_state = LinphoneCallIdle;
const char *next_state_str = NULL;
LinphoneTaskList tl;
switch (call->state){/*immediately notify the connected state, even if errors occur after*/
case LinphoneCallOutgoingProgress:
case LinphoneCallOutgoingRinging:
case LinphoneCallOutgoingEarlyMedia:
/*immediately notify the connected state*/
linphone_call_set_state(call,LinphoneCallConnected,"Connected");
{
char *tmp=linphone_call_get_remote_address_as_string (call);
char *msg=ms_strdup_printf(_("Call answered by %s"),tmp);
linphone_core_notify_display_status(lc,msg);
ms_free(tmp);
ms_free(msg);
}
break;
default:
break;
}
linphone_task_list_init(&tl);
rmd=sal_call_get_remote_media_description(op);
/*set privacy*/
call->current_params->privacy=(LinphonePrivacyMask)sal_op_get_privacy(call->op);
/*reset the internal call update flag, so it doesn't risk to be copied and used in further re-INVITEs*/
if (call->params->internal_call_update)
call->params->internal_call_update = FALSE;
/* Handle remote ICE attributes if any. */
if (call->ice_session != NULL && rmd) {
@ -514,130 +514,108 @@ static void call_accepted(SalOp *op){
#endif //BUILD_UPNP
md=sal_call_get_final_media_description(op);
switch (call->state){
case LinphoneCallOutgoingProgress:
case LinphoneCallOutgoingRinging:
case LinphoneCallOutgoingEarlyMedia:
linphone_call_set_state(call,LinphoneCallConnected,"Connected");
if (call->referer) linphone_core_notify_refer_state(lc,call->referer,call);
break;
case LinphoneCallEarlyUpdating:
linphone_call_set_state(call,call->prevstate,"Early update accepted");
update_state=FALSE;
break;
default:
break;
if (md == NULL && call->prevstate == LinphoneCallOutgoingEarlyMedia && call->resultdesc != NULL){
ms_message("Using early media SDP since none was received with the 200 OK");
md = call->resultdesc;
}
if( (call->prevstate == LinphoneCallOutgoingEarlyMedia) && (md == NULL || sal_media_description_empty(md)) ){
/* media description is null or empty because no SDP was received in the 200 OK, we can possibly use the early-media SDP. */
if( call->resultdesc != NULL){
ms_message("Using early media SDP since none were received with the 200 OK");
md = call->resultdesc;
}
if (md && (sal_media_description_empty(md) || linphone_core_incompatible_security(lc,md))){
md = NULL;
}
if (md && !sal_media_description_empty(md) && !linphone_core_incompatible_security(lc,md)){
linphone_call_update_remote_session_id_and_ver(call);
linphone_core_update_ice_state_in_call_stats(call);
if (sal_media_description_has_dir(md,SalStreamSendOnly) ||
sal_media_description_has_dir(md,SalStreamInactive)){
{
char *tmp=linphone_call_get_remote_address_as_string (call);
char *msg=ms_strdup_printf(_("Call with %s is paused."),tmp);
linphone_core_notify_display_status(lc,msg);
ms_free(tmp);
ms_free(msg);
}
linphone_core_update_streams (lc,call,md);
if (update_state) linphone_call_set_state(call,LinphoneCallPaused,"Call paused");
if (call->refer_pending)
linphone_core_start_refered_call(lc,call,NULL);
}else if (sal_media_description_has_dir(md,SalStreamRecvOnly)){
/*we are put on hold when the call is initially accepted */
{
char *tmp=linphone_call_get_remote_address_as_string (call);
char *msg=ms_strdup_printf(_("Call answered by %s - on hold."),tmp);
linphone_core_notify_display_status(lc,msg);
ms_free(tmp);
ms_free(msg);
}
linphone_core_update_streams (lc,call,md);
if (update_state) linphone_call_set_state(call,LinphoneCallPausedByRemote,"Call paused by remote");
}else{
if (call->state!=LinphoneCallUpdating){
if (call->state==LinphoneCallResuming){
linphone_core_notify_display_status(lc,_("Call resumed."));
if (md){ /*there is a valid SDP in the response, either offer or answer, and we're able to start/update the streams*/
switch (call->state){
case LinphoneCallResuming:
linphone_core_notify_display_status(lc,_("Call resumed."));
/*intentionally no break*/
case LinphoneCallConnected:
if (call->referer) linphone_core_notify_refer_state(lc,call->referer,call);
/*intentionally no break*/
case LinphoneCallUpdating:
case LinphoneCallUpdatedByRemote:
if (!sal_media_description_has_dir(call->localdesc, SalStreamInactive) &&
(sal_media_description_has_dir(md,SalStreamRecvOnly) ||
sal_media_description_has_dir(md,SalStreamInactive))){
next_state = LinphoneCallPausedByRemote;
next_state_str = "Call paused by remote";
}else{
{
char *tmp=linphone_call_get_remote_address_as_string (call);
char *msg=ms_strdup_printf(_("Call answered by %s."),tmp);
linphone_core_notify_display_status(lc,msg);
ms_free(tmp);
ms_free(msg);
}
if (!call->current_params->in_conference)
lc->current_call=call;
next_state = LinphoneCallStreamsRunning;
next_state_str = "Streams running";
}
}
linphone_core_update_streams(lc,call,md);
/*also reflect the change if the "wished" params, in order to avoid to propose SAVP or video again
* further in the call, for example during pause,resume, conferencing reINVITEs*/
linphone_call_fix_call_parameters(call);
if (!call->current_params->in_conference)
lc->current_call=call;
if (update_state) linphone_call_set_state(call, LinphoneCallStreamsRunning, "Streams running");
break;
case LinphoneCallEarlyUpdating:
next_state_str = "Early update accepted";
next_state = call->prevstate;
break;
case LinphoneCallPausing:
/*when we entered the pausing state, we always reach the paused state whatever the content of the remote SDP is.
Our streams are all send-only (with music), soundcard and camera are never used*/
next_state = LinphoneCallPaused;
next_state_str = "Call paused";
if (call->refer_pending)
linphone_task_list_add(&tl, (LinphoneCoreIterateHook)start_pending_refer, call);
break;
default:
ms_error("call_accepted(): don't know what to do in state [%s]", linphone_call_state_to_string(call->state));
break;
}
}else{
if (next_state != LinphoneCallIdle){
linphone_call_update_remote_session_id_and_ver(call);
linphone_core_update_ice_state_in_call_stats(call);
linphone_core_update_streams(lc, call, md, next_state);
linphone_call_fix_call_parameters(call);
linphone_call_set_state(call, next_state, next_state_str);
}else{
ms_error("BUG: next_state is not set in call_accepted(), current state is %s", linphone_call_state_to_string(call->state));
}
}else{ /*invalid or no SDP*/
switch (call->prevstate){
/*send a bye only in case of outgoing state*/
/*send a bye only in case of early states*/
case LinphoneCallOutgoingInit:
case LinphoneCallOutgoingProgress:
case LinphoneCallOutgoingRinging:
case LinphoneCallOutgoingEarlyMedia:
ms_error("Incompatible SDP offer received in 200 OK, need to abort the call");
case LinphoneCallIncomingReceived:
case LinphoneCallIncomingEarlyMedia:
ms_error("Incompatible SDP answer received, need to abort the call");
linphone_core_abort_call(lc,call,_("Incompatible, check codecs or security settings..."));
break;
/*otherwise we are able to resume previous state*/
default:
ms_message("Incompatible SDP offer received in 200 OK, restoring previous state[%s]",linphone_call_state_to_string(call->prevstate));
ms_message("Incompatible SDP answer received, restoring previous state [%s]",linphone_call_state_to_string(call->prevstate));
linphone_call_set_state(call,call->prevstate,_("Incompatible media parameters."));
break;
}
}
linphone_task_list_run(&tl);
linphone_task_list_free(&tl);
}
static void call_ack(SalOp *op){
/*
* could be reach :
* - when the call is accepted
* - when a request is accepted (pause, resume)
*/
static void call_accepted(SalOp *op){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
if (call==NULL){
ms_warning("No call to be ACK'd");
if (call == NULL){
ms_warning("call_accepted: call does no longer exist.");
return ;
}
if (call->expect_media_in_ack){
SalMediaDescription *md=sal_call_get_final_media_description(op);
if (md && !sal_media_description_empty(md)){
linphone_core_update_streams(lc,call,md);
linphone_call_set_state (call,LinphoneCallStreamsRunning,"Connected (streams running)");
}else{
/*send a bye*/
ms_error("Incompatible SDP response received in ACK, need to abort the call");
linphone_core_abort_call(lc,call,"No codec intersection");
return;
}
}
process_call_accepted(lc, call, op);
}
static void call_resumed(LinphoneCore *lc, LinphoneCall *call){
/*when we are resumed, increment session id, because sdp is changed (a=recvonly disapears)*/
linphone_call_increment_local_media_description(call);
linphone_core_notify_display_status(lc,_("We have been resumed."));
_linphone_core_accept_call_update(lc,call,NULL,LinphoneCallStreamsRunning,"Connected (streams running)");
}
static void call_paused_by_remote(LinphoneCore *lc, LinphoneCall *call){
LinphoneCallParams *params;
/*when we are paused, increment session id, because sdp is changed (a=recvonly appears)*/
linphone_call_increment_local_media_description(call);
/* we are being paused */
linphone_core_notify_display_status(lc,_("We are paused by other party."));
params = linphone_call_params_copy(call->params);
@ -648,101 +626,49 @@ static void call_paused_by_remote(LinphoneCore *lc, LinphoneCall *call){
linphone_call_params_unref(params);
}
static void call_updated_by_remote(LinphoneCore *lc, LinphoneCall *call, bool_t is_update){
/*first check if media capabilities are compatible*/
SalMediaDescription *md;
SalMediaDescription *rmd=sal_call_get_remote_media_description(call->op);
SalMediaDescription *prev_result_desc=call->resultdesc;
if (rmd!=NULL){
if (call->state!=LinphoneCallPaused){
/*in paused state, we must stay in paused state.*/
linphone_call_make_local_media_description(lc,call);
sal_call_set_local_media_description(call->op,call->localdesc);
}
md=sal_call_get_final_media_description(call->op);
if (md && (sal_media_description_empty(md) || linphone_core_incompatible_security(lc,md))){
sal_call_decline(call->op,SalReasonNotAcceptable,NULL);
return;
}
if (is_update && prev_result_desc && md){
int diff=sal_media_description_equals(prev_result_desc,md);
if (diff & (SAL_MEDIA_DESCRIPTION_CRYPTO_POLICY_CHANGED|SAL_MEDIA_DESCRIPTION_STREAMS_CHANGED)){
ms_warning("Cannot accept this update, it is changing parameters that require user approval");
sal_call_decline(call->op,SalReasonNotAcceptable,NULL); /*FIXME should send 504 Cannot change the session parameters without prompting the user"*/
return;
}
}
}
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 = lp_config_get_int(lc->config, "sip", "defer_update_default", FALSE);
linphone_call_set_state(call, LinphoneCallUpdatedByRemote,"Call updated by remote");
if (call->defer_update==FALSE){
linphone_core_accept_call_update(lc,call,NULL);
}
if (rmd==NULL){
call->expect_media_in_ack=TRUE;
}
} else if( call->state == LinphoneCallPausedByRemote ){
/* FIXME: the comment below is meaningless. */
/* 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 = lp_config_get_int(lc->config, "sip", "defer_update_default", 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));
}
}
/* this callback is called when an incoming re-INVITE/ SIP UPDATE modifies the session*/
static void call_updating(SalOp *op, bool_t is_update){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
static void call_updated(LinphoneCore *lc, LinphoneCall *call, SalOp *op, bool_t is_update){
SalMediaDescription *rmd=sal_call_get_remote_media_description(op);
if (rmd==NULL){
/* case of a reINVITE or UPDATE without SDP */
call_updated_by_remote(lc,call,is_update);
return;
}
call->defer_update = lp_config_get_int(lc->config, "sip", "defer_update_default", FALSE);
switch(call->state){
case LinphoneCallPausedByRemote:
if (sal_media_description_has_dir(rmd,SalStreamSendRecv) || sal_media_description_has_dir(rmd,SalStreamRecvOnly)){
call_resumed(lc,call);
}else call_updated_by_remote(lc,call,is_update);
}else{
/*we are staying in PausedByRemote*/
linphone_core_notify_display_status(lc,_("Call is updated by remote."));
linphone_call_set_state(call, LinphoneCallUpdatedByRemote,"Call updated by remote");
if (call->defer_update == FALSE){
linphone_core_accept_call_update(lc,call,NULL);
}
}
break;
/*SIP UPDATE CASE*/
case LinphoneCallOutgoingRinging:
case LinphoneCallOutgoingEarlyMedia:
case LinphoneCallIncomingEarlyMedia:
if (is_update) call_updated_by_remote(lc,call,is_update);
if (is_update) {
linphone_call_set_state(call, LinphoneCallEarlyUpdatedByRemote, "EarlyUpdatedByRemote");
_linphone_core_accept_call_update(lc,call,NULL,call->prevstate,linphone_call_state_to_string(call->prevstate));
}
break;
case LinphoneCallStreamsRunning:
case LinphoneCallConnected:
if (sal_media_description_has_dir(rmd,SalStreamSendOnly) || sal_media_description_has_dir(rmd,SalStreamInactive)){
call_paused_by_remote(lc,call);
}else{
call_updated_by_remote(lc,call,is_update);
linphone_core_notify_display_status(lc,_("Call is updated by remote."));
linphone_call_set_state(call, LinphoneCallUpdatedByRemote,"Call updated by remote");
if (call->defer_update == FALSE){
linphone_core_accept_call_update(lc,call,NULL);
}
}
break;
case LinphoneCallPaused:
if (sal_media_description_has_dir(rmd,SalStreamSendOnly) || sal_media_description_has_dir(rmd,SalStreamInactive)){
call_paused_by_remote(lc,call);
}else{
call_updated_by_remote(lc,call,is_update);
}
/*we'll remain in pause state but accept the offer anyway according to default parameters*/
_linphone_core_accept_call_update(lc,call,NULL,call->state,linphone_call_state_to_string(call->state));
break;
case LinphoneCallUpdating:
case LinphoneCallPausing:
@ -765,6 +691,71 @@ static void call_updating(SalOp *op, bool_t is_update){
}
}
/* this callback is called when an incoming re-INVITE/ SIP UPDATE modifies the session*/
static void call_updating(SalOp *op, bool_t is_update){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
SalMediaDescription *rmd=sal_call_get_remote_media_description(op);
if (!call) {
ms_error("call_updating(): call doesn't exist anymore");
return ;
}
if (call->state!=LinphoneCallPaused){
/*Refresh the local description, but in paused state, we don't change anything.*/
linphone_call_make_local_media_description(call);
sal_call_set_local_media_description(call->op,call->localdesc);
}
if (rmd == NULL){
/* case of a reINVITE or UPDATE without SDP */
call->expect_media_in_ack = TRUE;
sal_call_accept(op); /*respond with an offer*/
/*don't do anything else in this case, wait for the ACK to receive to notify the app*/
}else {
SalMediaDescription *md;
SalMediaDescription *prev_result_desc=call->resultdesc;
call->expect_media_in_ack = FALSE;
md=sal_call_get_final_media_description(call->op);
if (md && (sal_media_description_empty(md) || linphone_core_incompatible_security(lc,md))){
sal_call_decline(call->op,SalReasonNotAcceptable,NULL);
return;
}
if (is_update && prev_result_desc && md){
int diff=sal_media_description_equals(prev_result_desc,md);
if (diff & (SAL_MEDIA_DESCRIPTION_CRYPTO_POLICY_CHANGED|SAL_MEDIA_DESCRIPTION_STREAMS_CHANGED)){
ms_warning("Cannot accept this update, it is changing parameters that require user approval");
sal_call_decline(call->op,SalReasonNotAcceptable,NULL); /*FIXME should send 504 Cannot change the session parameters without prompting the user"*/
return;
}
}
call_updated(lc, call, op, is_update);
}
}
static void call_ack(SalOp *op){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
if (call == NULL){
ms_warning("call_ack(): no call for which an ack is expected");
return;
}
if (call->expect_media_in_ack){
switch(call->state){
case LinphoneCallStreamsRunning:
case LinphoneCallPausedByRemote:
linphone_call_set_state(call, LinphoneCallUpdatedByRemote, "UpdatedByRemote");
break;
default:
break;
}
process_call_accepted(lc, call, op);
}
}
static void call_terminated(SalOp *op, const char *from){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
@ -921,16 +912,11 @@ static void call_failure(SalOp *op){
msg=_("Incompatible media parameters.");
linphone_core_notify_display_status(lc,msg);
break;
case SalReasonRequestPending:
/*restore previous state, the application will decide to resubmit the action if relevant*/
linphone_call_set_state(call,call->prevstate,msg);
return;
break;
default:
linphone_core_notify_display_status(lc,_("Call failed."));
}
/*some call error are not fatal*/
/*some call errors are not fatal*/
switch (call->state) {
case LinphoneCallUpdating:
case LinphoneCallPausing:
@ -1120,6 +1106,7 @@ static void text_received(SalOp *op, const SalMessage *msg){
static void is_composing_received(SalOp *op, const SalIsComposing *is_composing) {
LinphoneCore *lc = (LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
linphone_core_is_composing_received(lc, op, is_composing);
sal_op_release(op);
}
static void parse_presence_requested(SalOp *op, const char *content_type, const char *content_subtype, const char *body, SalPresenceModel **result) {
@ -1263,17 +1250,19 @@ static void text_delivery_update(SalOp *op, SalTextDeliveryStatus status){
// Do not handle delivery status for isComposing messages.
return;
}
// check that the message does not belong to an already destroyed chat room - if so, do not invoke callbacks
if (chat_msg->chat_room != NULL) {
chat_msg->state=chatStatusSal2Linphone(status);
linphone_chat_message_update_state(chat_msg);
chat_msg->state=chatStatusSal2Linphone(status);
linphone_chat_message_update_state(chat_msg);
if (chat_msg && (chat_msg->cb || (chat_msg->callbacks && linphone_chat_message_cbs_get_msg_state_changed(chat_msg->callbacks)))) {
ms_message("Notifying text delivery with status %s",linphone_chat_message_state_to_string(chat_msg->state));
if (chat_msg->callbacks && linphone_chat_message_cbs_get_msg_state_changed(chat_msg->callbacks)) {
linphone_chat_message_cbs_get_msg_state_changed(chat_msg->callbacks)(chat_msg, chat_msg->state);
} else {
/* Legacy */
chat_msg->cb(chat_msg,chat_msg->state,chat_msg->cb_ud);
if (chat_msg && (chat_msg->cb || (chat_msg->callbacks && linphone_chat_message_cbs_get_msg_state_changed(chat_msg->callbacks)))) {
ms_message("Notifying text delivery with status %s",linphone_chat_message_state_to_string(chat_msg->state));
if (chat_msg->callbacks && linphone_chat_message_cbs_get_msg_state_changed(chat_msg->callbacks)) {
linphone_chat_message_cbs_get_msg_state_changed(chat_msg->callbacks)(chat_msg, chat_msg->state);
} else {
/* Legacy */
chat_msg->cb(chat_msg,chat_msg->state,chat_msg->cb_ud);
}
}
}
if (status != SalTextDeliveryInProgress) { /*only release op if not in progress*/

View file

@ -39,6 +39,9 @@
#define FILE_TRANSFER_KEY_SIZE 32
static void linphone_chat_message_release(LinphoneChatMessage *msg);
static LinphoneChatMessageCbs * linphone_chat_message_cbs_new(void) {
return belle_sip_object_new(LinphoneChatMessageCbs);
}
@ -106,26 +109,13 @@ static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatM
static void process_io_error_upload(void *data, const belle_sip_io_error_event_t *event){
LinphoneChatMessage* msg=(LinphoneChatMessage *)data;
msg->state = LinphoneChatMessageStateNotDelivered;
ms_error("I/O Error during file upload to %s - msg [%p] chat room[%p]", linphone_core_get_file_transfer_server(msg->chat_room->lc), msg, msg->chat_room);
if (msg->cb) {
msg->cb(msg, msg->state, msg->cb_ud);
}
if (linphone_chat_message_cbs_get_msg_state_changed(msg->callbacks)) {
linphone_chat_message_cbs_get_msg_state_changed(msg->callbacks)(msg, msg->state);
}
linphone_chat_message_cancel_file_transfer(msg);
}
static void process_auth_requested_upload(void *data, belle_sip_auth_event_t *event){
LinphoneChatMessage* msg=(LinphoneChatMessage *)data;
msg->state = LinphoneChatMessageStateNotDelivered;
ms_error("Error during file upload : auth requested to connect %s - msg [%p] chat room[%p]", linphone_core_get_file_transfer_server(msg->chat_room->lc), msg, msg->chat_room);
if (msg->cb) {
msg->cb(msg, msg->state, msg->cb_ud);
}
if (linphone_chat_message_cbs_get_msg_state_changed(msg->callbacks)) {
linphone_chat_message_cbs_get_msg_state_changed(msg->callbacks)(msg, msg->state);
}
ms_error("Error during file upload: auth requested to connect %s - msg [%p] chat room[%p]", linphone_core_get_file_transfer_server(msg->chat_room->lc), msg, msg->chat_room);
linphone_chat_message_cancel_file_transfer(msg);
}
static void process_io_error_download(void *data, const belle_sip_io_error_event_t *event){
@ -376,7 +366,8 @@ void linphone_core_enable_chat(LinphoneCore *lc){
bool_t linphone_core_chat_enabled(const LinphoneCore *lc){
return lc->chat_deny_code!=LinphoneReasonNone;
}
MSList* linphone_core_get_chat_rooms(LinphoneCore *lc) {
const MSList* linphone_core_get_chat_rooms(LinphoneCore *lc) {
return lc->chatrooms;
}
@ -442,14 +433,6 @@ static LinphoneChatRoom * _linphone_core_get_or_create_chat_room(LinphoneCore* l
return ret;
}
LinphoneChatRoom* linphone_core_get_or_create_chat_room(LinphoneCore* lc, const char* to) {
return _linphone_core_get_or_create_chat_room(lc, to);
}
LinphoneChatRoom * linphone_core_create_chat_room(LinphoneCore *lc, const char *to) {
return _linphone_core_get_or_create_chat_room(lc, to);
}
LinphoneChatRoom *linphone_core_get_chat_room(LinphoneCore *lc, const LinphoneAddress *addr){
LinphoneChatRoom *ret = _linphone_core_get_chat_room(lc, addr);
if (!ret) {
@ -458,6 +441,18 @@ LinphoneChatRoom *linphone_core_get_chat_room(LinphoneCore *lc, const LinphoneAd
return ret;
}
void linphone_core_delete_chat_room(LinphoneCore *lc, LinphoneChatRoom *cr){
if (ms_list_find(lc->chatrooms, cr)){
lc->chatrooms = ms_list_remove(cr->lc->chatrooms, cr);
linphone_chat_room_delete_history(cr);
linphone_chat_room_unref(cr);
}else{
ms_error("linphone_core_delete_chat_room(): chatroom [%p] isn't part of LinphoneCore.",
cr);
}
}
LinphoneChatRoom * linphone_core_get_chat_room_from_uri(LinphoneCore *lc, const char *to) {
return _linphone_core_get_or_create_chat_room(lc, to);
}
@ -490,12 +485,18 @@ static void linphone_chat_room_delete_remote_composing_refresh_timer(LinphoneCha
}
static void _linphone_chat_room_destroy(LinphoneChatRoom *cr){
ms_list_free_with_data(cr->transient_messages, (void (*)(void*))linphone_chat_message_unref);
ms_list_free_with_data(cr->transient_messages, (void (*)(void*))linphone_chat_message_release);
linphone_chat_room_delete_composing_idle_timer(cr);
linphone_chat_room_delete_composing_refresh_timer(cr);
linphone_chat_room_delete_remote_composing_refresh_timer(cr);
if (cr->lc != NULL) {
cr->lc->chatrooms=ms_list_remove(cr->lc->chatrooms,(void *) cr);
if (ms_list_find(cr->lc->chatrooms, cr)){
ms_error("LinphoneChatRoom[%p] is destroyed while still being used by the LinphoneCore. This is abnormal."
" linphone_core_get_chat_room() doesn't give a reference, there is no need to call linphone_chat_room_unref(). "
"In order to remove a chat room from the core, use linphone_core_delete_chat_room().",
cr);
}
cr->lc->chatrooms=ms_list_remove(cr->lc->chatrooms, cr);
}
linphone_address_destroy(cr->peer_url);
ms_free(cr->peer);
@ -807,14 +808,17 @@ static void process_im_is_composing_notification(LinphoneChatRoom *cr, xmlparsin
xmlXPathRegisterNs(xml_ctx->xpath_ctx, (const xmlChar *)"xsi", (const xmlChar *)"urn:ietf:params:xml:ns:im-iscomposing");
iscomposing_object = linphone_get_xml_xpath_object_for_node_list(xml_ctx, iscomposing_prefix);
if ((iscomposing_object != NULL) && (iscomposing_object->nodesetval != NULL)) {
for (i = 1; i <= iscomposing_object->nodesetval->nodeNr; i++) {
snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/xsi:state", iscomposing_prefix, i);
state_str = linphone_get_xml_text_content(xml_ctx, xpath_str);
if (state_str == NULL) continue;
snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/xsi:refresh", iscomposing_prefix, i);
refresh_str = linphone_get_xml_text_content(xml_ctx, xpath_str);
if (iscomposing_object != NULL){
if(iscomposing_object->nodesetval != NULL) {
for (i = 1; i <= iscomposing_object->nodesetval->nodeNr; i++) {
snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/xsi:state", iscomposing_prefix, i);
state_str = linphone_get_xml_text_content(xml_ctx, xpath_str);
if (state_str == NULL) continue;
snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/xsi:refresh", iscomposing_prefix, i);
refresh_str = linphone_get_xml_text_content(xml_ctx, xpath_str);
}
}
xmlXPathFreeObject(iscomposing_object);
}
if (state_str != NULL) {
@ -854,10 +858,12 @@ static void linphone_chat_room_notify_is_composing(LinphoneChatRoom *cr, const c
}
void linphone_core_is_composing_received(LinphoneCore *lc, SalOp *op, const SalIsComposing *is_composing) {
LinphoneChatRoom *cr = linphone_core_get_or_create_chat_room(lc, is_composing->from);
LinphoneAddress *addr = linphone_address_new(is_composing->from);
LinphoneChatRoom *cr = _linphone_core_get_chat_room(lc, addr);
if (cr != NULL) {
linphone_chat_room_notify_is_composing(cr, is_composing->text);
}
linphone_address_destroy(addr);
}
bool_t linphone_chat_room_is_remote_composing(const LinphoneChatRoom *cr) {
@ -984,37 +990,22 @@ static char * linphone_chat_room_create_is_composing_xml(LinphoneChatRoom *cr) {
static void linphone_chat_room_send_is_composing_notification(LinphoneChatRoom *cr) {
SalOp *op = NULL;
LinphoneCall *call;
const char *identity = NULL;
char *content = NULL;
LinphoneProxyConfig *proxy = linphone_core_lookup_known_proxy(cr->lc, cr->peer_url);
if (proxy)
identity = linphone_proxy_config_get_identity(proxy);
else
identity = linphone_core_get_primary_contact(cr->lc);
/*sending out of calls*/
op = sal_op_new(cr->lc->sal);
linphone_configure_op(cr->lc, op, cr->peer_url, NULL, lp_config_get_int(cr->lc->config, "sip", "chat_msg_with_contact", 0));
if (lp_config_get_int(cr->lc->config, "sip", "chat_use_call_dialogs", 0)) {
if ((call = linphone_core_get_call_by_remote_address(cr->lc, cr->peer)) != NULL) {
if (call->state == LinphoneCallConnected ||
call->state == LinphoneCallStreamsRunning ||
call->state == LinphoneCallPaused ||
call->state == LinphoneCallPausing ||
call->state == LinphoneCallPausedByRemote) {
ms_message("send SIP message through the existing call.");
op = call->op;
identity = linphone_core_find_best_identity(cr->lc, linphone_call_get_remote_address(call));
}
}
}
if (op == NULL) {
LinphoneProxyConfig *proxy = linphone_core_lookup_known_proxy(cr->lc, cr->peer_url);
if (proxy)
identity = linphone_proxy_config_get_identity(proxy);
else
identity = linphone_core_get_primary_contact(cr->lc);
/*sending out of calls*/
op = sal_op_new(cr->lc->sal);
linphone_configure_op(cr->lc, op, cr->peer_url, NULL, lp_config_get_int(cr->lc->config, "sip", "chat_msg_with_contact", 0));
}
content = linphone_chat_room_create_is_composing_xml(cr);
if (content != NULL) {
sal_message_send(op, identity, cr->peer, "application/im-iscomposing+xml", content, NULL);
ms_free(content);
sal_op_unref(op);
}
}
@ -1404,7 +1395,6 @@ static void _linphone_chat_message_destroy(LinphoneChatMessage* msg) {
ms_free(msg->file_transfer_filepath);
}
linphone_chat_message_cbs_unref(msg->callbacks);
ms_message("LinphoneChatMessage [%p] destroyed.",msg);
}
LinphoneChatMessage * linphone_chat_message_ref(LinphoneChatMessage *msg){
@ -1416,6 +1406,12 @@ void linphone_chat_message_unref(LinphoneChatMessage *msg){
belle_sip_object_unref(msg);
}
static void linphone_chat_message_release(LinphoneChatMessage *msg){
/*mark the chat message as orphan (it has no chat room anymore), and unref it*/
msg->chat_room = NULL;
linphone_chat_message_unref(msg);
}
const LinphoneErrorInfo *linphone_chat_message_get_error_info(const LinphoneChatMessage *msg){
return linphone_error_info_from_sal_op(msg->op);
}
@ -1440,7 +1436,7 @@ LinphoneChatMessageCbs * linphone_chat_message_get_callbacks(const LinphoneChatM
return msg->callbacks;
}
LinphoneChatMessage* linphone_chat_room_create_file_transfer_message(LinphoneChatRoom *cr, LinphoneContent* initial_content) {
LinphoneChatMessage* linphone_chat_room_create_file_transfer_message(LinphoneChatRoom *cr, const LinphoneContent* initial_content) {
LinphoneChatMessage* msg = belle_sip_object_new(LinphoneChatMessage);
msg->callbacks=linphone_chat_message_cbs_new();
msg->chat_room=(LinphoneChatRoom*)cr;

View file

@ -92,7 +92,7 @@ LinphoneFriend *linphone_find_friend_by_inc_subscribe(MSList *l, SalOp *op){
MSList *elem;
for (elem=l;elem!=NULL;elem=elem->next){
LinphoneFriend *lf=(LinphoneFriend*)elem->data;
if (lf->insub==op) return lf;
if (ms_list_find(lf->insubs, op)) return lf;
}
return NULL;
}
@ -227,12 +227,24 @@ int linphone_friend_set_inc_subscribe_policy(LinphoneFriend *fr, LinphoneSubscri
}
void linphone_friend_notify(LinphoneFriend *lf, LinphonePresenceModel *presence){
char *addr=linphone_address_as_string(linphone_friend_get_address(lf));
ms_message("Want to notify %s, insub=%p",addr,lf->insub);
ms_free(addr);
if (lf->insub!=NULL){
sal_notify_presence(lf->insub,(SalPresenceModel *)presence);
MSList *elem;
if (lf->insubs){
char *addr=linphone_address_as_string(linphone_friend_get_address(lf));
ms_message("Want to notify %s",addr);
ms_free(addr);
}
for(elem=lf->insubs; elem!=NULL; elem=elem->next){
SalOp *op = (SalOp*)elem->data;
sal_notify_presence(op,(SalPresenceModel *)presence);
}
}
void linphone_friend_add_incoming_subscription(LinphoneFriend *lf, SalOp *op){
lf->insubs = ms_list_append(lf->insubs, op);
}
void linphone_friend_remove_incoming_subscription(LinphoneFriend *lf, SalOp *op){
lf->insubs = ms_list_remove(lf->insubs, op);
}
static void linphone_friend_unsubscribe(LinphoneFriend *lf){
@ -260,17 +272,12 @@ static void linphone_friend_invalidate_subscription(LinphoneFriend *lf){
void linphone_friend_close_subscriptions(LinphoneFriend *lf){
linphone_friend_unsubscribe(lf);
if (lf->insub){
sal_notify_presence_close(lf->insub);
ms_list_for_each(lf->insubs, (MSIterateFunc) sal_notify_presence_close);
}
}
static void _linphone_friend_destroy(LinphoneFriend *lf){
if (lf->insub) {
sal_op_release(lf->insub);
lf->insub=NULL;
}
lf->insubs = ms_list_free_with_data(lf->insubs, (MSIterateFunc) sal_op_release);
if (lf->outsub){
sal_op_release(lf->outsub);
lf->outsub=NULL;

View file

@ -81,7 +81,7 @@ int main(int argc, char *argv[]){
/*Next step is to create a chat root*/
chat_room = linphone_core_create_chat_room(lc,dest_friend);
chat_room = linphone_core_get_chat_room_from_uri(lc,dest_friend);
linphone_chat_room_send_message(chat_room,"Hello world"); /*sending message*/
@ -92,7 +92,6 @@ int main(int argc, char *argv[]){
}
printf("Shutting down...\n");
linphone_chat_room_destroy(chat_room);
linphone_core_destroy(lc);
printf("Exited\n");
return 0;

View file

@ -160,7 +160,7 @@ int main(int argc, char *argv[]){
/*Next step is to create a chat room*/
chat_room = linphone_core_create_chat_room(lc,dest_friend);
chat_room = linphone_core_get_chat_room_from_uri(lc,dest_friend);
content = linphone_core_create_content(lc);
linphone_content_set_type(content,"text");
@ -196,7 +196,6 @@ int main(int argc, char *argv[]){
printf("Shutting down...\n");
linphone_content_unref(content);
linphone_chat_room_destroy(chat_room);
linphone_core_destroy(lc);
printf("Exited\n");
return 0;

View file

@ -402,11 +402,15 @@ LINPHONE_PUBLIC bool_t linphone_proxy_config_is_phone_number(LinphoneProxyConfig
* @param result the newly normalized number
* @param result_len the size of the normalized number \a result
* @return TRUE if a phone number was recognized, FALSE otherwise.
* @deprecated use linphone_proxy_config_normalize_phone_number()
*/
LINPHONE_PUBLIC bool_t linphone_proxy_config_normalize_number(LinphoneProxyConfig *proxy, const char *username, char *result, size_t result_len);
/**
* Same objective as linphone_proxy_config_normalize_number but allocates a new string
* Normalize a human readable phone number into a basic string. 888-444-222 becomes 888444222
* or +33888444222 depending on the #LinphoneProxyConfig object. However this argument is OPTIONNAL
* and if not provided, a default one will be used.
* This function will always generate a normalized username; if input is not a phone number, output will be a copy of input.
* @param proxy #LinphoneProxyConfig object containing country code and/or escape symbol. If NULL passed, will use default configuration.
* @param username the string to parse
* @return NULL if invalid phone number, normalized phone number from username input otherwise.

View file

@ -43,11 +43,15 @@ static const char *EC_STATE_STORE = ".linphone.ecstate";
static void linphone_call_stats_uninit(LinphoneCallStats *stats);
static void linphone_call_get_local_ip(LinphoneCall *call, const LinphoneAddress *remote_addr);
#ifdef VIDEO_ENABLED
MSWebCam *get_nowebcam_device(){
#ifdef VIDEO_ENABLED
return ms_web_cam_manager_get_cam(ms_web_cam_manager_get(),"StaticImage: Static picture");
}
#else
return NULL;
#endif
}
static bool_t generate_b64_crypto_key(int key_length, char* key_out, size_t key_out_size) {
int b64_size;
@ -578,11 +582,30 @@ static const char *linphone_call_get_public_ip_for_stream(LinphoneCall *call, in
return public_ip;
}
void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *call) {
linphone_call_make_local_media_description_with_params(lc, call, call->params);
static void force_streams_dir_according_to_state(LinphoneCall *call, SalMediaDescription *md){
int i;
switch (call->state){
case LinphoneCallPausing:
case LinphoneCallPaused:
break;
default:
return;
break;
}
for (i=0; i<2; ++i){
SalStreamDescription *sd = &md->streams[i];
sd->dir = SalStreamSendOnly;
if (sd->type == SalVideo){
if (lp_config_get_int(call->core->config, "sip", "inactive_video_on_pause", 0)) {
sd->dir = SalStreamInactive;
}
}
}
}
void linphone_call_make_local_media_description_with_params(LinphoneCore *lc, LinphoneCall *call, LinphoneCallParams *params) {
void linphone_call_make_local_media_description(LinphoneCall *call) {
MSList *l;
SalMediaDescription *old_md=call->localdesc;
int i;
@ -591,6 +614,9 @@ void linphone_call_make_local_media_description_with_params(LinphoneCore *lc, Li
LinphoneAddress *addr;
const char *subject;
CodecConstraints codec_hints={0};
LinphoneCallParams *params = call->params;
LinphoneCore *lc = call->core;
/*multicast is only set in case of outgoing call*/
if (call->dir == LinphoneCallOutgoing && linphone_call_params_audio_multicast_enabled(params)) {
@ -714,6 +740,7 @@ void linphone_call_make_local_media_description_with_params(LinphoneCore *lc, Li
call->localdesc_changed=sal_media_description_equals(md,old_md);
sal_media_description_unref(old_md);
}
force_streams_dir_according_to_state(call, md);
}
static int find_port_offset(LinphoneCore *lc, int stream_index, int base_port){
@ -818,9 +845,6 @@ static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from,
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 VIDEO_ENABLED
call->cam = call->core->video_conf.device;
#endif
}
void linphone_call_init_stats(LinphoneCallStats *stats, int type) {
@ -948,6 +972,7 @@ void linphone_call_fill_media_multicast_addr(LinphoneCall *call) {
} else
call->media_ports[1].multicast_ip[0]='\0';
}
LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, const LinphoneCallParams *params, LinphoneProxyConfig *cfg){
LinphoneCall *call = belle_sip_object_new(LinphoneCall);
@ -955,7 +980,7 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr
call->core=lc;
linphone_call_outgoing_select_ip_version(call,to,cfg);
linphone_call_get_local_ip(call, to);
linphone_call_init_common(call,from,to);
linphone_call_init_common(call, from, to);
call->params = linphone_call_params_copy(params);
linphone_call_fill_media_multicast_addr(call);
@ -1260,7 +1285,7 @@ void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const
call->prevstate=call->state;
if (call->state==LinphoneCallEnd || call->state==LinphoneCallError){
if (cstate!=LinphoneCallReleased){
ms_warning("Spurious call state change from %s to %s, ignored." ,linphone_call_state_to_string(call->state)
ms_fatal("Spurious call state change from %s to %s, ignored." ,linphone_call_state_to_string(call->state)
,linphone_call_state_to_string(cstate));
return;
}
@ -1286,11 +1311,11 @@ void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const
break;
case LinphoneCallEnd:
case LinphoneCallError:
switch(call->non_op_error.reason){
case SalReasonDeclined:
switch(linphone_error_info_get_reason(linphone_call_get_error_info(call))) {
case LinphoneReasonDeclined:
call->log->status=LinphoneCallDeclined;
break;
case SalReasonRequestTimeout:
case LinphoneReasonNotAnswered:
call->log->status=LinphoneCallMissed;
break;
default:
@ -1324,7 +1349,13 @@ void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const
linphone_call_cancel_dtmfs(call);
}
}
linphone_core_notify_call_state_changed(lc,call,cstate,message);
if (!message) {
ms_error("%s(): You must fill a reason when changing call state (from %s o %s)."
, __FUNCTION__
, linphone_call_state_to_string(call->prevstate)
, linphone_call_state_to_string(call->state));
}
linphone_core_notify_call_state_changed(lc,call,cstate,message?message:"");
linphone_reporting_call_state_updated(call);
if (cstate==LinphoneCallReleased) {/*shall be performed after app notification*/
linphone_call_set_released(call);
@ -2009,6 +2040,7 @@ void linphone_call_init_audio_stream(LinphoneCall *call){
ms_free(cname);
rtp_session_set_symmetric_rtp(audiostream->ms.sessions.rtp_session,linphone_core_symmetric_rtp_enabled(lc));
setup_dtls_params(call, &audiostream->ms);
media_stream_reclaim_sessions(&audiostream->ms, &call->sessions[0]);
}else{
call->audiostream=audio_stream_new_with_sessions(&call->sessions[0]);
}
@ -2108,8 +2140,8 @@ void linphone_call_init_video_stream(LinphoneCall *call){
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));
setup_dtls_params(call, &call->videostream->ms);
media_stream_reclaim_sessions(&call->videostream->ms, &call->sessions[1]);
}else{
call->videostream=video_stream_new_with_sessions(&call->sessions[1]);
}
@ -2546,9 +2578,8 @@ static RtpSession * create_audio_rtp_io_session(LinphoneCall *call) {
return rtp_session;
}
static void linphone_call_start_audio_stream(LinphoneCall *call, bool_t muted, bool_t send_ringbacktone, bool_t use_arc){
static void linphone_call_start_audio_stream(LinphoneCall *call, LinphoneCallState next_state, bool_t use_arc){
LinphoneCore *lc=call->core;
LpConfig* conf;
int used_pt=-1;
char rtcp_tool[128]={0};
const SalStreamDescription *stream;
@ -2585,26 +2616,24 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, bool_t muted, b
if (captcard==NULL) {
ms_warning("No card defined for capture !");
}
/*Replace soundcard filters by inactive file players or recorders
when placed in recvonly or sendonly mode*/
/*Don't use file or soundcard capture when placed in recv-only mode*/
if (stream->rtp_port==0
|| stream->dir==SalStreamRecvOnly
|| (stream->multicast_role == SalMulticastReceiver && is_multicast)){
captcard=NULL;
playfile=NULL;
}else if (stream->dir==SalStreamSendOnly){
}
if (next_state == LinphoneCallPaused){
/*in paused state, we never use soundcard*/
playcard=NULL;
/*jehan: why capture card should be null in this case ? Not very good to only rely on stream dir to detect paused state.
* It can also be a simple call in one way audio*/
captcard=NULL;
recfile=NULL;
/*And we will eventually play "playfile" if set by the user*/
}
if (send_ringbacktone){
conf = linphone_core_get_config(lc);
if (call->playing_ringbacktone){
captcard=NULL;
playfile=NULL;/* it is setup later*/
if( conf && lp_config_get_int(conf,"sound","send_ringback_without_playback", 0) == 1){
if (lp_config_get_int(lc->config,"sound","send_ringback_without_playback", 0) == 1){
playcard = NULL;
recfile = NULL;
}
@ -2628,7 +2657,7 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, bool_t muted, b
if (captcard && stream->max_rate>0) ms_snd_card_set_preferred_sample_rate(captcard, stream->max_rate);
audio_stream_enable_adaptive_bitrate_control(call->audiostream,use_arc);
media_stream_set_adaptive_bitrate_algorithm(&call->audiostream->ms,
ms_qos_analyzer_algorithm_from_string(linphone_core_get_adaptive_rate_algorithm(lc)));
ms_qos_analyzer_algorithm_from_string(linphone_core_get_adaptive_rate_algorithm(lc)));
audio_stream_enable_adaptive_jittcomp(call->audiostream, linphone_core_audio_adaptive_jittcomp_enabled(lc));
rtp_session_set_jitter_compensation(call->audiostream->ms.sessions.rtp_session,linphone_core_get_audio_jittcomp(lc));
if (!call->params->in_conference && call->params->record_file){
@ -2673,7 +2702,7 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, bool_t muted, b
io.input.type = MSResourceFile;
io.input.file = playfile;
}
}
if (ok == TRUE) {
audio_stream_start_from_io(call->audiostream,
@ -2685,22 +2714,22 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, bool_t muted, b
used_pt,
&io
);
post_configure_audio_streams(call, muted && !send_ringbacktone);
post_configure_audio_streams(call, (call->all_muted || call->audio_muted) && !call->playing_ringbacktone);
}
ms_media_stream_sessions_set_encryption_mandatory(&call->audiostream->ms.sessions,linphone_core_is_media_encryption_mandatory(call->core));
if (stream->dir==SalStreamSendOnly && playfile!=NULL){
if (next_state == LinphoneCallPaused && captcard == NULL && playfile != NULL){
int pause_time=500;
ms_filter_call_method(call->audiostream->soundread,MS_FILE_PLAYER_LOOP,&pause_time);
}
if (send_ringbacktone){
if (call->playing_ringbacktone){
setup_ring_player(lc,call);
}
if (call->params->in_conference){
/*transform the graph to connect it to the conference filter */
mute=stream->dir==SalStreamRecvOnly;
mute = stream->dir==SalStreamRecvOnly;
linphone_call_add_to_conf(call, mute);
}
call->current_params->in_conference=call->params->in_conference;
@ -2736,7 +2765,7 @@ static RtpSession * create_video_rtp_io_session(LinphoneCall *call) {
}
#endif
static void linphone_call_start_video_stream(LinphoneCall *call, bool_t all_inputs_muted){
static void linphone_call_start_video_stream(LinphoneCall *call, LinphoneCallState next_state){
#ifdef VIDEO_ENABLED
LinphoneCore *lc=call->core;
int used_pt=-1;
@ -2765,7 +2794,7 @@ static void linphone_call_start_video_stream(LinphoneCall *call, bool_t all_inpu
MediaStreamDir dir= MediaStreamSendRecv;
bool_t is_inactive=FALSE;
MSWebCam *cam;
call->current_params->video_codec = rtp_profile_get_payload(call->video_profile, used_pt);
call->current_params->has_video=TRUE;
@ -2778,6 +2807,8 @@ static void linphone_call_start_video_stream(LinphoneCall *call, bool_t all_inpu
if (lc->video_conf.preview_vsize.width!=0)
video_stream_set_preview_size(call->videostream,lc->video_conf.preview_vsize);
video_stream_set_fps(call->videostream,linphone_core_get_preferred_framerate(lc));
if (lp_config_get_int(lc->config, "video", "nowebcam_uses_normal_fps", 0))
call->videostream->staticimage_webcam_fps_optimization = FALSE;
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 (call->video_window_id != NULL)
@ -2809,11 +2840,7 @@ static void linphone_call_start_video_stream(LinphoneCall *call, bool_t all_inpu
/*either inactive or incompatible with local capabilities*/
is_inactive=TRUE;
}
if (all_inputs_muted){
cam=get_nowebcam_device();
} else {
cam = linphone_call_get_video_device(call);
}
cam = linphone_call_get_video_device(call);
if (!is_inactive){
if (sal_stream_description_has_srtp(vstream) == TRUE) {
int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, vstream->crypto_local_tag);
@ -2933,13 +2960,29 @@ static void setZrtpCryptoTypesParameters(MSZrtpParams *params, LinphoneCore *lc)
params->keyAgreementsCount = linphone_core_get_zrtp_key_agreement_suites(lc, params->keyAgreements);
}
void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_muted, bool_t send_ringbacktone){
void linphone_call_start_media_streams(LinphoneCall *call, LinphoneCallState next_state){
LinphoneCore *lc=call->core;
bool_t use_arc=linphone_core_adaptive_rate_control_enabled(lc);
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);
#endif
switch (next_state){
case LinphoneCallIncomingEarlyMedia:
if (linphone_core_get_remote_ringback_tone(lc)){
call->playing_ringbacktone = TRUE;
}
case LinphoneCallOutgoingEarlyMedia:
if (!call->params->real_early_media){
call->all_muted = TRUE;
}
break;
default:
call->playing_ringbacktone = FALSE;
call->all_muted = FALSE;
break;
}
call->current_params->audio_codec = NULL;
call->current_params->video_codec = NULL;
@ -2957,18 +3000,16 @@ 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,all_inputs_muted||call->audio_muted,send_ringbacktone,use_arc);
linphone_call_start_audio_stream(call, next_state, 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,all_inputs_muted);
linphone_call_start_video_stream(call, next_state);
}
call->all_muted=all_inputs_muted;
call->playing_ringbacktone=send_ringbacktone;
call->up_bw=linphone_core_get_upload_bandwidth(lc);
/*might be moved in audio/video stream_start*/
@ -3087,6 +3128,17 @@ static void linphone_call_log_fill_stats(LinphoneCallLog *log, MediaStream *st){
}
}
static void update_rtp_stats(LinphoneCall *call, int stream_index) {
if (stream_index >= linphone_call_get_stream_count(call)) {
return;
}
if (call->sessions[stream_index].rtp_session) {
const rtp_stats_t *stats = rtp_session_get_stats(call->sessions[stream_index].rtp_session);
memcpy(&call->stats[stream_index].rtp_stats, stats, sizeof(*stats));
}
}
static void linphone_call_stop_audio_stream(LinphoneCall *call) {
if (call->audiostream!=NULL) {
linphone_reporting_update_media_info(call, LINPHONE_CALL_STATS_AUDIO);
@ -3106,6 +3158,7 @@ static void linphone_call_stop_audio_stream(LinphoneCall *call) {
linphone_call_remove_from_conf(call);
}
audio_stream_stop(call->audiostream);
update_rtp_stats(call, 0);
rtp_session_unregister_event_queue(call->sessions[0].rtp_session, call->audiostream_app_evq);
ortp_ev_queue_flush(call->audiostream_app_evq);
ortp_ev_queue_destroy(call->audiostream_app_evq);
@ -3123,6 +3176,7 @@ static void linphone_call_stop_video_stream(LinphoneCall *call) {
linphone_call_log_fill_stats(call->log,(MediaStream*)call->videostream);
video_stream_stop(call->videostream);
call->videostream=NULL;
update_rtp_stats(call, 1);
rtp_session_unregister_event_queue(call->sessions[1].rtp_session, call->videostream_app_evq);
ortp_ev_queue_flush(call->videostream_app_evq);
ortp_ev_queue_destroy(call->videostream_app_evq);
@ -3316,19 +3370,20 @@ float linphone_call_get_average_quality(LinphoneCall *call){
return -1;
}
static void update_local_stats(LinphoneCallStats *stats, MediaStream *stream){
const MSQualityIndicator *qi=media_stream_get_quality_indicator(stream);
static void update_local_stats(LinphoneCallStats *stats, MediaStream *stream) {
const MSQualityIndicator *qi = media_stream_get_quality_indicator(stream);
if (qi) {
stats->local_late_rate=ms_quality_indicator_get_local_late_rate(qi);
stats->local_loss_rate=ms_quality_indicator_get_local_loss_rate(qi);
}
media_stream_get_local_rtp_stats(stream, &stats->rtp_stats);
}
/**
* Access last known statistics for audio stream, for a given call.
**/
const LinphoneCallStats *linphone_call_get_audio_stats(LinphoneCall *call) {
LinphoneCallStats *stats=&call->stats[LINPHONE_CALL_STATS_AUDIO];
LinphoneCallStats *stats = &call->stats[LINPHONE_CALL_STATS_AUDIO];
if (call->audiostream){
update_local_stats(stats,(MediaStream*)call->audiostream);
}
@ -3339,7 +3394,7 @@ const LinphoneCallStats *linphone_call_get_audio_stats(LinphoneCall *call) {
* Access last known statistics for video stream, for a given call.
**/
const LinphoneCallStats *linphone_call_get_video_stats(LinphoneCall *call) {
LinphoneCallStats *stats=&call->stats[LINPHONE_CALL_STATS_VIDEO];
LinphoneCallStats *stats = &call->stats[LINPHONE_CALL_STATS_VIDEO];
if (call->videostream){
update_local_stats(stats,(MediaStream*)call->videostream);
}
@ -3473,18 +3528,14 @@ float linphone_call_stats_get_receiver_interarrival_jitter(const LinphoneCallSta
return (float)report_block_get_interarrival_jitter(rrb) / (float)pt->clock_rate;
}
rtp_stats_t linphone_call_stats_get_rtp_stats(const LinphoneCallStats *stats, LinphoneCall *call) {
rtp_stats_t linphone_call_stats_get_rtp_stats(const LinphoneCallStats *stats) {
rtp_stats_t rtp_stats;
memset(&rtp_stats, 0, sizeof(rtp_stats));
if (stats && call) {
if (stats->type == LINPHONE_CALL_STATS_AUDIO && call->audiostream != NULL)
audio_stream_get_local_rtp_stats(call->audiostream, &rtp_stats);
#ifdef VIDEO_ENABLED
else if (call->videostream != NULL)
video_stream_get_local_rtp_stats(call->videostream, &rtp_stats);
#endif
if (stats) {
memcpy(&rtp_stats, &stats->rtp_stats, sizeof(stats->rtp_stats));
}
return rtp_stats;
}
@ -3493,7 +3544,7 @@ rtp_stats_t linphone_call_stats_get_rtp_stats(const LinphoneCallStats *stats, Li
* @return The cumulative number of late packets
**/
uint64_t linphone_call_stats_get_late_packets_cumulative_number(const LinphoneCallStats *stats, LinphoneCall *call) {
return linphone_call_stats_get_rtp_stats(stats, call).outoftime;
return linphone_call_stats_get_rtp_stats(stats).outoftime;
}
/**
@ -3577,12 +3628,13 @@ static void report_bandwidth(LinphoneCall *call, MediaStream *as, MediaStream *v
call->stats[LINPHONE_CALL_STATS_AUDIO].updated|=LINPHONE_CALL_STATS_PERIODICAL_UPDATE;
linphone_core_notify_call_stats_updated(call->core, call, &call->stats[LINPHONE_CALL_STATS_AUDIO]);
call->stats[LINPHONE_CALL_STATS_AUDIO].updated=0;
update_local_stats(&call->stats[LINPHONE_CALL_STATS_AUDIO], as);
}
if (vs_active) {
call->stats[LINPHONE_CALL_STATS_VIDEO].updated|=LINPHONE_CALL_STATS_PERIODICAL_UPDATE;
linphone_core_notify_call_stats_updated(call->core, call, &call->stats[LINPHONE_CALL_STATS_VIDEO]);
call->stats[LINPHONE_CALL_STATS_VIDEO].updated=0;
update_local_stats(&call->stats[LINPHONE_CALL_STATS_VIDEO], vs);
}
ms_message( "Bandwidth usage for call [%p]:\n"
@ -3601,16 +3653,23 @@ static void report_bandwidth(LinphoneCall *call, MediaStream *as, MediaStream *v
}
static void linphone_core_disconnected(LinphoneCore *lc, LinphoneCall *call){
char temp[256]={0};
static void linphone_call_lost(LinphoneCall *call, LinphoneReason reason){
LinphoneCore *lc = call->core;
char *temp = NULL;
char *from=NULL;
from = linphone_call_get_remote_address_as_string(call);
snprintf(temp,sizeof(temp)-1,"Remote end %s seems to have disconnected, the call is going to be closed.",from ? from : "");
switch(reason){
case LinphoneReasonIOError:
temp = ms_strdup_printf("Call with %s disconnected because of network, it is going to be closed.", from ? from : "?");
break;
default:
temp = ms_strdup_printf("Media connectivity with %s is lost, call is going to be closed.", from ? from : "?");
break;
}
if (from) ms_free(from);
ms_message("On call [%p]: %s",call,temp);
linphone_core_notify_display_warning(lc,temp);
ms_message("LinphoneCall [%p]: %s",call, temp);
linphone_core_notify_display_warning(lc, temp);
linphone_core_terminate_call(lc,call);
linphone_core_play_named_tone(lc,LinphoneToneCallLost);
}
@ -3878,7 +3937,7 @@ void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapse
&& call->audiostream->ms.state==MSStreamStarted && disconnect_timeout>0 )
disconnected=!audio_stream_alive(call->audiostream,disconnect_timeout);
if (disconnected)
linphone_core_disconnected(call->core,call);
linphone_call_lost(call, LinphoneReasonUnknown);
}
void linphone_call_log_completed(LinphoneCall *call){
@ -4129,17 +4188,107 @@ void linphone_call_set_native_video_window_id(LinphoneCall *call, void *id) {
}
#endif
}
#ifdef VIDEO_ENABLED
MSWebCam *linphone_call_get_video_device(const LinphoneCall *call) {
if (call->camera_enabled==FALSE)
if (call->all_muted || call->camera_enabled == FALSE)
return get_nowebcam_device();
else
return call->cam;
return call->core->video_conf.device;
}
#endif
void linphone_call_set_audio_route(LinphoneCall *call, LinphoneAudioRoute route) {
if (call != NULL && call->audiostream != NULL){
audio_stream_set_audio_route(call->audiostream, (MSAudioRoute) route);
}
}
int linphone_call_get_stream_count(LinphoneCall *call) {
// Revisit when multiple media streams will be implemented
#ifdef VIDEO_ENABLED
return 2;
#else
return 1;
#endif
}
MSFormatType linphone_call_get_stream_type(LinphoneCall *call, int stream_index) {
// Revisit when multiple media streams will be implemented
if (stream_index == 0) {
return MSAudio;
}
return MSVideo;
}
RtpTransport* linphone_call_get_meta_rtp_transport(LinphoneCall *call, int stream_index) {
RtpTransport *meta_rtp;
RtpTransport *meta_rtcp;
if (!call || stream_index < 0 || stream_index >= linphone_call_get_stream_count(call)) {
return NULL;
}
rtp_session_get_transports(call->sessions[stream_index].rtp_session, &meta_rtp, &meta_rtcp);
return meta_rtp;
}
RtpTransport* linphone_call_get_meta_rtcp_transport(LinphoneCall *call, int stream_index) {
RtpTransport *meta_rtp;
RtpTransport *meta_rtcp;
if (!call || stream_index < 0 || stream_index >= linphone_call_get_stream_count(call)) {
return NULL;
}
rtp_session_get_transports(call->sessions[stream_index].rtp_session, &meta_rtp, &meta_rtcp);
return meta_rtcp;
}
void linphone_call_set_broken(LinphoneCall *call){
switch(call->state){
/*for all the early states, we prefer to drop the call*/
case LinphoneCallOutgoingInit:
case LinphoneCallOutgoingRinging:
case LinphoneCallOutgoingEarlyMedia:
case LinphoneCallIncomingReceived:
case LinphoneCallIncomingEarlyMedia:
linphone_call_lost(call, LinphoneReasonIOError);
break;
case LinphoneCallStreamsRunning:
case LinphoneCallPaused:
case LinphoneCallPausedByRemote:
call->broken = TRUE;
break;
default:
ms_error("linphone_call_set_broken() unimplemented case.");
break;
}
}
void linphone_call_repair_if_broken(LinphoneCall *call){
LinphoneCallParams *params;
if (!call->broken) return;
/*First, make sure that the proxy from which we received this call, or to which we routed this call is registered*/
if (!call->dest_proxy || linphone_proxy_config_get_state(call->dest_proxy) != LinphoneRegistrationOk) return;
switch (call->state){
case LinphoneCallStreamsRunning:
case LinphoneCallPaused:
case LinphoneCallPausedByRemote:
ms_message("LinphoneCall[%p] is going to be updated (reINVITE) in order to recover from lost connectivity", call);
if (call->ice_session){
ice_session_restart(call->ice_session);
ice_session_set_role(call->ice_session, IR_Controlling);
}
params = linphone_core_create_call_params(call->core, call);
linphone_core_update_call(call->core, call, params);
linphone_call_params_unref(params);
break;
default:
ms_error("linphone_call_resume_if_broken(): don't know what to do in state [%s]", linphone_call_state_to_string(call->state));
break;
}
}

View file

@ -100,7 +100,6 @@ static ortp_mutex_t liblinphone_log_collection_mutex;
static bool_t liblinphone_serialize_logs = FALSE;
static void set_network_reachable(LinphoneCore* lc,bool_t isReachable, time_t curtime);
static void linphone_core_run_hooks(LinphoneCore *lc);
static void linphone_core_free_hooks(LinphoneCore *lc);
#include "enum.h"
#include "contact_providers_priv.h"
@ -931,7 +930,7 @@ static void sip_config_read(LinphoneCore *lc)
if (hostname==NULL)
hostname="unknown-host";
if (username==NULL){
username="toto";
username="linphone";
}
contact=ortp_strdup_printf("sip:%s@%s",username,hostname);
linphone_core_set_primary_contact(lc,contact);
@ -1565,6 +1564,8 @@ static void linphone_core_register_default_codecs(LinphoneCore *lc){
linphone_core_register_payload_type(lc,&payload_type_aal2_g726_24,NULL,FALSE);
linphone_core_register_payload_type(lc,&payload_type_aal2_g726_32,NULL,FALSE);
linphone_core_register_payload_type(lc,&payload_type_aal2_g726_40,NULL,FALSE);
linphone_core_register_payload_type(lc,&payload_type_codec2,NULL,FALSE);
@ -1588,7 +1589,7 @@ static void linphone_core_init(LinphoneCore * lc, const LinphoneCoreVTable *vtab
lc->config=lp_config_ref(config);
lc->data=userdata;
lc->ringstream_autorelease=TRUE;
linphone_task_list_init(&lc->hooks);
memcpy(local_vtable,vtable,sizeof(LinphoneCoreVTable));
_linphone_core_add_listener(lc, local_vtable, TRUE);
@ -2767,7 +2768,7 @@ int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call, const Linph
linphone_call_set_contact_op(call);
linphone_core_stop_dtmf_stream(lc);
linphone_call_make_local_media_description(lc,call);
linphone_call_make_local_media_description(call);
if (lc->ringstream==NULL) {
if (lc->sound_conf.play_sndcard && lc->sound_conf.capt_sndcard){
@ -2923,21 +2924,6 @@ void linphone_configure_op(LinphoneCore *lc, SalOp *op, const LinphoneAddress *d
sal_op_cnx_ip_to_0000_if_sendonly_enable(op,lp_config_get_default_int(lc->config,"sip","cnx_ip_to_0000_if_sendonly_enabled",0)); /*also set in linphone_call_new_incoming*/
}
/**
* Initiates an outgoing call given a destination LinphoneAddress
*
* @ingroup call_control
* @param lc the LinphoneCore object
* @param addr the destination of the call (sip address).
@param params call parameters
*
* The LinphoneAddress can be constructed directly using linphone_address_new(), or
* created by linphone_core_interpret_url().
* The application doesn't own a reference to the returned LinphoneCall object.
* Use linphone_call_ref() to safely keep the LinphoneCall pointer valid within your application.
*
* @return a LinphoneCall object or NULL in case of failure
**/
LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const LinphoneAddress *addr, const LinphoneCallParams *params)
{
const char *from=NULL;
@ -3185,16 +3171,16 @@ int linphone_core_accept_early_media_with_params(LinphoneCore* lc, LinphoneCall*
// if parameters are passed, update the media description
if ( params ) {
linphone_call_set_new_params(call,params);
linphone_call_make_local_media_description ( lc,call );
linphone_call_make_local_media_description (call);
sal_call_set_local_media_description ( call->op,call->localdesc );
sal_op_set_sent_custom_header ( call->op,params->custom_headers );
}
sal_call_notify_ringing(call->op,TRUE);
sal_call_notify_ringing(call->op, TRUE);
linphone_call_set_state(call,LinphoneCallIncomingEarlyMedia,"Incoming call early media");
md=sal_call_get_final_media_description(call->op);
if (md) linphone_core_update_streams(lc,call,md);
if (md) linphone_core_update_streams(lc, call, md, call->state);
return 0;
}else{
ms_error("Bad state %s for linphone_core_accept_early_media_with_params()", linphone_call_state_to_string(call->state));
@ -3223,7 +3209,7 @@ int linphone_core_start_update_call(LinphoneCore *lc, LinphoneCall *call){
linphone_call_fill_media_multicast_addr(call);
if (!no_user_consent) linphone_call_make_local_media_description(lc,call);
if (!no_user_consent) linphone_call_make_local_media_description(call);
#ifdef BUILD_UPNP
if(call->upnp_session != NULL) {
linphone_core_update_local_media_description_from_upnp(call->localdesc, call->upnp_session);
@ -3285,6 +3271,8 @@ int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const Linpho
nextstate=LinphoneCallEarlyUpdating;
break;
case LinphoneCallStreamsRunning:
case LinphoneCallPaused:
case LinphoneCallPausedByRemote:
nextstate=LinphoneCallUpdating;
break;
default:
@ -3293,6 +3281,7 @@ int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const Linpho
}
if (params!=NULL){
call->broken = FALSE;
linphone_call_set_state(call,nextstate,"Updating call");
#if defined(VIDEO_ENABLED) && defined(BUILD_UPNP)
has_video = call->params->has_video;
@ -3332,7 +3321,7 @@ int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const Linpho
#endif //defined(VIDEO_ENABLED) && defined(BUILD_UPNP)
if ((err = linphone_core_start_update_call(lc, call)) && call->state!=initial_state) {
/*Restore initial state*/
linphone_call_set_state(call,initial_state,NULL);
linphone_call_set_state(call,initial_state,"Restore initial state");
}
}else{
@ -3341,7 +3330,7 @@ int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const Linpho
video_stream_set_sent_video_size(call->videostream,linphone_core_get_preferred_video_size(lc));
video_stream_set_fps(call->videostream, linphone_core_get_preferred_framerate(lc));
if (call->camera_enabled && call->videostream->cam!=lc->video_conf.device){
video_stream_change_camera(call->videostream,call->cam = lc->video_conf.device);
video_stream_change_camera(call->videostream, lc->video_conf.device);
}else video_stream_update_video_params(call->videostream);
}
#endif
@ -3363,14 +3352,23 @@ int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const Linpho
* Then, when the user responds to dialog prompt, it becomes possible to call linphone_core_accept_call_update() to answer
* the reINVITE, with eventually video enabled in the LinphoneCallParams argument.
*
* @return 0 if successful, -1 if the linphone_core_defer_call_update() was done outside a #LinphoneCallUpdatedByRemote notification, which is illegal.
* The #LinphoneCallUpdatedByRemote notification can also arrive when receiving an INVITE without SDP. In such case, an unchanged offer is made
* in the 200Ok, and when the ACK containing the SDP answer is received, #LinphoneCallUpdatedByRemote is triggered to notify the application of possible
* changes in the media session. However in such case defering the update has no meaning since we just generating an offer.
*
* @return 0 if successful, -1 if the linphone_core_defer_call_update() was done outside a valid #LinphoneCallUpdatedByRemote notification.
**/
int linphone_core_defer_call_update(LinphoneCore *lc, LinphoneCall *call){
if (call->state==LinphoneCallUpdatedByRemote){
if (call->expect_media_in_ack){
ms_error("linphone_core_defer_call_update() is not possible during a late offer incoming reINVITE (INVITE without SDP)");
return -1;
}
call->defer_update=TRUE;
return 0;
}else{
ms_error("linphone_core_defer_call_update() not done in state LinphoneCallUpdatedByRemote");
}
ms_error("linphone_core_defer_call_update() not done in state LinphoneCallUpdatedByRemote");
return -1;
}
@ -3382,7 +3380,7 @@ int linphone_core_start_accept_call_update(LinphoneCore *lc, LinphoneCall *call,
return 0;
}
}
linphone_call_make_local_media_description(lc,call);
linphone_call_make_local_media_description(call);
linphone_call_update_remote_session_id_and_ver(call);
linphone_call_stop_ice_for_inactive_streams(call);
@ -3390,7 +3388,7 @@ int linphone_core_start_accept_call_update(LinphoneCore *lc, LinphoneCall *call,
sal_call_accept(call->op);
md=sal_call_get_final_media_description(call->op);
if (md && !sal_media_description_empty(md)){
linphone_core_update_streams (lc,call,md);
linphone_core_update_streams(lc, call, md, next_state);
linphone_call_fix_call_parameters(call);
}
linphone_call_set_state(call,next_state,state_info);
@ -3599,7 +3597,7 @@ int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call,
linphone_call_set_compatible_incoming_call_parameters(call, md);
}
linphone_call_prepare_ice(call,TRUE);
linphone_call_make_local_media_description(lc,call);
linphone_call_make_local_media_description(call);
sal_call_set_local_media_description(call->op,call->localdesc);
sal_op_set_sent_custom_header(call->op,params->custom_headers);
}
@ -3625,7 +3623,7 @@ int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call,
linphone_call_set_state(call,LinphoneCallConnected,"Connected");
new_md=sal_call_get_final_media_description(call->op);
if (new_md){
linphone_core_update_streams(lc, call, new_md);
linphone_core_update_streams(lc, call, new_md, LinphoneCallStreamsRunning);
linphone_call_fix_call_parameters(call);
linphone_call_set_state(call,LinphoneCallStreamsRunning,"Connected (streams running)");
}else call->expect_media_in_ack=TRUE;
@ -3809,10 +3807,8 @@ int linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call){
}
/* Internal version that does not play tone indication*/
int _linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call)
{
int _linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call){
const char *subject=NULL;
LinphoneCallParams *params;
if (call->state!=LinphoneCallStreamsRunning && call->state!=LinphoneCallPausedByRemote){
ms_warning("Cannot pause this call, it is not active.");
@ -3826,15 +3822,8 @@ int _linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call)
ms_error("No reason to pause this call, it is already paused or inactive.");
return -1;
}
params = linphone_call_params_copy(call->params);
linphone_call_params_set_audio_direction(params, LinphoneMediaDirectionSendOnly);
if (lp_config_get_int(lc->config, "sip", "inactive_video_on_pause", 0)) {
linphone_call_params_set_video_direction(params, LinphoneMediaDirectionInactive);
} else {
linphone_call_params_set_video_direction(params, LinphoneMediaDirectionSendOnly);
}
linphone_call_make_local_media_description_with_params(lc, call, params);
linphone_call_params_unref(params);
linphone_call_set_state(call, LinphoneCallPausing, "Pausing call");
linphone_call_make_local_media_description(call);
#ifdef BUILD_UPNP
if(call->upnp_session != NULL) {
linphone_core_update_local_media_description_from_upnp(call->localdesc, call->upnp_session);
@ -3848,7 +3837,6 @@ int _linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call)
linphone_core_notify_display_status(lc,_("Pausing the current call..."));
if (call->audiostream || call->videostream)
linphone_call_stop_media_streams (call);
linphone_call_set_state(call,LinphoneCallPausing,"Pausing call");
call->paused_by_app=FALSE;
return 0;
}
@ -3915,7 +3903,7 @@ int linphone_core_resume_call(LinphoneCore *lc, LinphoneCall *call){
prevents the participants to hear it while the 200OK comes back.*/
if (call->audiostream) audio_stream_play(call->audiostream, NULL);
linphone_call_make_local_media_description(lc,call);
linphone_call_make_local_media_description(call);
#ifdef BUILD_UPNP
if(call->upnp_session != NULL) {
linphone_core_update_local_media_description_from_upnp(call->localdesc, call->upnp_session);
@ -6108,7 +6096,7 @@ LpConfig * linphone_core_create_lp_config(LinphoneCore *lc, const char *filename
static void linphone_core_uninit(LinphoneCore *lc)
{
linphone_core_free_hooks(lc);
linphone_task_list_free(&lc->hooks);
lc->video_conf.show_local = FALSE;
while(lc->calls)
@ -6213,6 +6201,8 @@ static void set_network_reachable(LinphoneCore* lc,bool_t isReachable, time_t cu
if (!lc->network_reachable){
linphone_core_invalidate_friend_subscriptions(lc);
sal_reset_transports(lc->sal);
/*mark all calls as broken, so that they can be either dropped immediately or restaured when network will be back*/
ms_list_for_each(lc->calls, (MSIterateFunc) linphone_call_set_broken);
}else{
linphone_core_resolve_stun_server(lc);
}
@ -6570,47 +6560,18 @@ void linphone_core_set_max_calls(LinphoneCore *lc, int max) {
lc->max_calls=max;
}
typedef struct Hook{
LinphoneCoreIterateHook fun;
void *data;
}Hook;
static Hook *hook_new(LinphoneCoreIterateHook hook, void *hook_data){
Hook *h=ms_new0(Hook,1);
h->fun=hook;
h->data=hook_data;
return h;
}
static void hook_invoke(Hook *h){
h->fun(h->data);
}
void linphone_core_add_iterate_hook(LinphoneCore *lc, LinphoneCoreIterateHook hook, void *hook_data){
lc->hooks=ms_list_append(lc->hooks,hook_new(hook,hook_data));
linphone_task_list_add(&lc->hooks, hook, hook_data);
}
static void linphone_core_run_hooks(LinphoneCore *lc){
ms_list_for_each(lc->hooks,(void (*)(void*))hook_invoke);
}
static void linphone_core_free_hooks(LinphoneCore *lc){
ms_list_for_each(lc->hooks,(void (*)(void*))ms_free);
ms_list_free(lc->hooks);
lc->hooks=NULL;
linphone_task_list_run(&lc->hooks);
}
void linphone_core_remove_iterate_hook(LinphoneCore *lc, LinphoneCoreIterateHook hook, void *hook_data){
MSList *elem;
for(elem=lc->hooks;elem!=NULL;elem=elem->next){
Hook *h=(Hook*)elem->data;
if (h->fun==hook && h->data==hook_data){
lc->hooks = ms_list_remove_link(lc->hooks,elem);
ms_free(h);
return;
}
}
ms_error("linphone_core_remove_iterate_hook(): No such hook found.");
linphone_task_list_remove(&lc->hooks, hook, hook_data);
}
void linphone_core_set_zrtp_secrets_file(LinphoneCore *lc, const char* file){

View file

@ -551,6 +551,7 @@ struct _LinphoneCallStats {
int updated; /**< Tell which RTCP packet has been updated (received_rtcp or sent_rtcp). Can be either LINPHONE_CALL_STATS_RECEIVED_RTCP_UPDATE or LINPHONE_CALL_STATS_SENT_RTCP_UPDATE */
float rtcp_download_bandwidth; /**<RTCP download bandwidth measurement of received stream, expressed in kbit/s, including IP/UDP/RTP headers*/
float rtcp_upload_bandwidth; /**<RTCP download bandwidth measurement of sent stream, expressed in kbit/s, including IP/UDP/RTP headers*/
rtp_stats_t rtp_stats; /**< RTP stats */
};
/**
@ -563,7 +564,7 @@ LINPHONE_PUBLIC float linphone_call_stats_get_sender_loss_rate(const LinphoneCal
LINPHONE_PUBLIC float linphone_call_stats_get_receiver_loss_rate(const LinphoneCallStats *stats);
LINPHONE_PUBLIC float linphone_call_stats_get_sender_interarrival_jitter(const LinphoneCallStats *stats, LinphoneCall *call);
LINPHONE_PUBLIC float linphone_call_stats_get_receiver_interarrival_jitter(const LinphoneCallStats *stats, LinphoneCall *call);
LINPHONE_PUBLIC rtp_stats_t linphone_call_stats_get_rtp_stats(const LinphoneCallStats *statss, LinphoneCall *call);
LINPHONE_PUBLIC rtp_stats_t linphone_call_stats_get_rtp_stats(const LinphoneCallStats *statss);
LINPHONE_PUBLIC uint64_t linphone_call_stats_get_late_packets_cumulative_number(const LinphoneCallStats *stats, LinphoneCall *call);
LINPHONE_PUBLIC float linphone_call_stats_get_download_bandwidth(const LinphoneCallStats *stats);
LINPHONE_PUBLIC float linphone_call_stats_get_upload_bandwidth(const LinphoneCallStats *stats);
@ -722,7 +723,7 @@ LINPHONE_PUBLIC const char *linphone_call_get_remote_contact(LinphoneCall *call)
/**
* Get the mesured playback volume level.
*
*
* @param call The call.
* @return float Volume level in percentage.
*/
@ -730,7 +731,7 @@ LINPHONE_PUBLIC float linphone_call_get_play_volume(LinphoneCall *call);
/**
* Get the mesured record volume level
*
*
* @param call The call.
* @return float Volume level in percentage.
*/
@ -740,7 +741,7 @@ LINPHONE_PUBLIC float linphone_call_get_record_volume(LinphoneCall *call);
* Get speaker volume gain.
* If the sound backend supports it, the returned gain is equal to the gain set
* with the system mixer.
*
*
* @param call The call.
* @return Percenatge of the max supported volume gain. Valid values are in [ 0.0 : 1.0 ].
* In case of failure, a negative value is returned
@ -750,7 +751,7 @@ LINPHONE_PUBLIC float linphone_call_get_speaker_volume_gain(const LinphoneCall *
/**
* Set speaker volume gain.
* If the sound backend supports it, the new gain will synchronized with the system mixer.
*
*
* @param call The call.
* @param volume Percentage of the max supported gain. Valid values are in [ 0.0 : 1.0 ].
*/
@ -760,7 +761,7 @@ LINPHONE_PUBLIC void linphone_call_set_speaker_volume_gain(LinphoneCall *call, f
* Get microphone volume gain.
* If the sound backend supports it, the returned gain is equal to the gain set
* with the system mixer.
*
*
* @param call The call.
* @return double Percenatge of the max supported volume gain. Valid values are in [ 0.0 : 1.0 ].
* In case of failure, a negative value is returned
@ -770,7 +771,7 @@ LINPHONE_PUBLIC float linphone_call_get_microphone_volume_gain(const LinphoneCal
/**
* Set microphone volume gain.
* If the sound backend supports it, the new gain will synchronized with the system mixer.
*
*
* @param call The call.
* @param volume Percentage of the max supported gain. Valid values are in [ 0.0 : 1.0 ].
*/
@ -895,10 +896,46 @@ typedef enum _LinphoneAudioRoute LinphoneAudioRoute;
* Change the playback output device (currently only used for blackberry)
* @param call
* @param route the wanted audio route (earpiece, speaker, ...)
*
*
* @ingroup call_control
**/
LINPHONE_PUBLIC void linphone_call_set_audio_route(LinphoneCall *call, LinphoneAudioRoute route);
LINPHONE_PUBLIC void linphone_call_set_audio_route(LinphoneCall *call, LinphoneAudioRoute route);
/**
* Returns the number of stream for the given call.
* Currently there is only two (Audio, Video), but later there will be more.
* @param call
*
* @return 2
**/
LINPHONE_PUBLIC int linphone_call_get_stream_count(LinphoneCall *call);
/**
* Returns the type of stream for the given stream index.
* @param call
* @param stream_index
*
* @return MsAudio if stream_index = 0, MsVideo otherwise
**/
LINPHONE_PUBLIC MSFormatType linphone_call_get_stream_type(LinphoneCall *call, int stream_index);
/**
* Returns the meta rtp transport for the given stream index.
* @param call
* @param stream_index
*
* @return a pointer to the meta rtp transport if it exists, NULL otherwise
**/
LINPHONE_PUBLIC RtpTransport* linphone_call_get_meta_rtp_transport(LinphoneCall *call, int stream_index);
/**
* Returns the meta rtcp transport for the given stream index.
* @param call
* @param stream_index
*
* @return a pointer to the meta rtcp transport if it exists, NULL otherwise
**/
LINPHONE_PUBLIC RtpTransport* linphone_call_get_meta_rtcp_transport(LinphoneCall *call, int stream_index);
/*keep this in sync with mediastreamer2/msvolume.h*/
@ -1195,24 +1232,11 @@ typedef LinphoneBuffer * (*LinphoneChatMessageCbsFileTransferSendCb)(LinphoneCha
typedef void (*LinphoneChatMessageCbsFileTransferProgressIndicationCb)(LinphoneChatMessage *message, const LinphoneContent* content, size_t offset, size_t total);
LINPHONE_PUBLIC void linphone_core_set_chat_database_path(LinphoneCore *lc, const char *path);
/**
* Create a new chat room for messaging from a sip uri like sip:joe@sip.linphone.org
* @param lc #LinphoneCore object
* @param to destination address for messages
* @return #LinphoneChatRoom where messaging can take place.
* @deprecated Use linphone_core_get_chat_room() or linphone_core_get_chat_room_from_uri() instead.
*/
LINPHONE_PUBLIC LinphoneChatRoom * linphone_core_create_chat_room(LinphoneCore *lc, const char *to);
/**
* Create a new chat room for messaging from a sip uri like sip:joe@sip.linphone.org if not already existing, else return exisiting one
* @param lc #LinphoneCore object
* @param to destination address for messages
* @return #LinphoneChatRoom where messaging can take place.
* @deprecated Use linphone_core_get_chat_room() or linphone_core_get_chat_room_from_uri() instead.
*/
LINPHONE_PUBLIC LinphoneChatRoom * linphone_core_get_or_create_chat_room(LinphoneCore *lc, const char *to);
/**
* Get a chat room whose peer is the supplied address. If it does not exist yet, it will be created.
* No reference is transfered to the application. The LinphoneCore keeps a reference on the chat room.
* @param lc the linphone core
* @param addr a linphone address.
* @return #LinphoneChatRoom where messaging can take place.
@ -1220,11 +1244,20 @@ LINPHONE_PUBLIC LinphoneChatRoom * linphone_core_get_or_create_chat_room(Linphon
LINPHONE_PUBLIC LinphoneChatRoom *linphone_core_get_chat_room(LinphoneCore *lc, const LinphoneAddress *addr);
/**
* Get a chat room for messaging from a sip uri like sip:joe@sip.linphone.org. If it does not exist yet, it will be created.
* No reference is transfered to the application. The LinphoneCore keeps a reference on the chat room.
* @param lc The linphone core
* @param to The destination address for messages.
* @return #LinphoneChatRoom where messaging can take place.
**/
LINPHONE_PUBLIC LinphoneChatRoom *linphone_core_get_chat_room_from_uri(LinphoneCore *lc, const char *to);
/**
* Removes a chatroom including all message history from the LinphoneCore.
* @param lc The linphone core
* @param to The chatroom.
**/
LINPHONE_PUBLIC void linphone_core_delete_chat_room(LinphoneCore *lc, LinphoneChatRoom *cr);
/**
* Inconditionnaly disable incoming chat messages.
* @param lc the core
@ -1296,17 +1329,17 @@ LINPHONE_PUBLIC void linphone_chat_room_set_user_data(LinphoneChatRoom *cr, void
/**
* Create a message attached to a dedicated chat room with a particular content.
* Use #linphone_chat_room_send_message2 to initiate the transfer
* Use #linphone_chat_room_send_message to initiate the transfer
* @param cr the chat room.
* @param initial_content #LinphoneContent initial content. #LinphoneCoreVTable.file_transfer_send is invoked later to notify file transfer progress and collect next chunk of the message if #LinphoneContent.data is NULL.
* @return a new #LinphoneChatMessage
*/
LINPHONE_PUBLIC LinphoneChatMessage* linphone_chat_room_create_file_transfer_message(LinphoneChatRoom *cr, LinphoneContent* initial_content);
LINPHONE_PUBLIC LinphoneChatMessage* linphone_chat_room_create_file_transfer_message(LinphoneChatRoom *cr, const LinphoneContent* initial_content);
LINPHONE_PUBLIC const LinphoneAddress* linphone_chat_room_get_peer_address(LinphoneChatRoom *cr);
/**
* Send a message to peer member of this chat room.
* @deprecated linphone_chat_room_send_message2() gives more control on the message expedition.
* @deprecated Use linphone_chat_room_send_chat_message() instead.
* @param cr #LinphoneChatRoom object
* @param msg message to be sent
*/
@ -1319,6 +1352,7 @@ LINPHONE_PUBLIC void linphone_chat_room_send_message(LinphoneChatRoom *cr, const
* @param ud user data for the status cb.
* @deprecated Use linphone_chat_room_send_chat_message() instead.
* @note The LinphoneChatMessage must not be destroyed until the the callback is called.
* The LinphoneChatMessage reference is transfered to the function and thus doesn't need to be unref'd by the application.
*/
LINPHONE_PUBLIC void linphone_chat_room_send_message2(LinphoneChatRoom *cr, LinphoneChatMessage* msg,LinphoneChatMessageStateChangedCb status_cb,void* ud);
/**
@ -1327,6 +1361,7 @@ LINPHONE_PUBLIC void linphone_chat_room_send_message2(LinphoneChatRoom *cr, Linp
* @param[in] msg LinphoneChatMessage object
* The state of the message sending will be notified via the callbacks defined in the LinphoneChatMessageCbs object that can be obtained
* by calling linphone_chat_message_get_callbacks().
* The LinphoneChatMessage reference is transfered to the function and thus doesn't need to be unref'd by the application.
*/
LINPHONE_PUBLIC void linphone_chat_room_send_chat_message(LinphoneChatRoom *cr, LinphoneChatMessage *msg);
@ -1405,7 +1440,7 @@ LINPHONE_PUBLIC LinphoneCore* linphone_chat_room_get_core(LinphoneChatRoom *cr);
* @param[in] lc #LinphoneCore object
* @return \mslist{LinphoneChatRoom}
**/
LINPHONE_PUBLIC MSList* linphone_core_get_chat_rooms(LinphoneCore *lc);
LINPHONE_PUBLIC const MSList* linphone_core_get_chat_rooms(LinphoneCore *lc);
LINPHONE_PUBLIC unsigned int linphone_chat_message_store(LinphoneChatMessage *msg);
/**
@ -1546,7 +1581,7 @@ LINPHONE_PUBLIC void linphone_chat_message_set_user_data(LinphoneChatMessage* me
**/
LINPHONE_PUBLIC LinphoneChatRoom* linphone_chat_message_get_chat_room(LinphoneChatMessage *msg);
/**
* get peer address \link linphone_core_create_chat_room() associated to \endlink this #LinphoneChatRoom
* get peer address \link linphone_core_get_chat_room() associated to \endlink this #LinphoneChatRoom
* @param cr #LinphoneChatRoom object
* @return #LinphoneAddress peer address
*/
@ -1731,7 +1766,7 @@ typedef void (*LinphoneCoreGlobalStateChangedCb)(LinphoneCore *lc, LinphoneGloba
* @param lc the LinphoneCore
* @param call the call object whose state is changed.
* @param cstate the new state of the call
* @param message an informational message about the state.
* @param message a non NULL informational message about the state.
*/
typedef void (*LinphoneCoreCallStateChangedCb)(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate, const char *message);
@ -2282,6 +2317,21 @@ LINPHONE_PUBLIC LinphoneCall * linphone_core_invite_address(LinphoneCore *lc, co
LINPHONE_PUBLIC LinphoneCall * linphone_core_invite_with_params(LinphoneCore *lc, const char *url, const LinphoneCallParams *params);
/**
* Initiates an outgoing call given a destination LinphoneAddress
*
* @ingroup call_control
* @param lc the LinphoneCore object
* @param addr the destination of the call (sip address).
@param params call parameters
*
* The LinphoneAddress can be constructed directly using linphone_address_new(), or
* created by linphone_core_interpret_url().
* The application doesn't own a reference to the returned LinphoneCall object.
* Use linphone_call_ref() to safely keep the LinphoneCall pointer valid within your application.
*
* @return a LinphoneCall object or NULL in case of failure
**/
LINPHONE_PUBLIC LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const LinphoneAddress *addr, const LinphoneCallParams *params);
LINPHONE_PUBLIC int linphone_core_transfer_call(LinphoneCore *lc, LinphoneCall *call, const char *refer_to);
@ -2539,7 +2589,7 @@ LINPHONE_PUBLIC int linphone_core_get_upload_ptime(LinphoneCore *lc);
* @param[in] timeout_ms The SIP transport timeout in milliseconds.
* @ingroup media_parameters
*/
void linphone_core_set_sip_transport_timeout(LinphoneCore *lc, int timeout_ms);
LINPHONE_PUBLIC void linphone_core_set_sip_transport_timeout(LinphoneCore *lc, int timeout_ms);
/**
* Get the SIP transport timeout.

View file

@ -58,6 +58,9 @@ extern "C" void libmsbcg729_init();
#ifdef HAVE_WEBRTC
extern "C" void libmswebrtc_init();
#endif
#ifdef HAVE_CODEC2
extern "C" void libmscodec2_init();
#endif
#include <belle-sip/wakelock.h>
#endif /*ANDROID*/
@ -148,7 +151,7 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *ajvm, void *reserved)
{
#ifdef ANDROID
ms_set_jvm(ajvm);
#endif /*ANDROID*/
jvm=ajvm;
return JNI_VERSION_1_2;
@ -1142,6 +1145,9 @@ extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_newLinphoneCore(JNIEnv*
#ifdef HAVE_WEBRTC
libmswebrtc_init();
#endif
#ifdef HAVE_CODEC2
libmscodec2_init();
#endif
jobject core = env->NewGlobalRef(thiz);
jlong nativePtr = (jlong)linphone_core_new(vTable, userConfig, factoryConfig, core);
@ -1990,7 +1996,7 @@ extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_needsEchoCalibration
if(sound_description != NULL && sound_description == &genericSoundDeviceDescriptor){
return TRUE;
}
if (ms_snd_card_get_capabilities(sndcard) & MS_SND_CARD_CAP_BUILTIN_ECHO_CANCELLER) return FALSE;
if (ms_snd_card_get_minimal_latency(sndcard) != 0) return FALSE;
return TRUE;
@ -2176,16 +2182,17 @@ extern "C" jstring Java_org_linphone_core_LinphoneProxyConfigImpl_normalizePhone
if (jnumber == 0) {
ms_error("cannot normalized null number");
}
char * normalized_phone;
const char* number = env->GetStringUTFChars(jnumber, NULL);
int len = env->GetStringLength(jnumber);
if (len == 0) {
ms_warning("cannot normalize empty number");
return jnumber;
}
char targetBuff[2*len];// returned number can be greater than origin (specially in case of prefix insertion
linphone_proxy_config_normalize_number((LinphoneProxyConfig*)proxyCfg,number,targetBuff,sizeof(targetBuff));
jstring normalizedNumber = env->NewStringUTF(targetBuff);
normalized_phone = linphone_proxy_config_normalize_phone_number((LinphoneProxyConfig*)proxyCfg,number);
jstring normalizedNumber = env->NewStringUTF(normalized_phone ? normalized_phone : number);
env->ReleaseStringUTFChars(jnumber, number);
ms_free(normalized_phone);
return normalizedNumber;
}
extern "C" jint Java_org_linphone_core_LinphoneProxyConfigImpl_lookupCCCFromIso(JNIEnv* env, jobject thiz, jlong proxyCfg, jstring jiso) {
@ -3277,7 +3284,7 @@ static void message_state_changed(LinphoneChatMessage* msg, LinphoneChatMessageS
jmethodID method = env->GetMethodID(clazz, "onLinphoneChatMessageStateChanged","(Lorg/linphone/core/LinphoneChatMessage;Lorg/linphone/core/LinphoneChatMessage$State;)V");
jobject jmessage = getChatMessage(env, msg);
env->DeleteLocalRef(clazz);
jclass chatMessageStateClass = (jclass)env->FindClass("org/linphone/core/LinphoneChatMessage$State");
jmethodID chatMessageStateFromIntId = env->GetStaticMethodID(chatMessageStateClass, "fromInt","(I)Lorg/linphone/core/LinphoneChatMessage$State;");
env->CallVoidMethod(listener, method, jmessage, env->CallStaticObjectMethod(chatMessageStateClass, chatMessageStateFromIntId, (jint)state));
@ -3320,7 +3327,7 @@ static void file_transfer_recv(LinphoneChatMessage *msg, const LinphoneContent*
jclass clazz = (jclass) env->GetObjectClass(listener);
jmethodID method = env->GetMethodID(clazz, "onLinphoneChatMessageFileTransferReceived", "(Lorg/linphone/core/LinphoneChatMessage;Lorg/linphone/core/LinphoneContent;Lorg/linphone/core/LinphoneBuffer;)V");
env->DeleteLocalRef(clazz);
jobject jmessage = getChatMessage(env, msg);
jobject jbuffer = buffer ? create_java_linphone_buffer(env, buffer) : NULL;
jobject jcontent = content ? create_java_linphone_content(env, content) : NULL;
@ -3346,7 +3353,7 @@ static LinphoneBuffer* file_transfer_send(LinphoneChatMessage *msg, const Linph
jclass clazz = (jclass) env->GetObjectClass(listener);
jmethodID method = env->GetMethodID(clazz, "onLinphoneChatMessageFileTransferSent","(Lorg/linphone/core/LinphoneChatMessage;Lorg/linphone/core/LinphoneContent;IILorg/linphone/core/LinphoneBuffer;)V");
env->DeleteLocalRef(clazz);
jobject jmessage = getChatMessage(env, msg);
jobject jbuffer = create_java_linphone_buffer(env, NULL);
jobject jcontent = content ? create_java_linphone_content(env, content) : NULL;
@ -3354,7 +3361,7 @@ static LinphoneBuffer* file_transfer_send(LinphoneChatMessage *msg, const Linph
if (jcontent) {
env->DeleteLocalRef(jcontent);
}
buffer = create_c_linphone_buffer_from_java_linphone_buffer(env, jbuffer);
env->DeleteLocalRef(jbuffer);
return buffer;
@ -3364,7 +3371,7 @@ extern "C" void Java_org_linphone_core_LinphoneChatMessageImpl_setListener(JNIEn
jobject listener = env->NewGlobalRef(jlistener);
LinphoneChatMessage *message = (LinphoneChatMessage *)ptr;
LinphoneChatMessageCbs *cbs;
message->cb_ud = listener;
cbs = linphone_chat_message_get_callbacks(message);
linphone_chat_message_cbs_set_msg_state_changed(cbs, message_state_changed);
@ -4643,7 +4650,7 @@ static jobject create_java_linphone_content(JNIEnv *env, const LinphoneContent *
}
jobject jobj = env->NewObject(contentClass, ctor, jname, jtype, jsubtype, jdata, jencoding, jsize);
env->DeleteLocalRef(contentClass);
env->DeleteLocalRef(jtype);
env->DeleteLocalRef(jsubtype);
@ -4653,7 +4660,7 @@ static jobject create_java_linphone_content(JNIEnv *env, const LinphoneContent *
if (jname) {
env->DeleteLocalRef(jname);
}
return jobj;
}
@ -4689,7 +4696,7 @@ static LinphoneBuffer* create_c_linphone_buffer_from_java_linphone_buffer(JNIEnv
bufferClass = (jclass)env->FindClass("org/linphone/core/LinphoneBufferImpl");
getSizeMethod = env->GetMethodID(bufferClass, "getSize", "()I");
getDataMethod = env->GetMethodID(bufferClass, "getContent", "()[B");
jsize = env->CallIntMethod(jbuffer, getSizeMethod);
jdata = env->CallObjectMethod(jbuffer, getDataMethod);
jcontent = reinterpret_cast<jbyteArray>(jdata);
@ -4699,7 +4706,7 @@ static LinphoneBuffer* create_c_linphone_buffer_from_java_linphone_buffer(JNIEnv
env->ReleaseByteArrayElements(jcontent, (jbyte*)content, JNI_ABORT);
}
env->DeleteLocalRef(bufferClass);
return buffer;
}

View file

@ -94,6 +94,20 @@ static void fetch_content_from_database(sqlite3 *db, LinphoneChatMessage *messag
sqlite3_free(buf);
}
// Called when fetching all conversations from database
static int callback_all(void *data, int argc, char **argv, char **colName){
LinphoneCore* lc = (LinphoneCore*) data;
char* address = argv[0];
LinphoneAddress *addr = linphone_address_new(address);
if (addr){
linphone_core_get_chat_room(lc, addr);
linphone_address_destroy(addr);
}
return 0;
}
/* DB layout:
* | 0 | storage_id
* | 1 | localContact
@ -106,13 +120,12 @@ static void fetch_content_from_database(sqlite3 *db, LinphoneChatMessage *messag
* | 8 | external body url
* | 9 | utc timestamp
* | 10 | app data text
* | 11 | linphone content
* | 11 | linphone content id
*/
static void create_chat_message(char **argv, void *data){
static int create_chat_message(void *data, int argc, char **argv, char **colName){
LinphoneChatRoom *cr = (LinphoneChatRoom *)data;
LinphoneAddress *from;
LinphoneAddress *to;
unsigned int storage_id = atoi(argv[0]);
// check if the message exists in the transient list, in which case we should return that one.
@ -136,17 +149,12 @@ static void create_chat_message(char **argv, void *data){
linphone_address_destroy(to);
}
if( argv[9] != NULL ){
new_message->time = (time_t)atol(argv[9]);
} else {
new_message->time = time(NULL);
}
new_message->time = (time_t)atol(argv[9]);
new_message->is_read=atoi(argv[6]);
new_message->state=atoi(argv[7]);
new_message->storage_id=storage_id;
new_message->external_body_url= argv[8] ? ms_strdup(argv[8]) : NULL;
new_message->appdata = argv[10]? ms_strdup(argv[10]) : NULL;
new_message->external_body_url= ms_strdup(argv[8]);
new_message->appdata = ms_strdup(argv[10]);
if (argv[11] != NULL) {
int id = atoi(argv[11]);
@ -156,25 +164,14 @@ static void create_chat_message(char **argv, void *data){
}
}
cr->messages_hist=ms_list_prepend(cr->messages_hist,new_message);
}
// Called when fetching all conversations from database
static int callback_all(void *data, int argc, char **argv, char **colName){
LinphoneCore* lc = (LinphoneCore*) data;
char* address = argv[0];
linphone_core_get_or_create_chat_room(lc, address);
return 0;
}
static int callback(void *data, int argc, char **argv, char **colName){
create_chat_message(argv,data);
return 0;
}
void linphone_sql_request_message(sqlite3 *db,const char *stmt,LinphoneChatRoom *cr){
char* errmsg=NULL;
int ret;
ret=sqlite3_exec(db,stmt,callback,cr,&errmsg);
ret=sqlite3_exec(db,stmt,create_chat_message,cr,&errmsg);
if(ret != SQLITE_OK) {
ms_error("Error in creation: %s.", errmsg);
sqlite3_free(errmsg);
@ -287,7 +284,7 @@ void linphone_chat_room_mark_as_read(LinphoneChatRoom *cr){
char *buf;
if (lc->db==NULL) return ;
// optimization: do not modify the database if no message is marked as unread
if(linphone_chat_room_get_unread_messages_count(cr) == 0) return;
@ -297,7 +294,7 @@ void linphone_chat_room_mark_as_read(LinphoneChatRoom *cr){
linphone_sql_request(lc->db,buf);
sqlite3_free(buf);
ms_free(peer);
cr->unread_count = 0;
}
@ -321,7 +318,7 @@ static int linphone_chat_room_get_messages_count(LinphoneChatRoom *cr, bool_t un
int returnValue;
if (lc->db==NULL) return 0;
// optimization: do not read database if the count is already available in memory
if(unread_only && cr->unread_count >= 0) return cr->unread_count;
@ -336,11 +333,11 @@ static int linphone_chat_room_get_messages_count(LinphoneChatRoom *cr, bool_t un
sqlite3_finalize(selectStatement);
sqlite3_free(buf);
ms_free(peer);
/* no need to test the sign of cr->unread_count here
* because it has been tested above */
if(unread_only) cr->unread_count = numrows;
return numrows;
}
@ -361,7 +358,7 @@ void linphone_chat_room_delete_message(LinphoneChatRoom *cr, LinphoneChatMessage
buf=sqlite3_mprintf("DELETE FROM history WHERE id = %i;", msg->storage_id);
linphone_sql_request(lc->db,buf);
sqlite3_free(buf);
if(cr->unread_count >= 0 && !msg->is_read) {
assert(cr->unread_count > 0);
cr->unread_count--;
@ -380,7 +377,7 @@ void linphone_chat_room_delete_history(LinphoneChatRoom *cr){
linphone_sql_request(lc->db,buf);
sqlite3_free(buf);
ms_free(peer);
if(cr->unread_count > 0) cr->unread_count = 0;
}
@ -618,7 +615,7 @@ static int _linphone_sqlite3_open(const char *db_file, sqlite3 **db) {
#elif defined(_WIN32)
int ret;
wchar_t db_file_utf16[MAX_PATH_SIZE];
ret = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, db_file, MAX_PATH_SIZE, db_file_utf16, MAX_PATH_SIZE);
ret = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, db_file, -1, db_file_utf16, MAX_PATH_SIZE);
if(ret == 0) db_file_utf16[0] = '\0';
return sqlite3_open16(db_file_utf16, db);
#else
@ -627,7 +624,7 @@ static int _linphone_sqlite3_open(const char *db_file, sqlite3 **db) {
char *inbuf=db_file_locale, *outbuf=db_file_utf8;
size_t inbyteleft = MAX_PATH_SIZE, outbyteleft = MAX_PATH_SIZE;
iconv_t cb;
strncpy(db_file_locale, db_file, MAX_PATH_SIZE-1);
cb = iconv_open("UTF-8", nl_langinfo(CODESET));
if(cb != (iconv_t)-1) {

View file

@ -1788,3 +1788,48 @@ const char *linphone_tunnel_mode_to_string(LinphoneTunnelMode mode) {
return "invalid";
}
typedef struct Hook{
LinphoneCoreIterateHook fun;
void *data;
}Hook;
void linphone_task_list_init(LinphoneTaskList *t){
t->hooks = NULL;
}
static Hook *hook_new(LinphoneCoreIterateHook hook, void *hook_data){
Hook *h=ms_new0(Hook,1);
h->fun=hook;
h->data=hook_data;
return h;
}
static void hook_invoke(Hook *h){
h->fun(h->data);
}
void linphone_task_list_add(LinphoneTaskList *t, LinphoneCoreIterateHook hook, void *hook_data){
t->hooks = ms_list_append(t->hooks,hook_new(hook,hook_data));
}
void linphone_task_list_remove(LinphoneTaskList *t, LinphoneCoreIterateHook hook, void *hook_data){
MSList *elem;
for(elem=t->hooks;elem!=NULL;elem=elem->next){
Hook *h=(Hook*)elem->data;
if (h->fun==hook && h->data==hook_data){
t->hooks = ms_list_remove_link(t->hooks,elem);
ms_free(h);
return;
}
}
ms_error("linphone_task_list_remove(): No such hook found.");
}
void linphone_task_list_run(LinphoneTaskList *t){
ms_list_for_each(t->hooks,(void (*)(void*))hook_invoke);
}
void linphone_task_list_free(LinphoneTaskList *t){
t->hooks = ms_list_free_with_data(t->hooks, (void (*)(void*))ms_free);
}

View file

@ -1445,7 +1445,7 @@ static LinphonePresenceModel * process_pidf_xml_presence_notification(xmlparsing
void linphone_core_add_subscriber(LinphoneCore *lc, const char *subscriber, SalOp *op){
LinphoneFriend *fl=linphone_friend_new_with_address(subscriber);
if (fl==NULL) return ;
fl->insub=op;
linphone_friend_add_incoming_subscription(fl, op);
linphone_friend_set_inc_subscribe_policy(fl,LinphoneSPAccept);
fl->inc_subscribe_pending=TRUE;
lc->subscribers=ms_list_append(lc->subscribers,(void *)fl);
@ -1468,9 +1468,7 @@ void linphone_core_notify_all_friends(LinphoneCore *lc, LinphonePresenceModel *p
if (activity_str != NULL) ms_free(activity_str);
for(elem=lc->friends;elem!=NULL;elem=elem->next){
LinphoneFriend *lf=(LinphoneFriend *)elem->data;
if (lf->insub){
linphone_friend_notify(lf,presence);
}
linphone_friend_notify(lf,presence);
}
}
@ -1478,26 +1476,15 @@ void linphone_subscription_new(LinphoneCore *lc, SalOp *op, const char *from){
LinphoneFriend *lf=NULL;
char *tmp;
LinphoneAddress *uri;
LinphoneProxyConfig *cfg;
uri=linphone_address_new(from);
linphone_address_clean(uri);
tmp=linphone_address_as_string(uri);
ms_message("Receiving new subscription from %s.",from);
cfg=linphone_core_lookup_known_proxy(lc,uri);
if (cfg!=NULL){
if (cfg->op){
if (sal_op_get_contact_address(cfg->op)) {
sal_op_set_contact_address (op,sal_op_get_contact_address(cfg->op));
ms_message("Contact for next subscribe answer has been fixed using proxy "/*to %s",fixed_contact*/);
}
}
}
/* check if we answer to this subscription */
if (linphone_find_friend_by_address(lc->friends,uri,&lf)!=NULL){
lf->insub=op;
linphone_friend_add_incoming_subscription(lf, op);
lf->inc_subscribe_pending=TRUE;
sal_subscribe_accept(op);
linphone_friend_done(lf); /*this will do all necessary actions */
@ -1904,7 +1891,7 @@ void linphone_subscription_closed(LinphoneCore *lc, SalOp *op){
lf=linphone_find_friend_by_inc_subscribe(lc->friends,op);
sal_op_release(op);
if (lf!=NULL){
lf->insub=NULL;
linphone_friend_remove_incoming_subscription(lf, op);
}else{
ms_warning("Receiving unsuscribe for unknown in-subscribtion from %s", sal_op_get_from(op));
}

View file

@ -79,7 +79,7 @@ extern "C" {
#endif
#include <libintl.h>
#ifndef _
#define _(String) dgettext(GETTEXT_PACKAGE,String)
#endif
@ -295,7 +295,6 @@ struct _LinphoneCall{
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 */
MSWebCam *cam; /*webcam use for this call*/
bool_t refer_pending;
bool_t expect_media_in_ack;
bool_t audio_muted;
@ -312,6 +311,7 @@ struct _LinphoneCall{
bool_t record_active;
bool_t paused_by_app;
bool_t broken; /*set to TRUE when the call is in broken state due to network disconnection or transport */
};
BELLE_SIP_DECLARE_VPTR(LinphoneCall);
@ -356,6 +356,8 @@ const LinphoneAddress* linphone_proxy_config_get_service_route(const LinphonePro
void linphone_friend_close_subscriptions(LinphoneFriend *lf);
void linphone_friend_update_subscribes(LinphoneFriend *fr, LinphoneProxyConfig *cfg, bool_t only_when_registered);
void linphone_friend_notify(LinphoneFriend *lf, LinphonePresenceModel *presence);
void linphone_friend_add_incoming_subscription(LinphoneFriend *lf, SalOp *op);
void linphone_friend_remove_incoming_subscription(LinphoneFriend *lf, SalOp *op);
LinphoneFriend *linphone_find_friend_by_inc_subscribe(MSList *l, SalOp *op);
LinphoneFriend *linphone_find_friend_by_out_subscribe(MSList *l, SalOp *op);
MSList *linphone_find_friend_by_address(MSList *fl, const LinphoneAddress *addr, LinphoneFriend **lf);
@ -450,7 +452,7 @@ void linphone_call_fix_call_parameters(LinphoneCall *call);
void linphone_call_init_audio_stream(LinphoneCall *call);
void linphone_call_init_video_stream(LinphoneCall *call);
void linphone_call_init_media_streams(LinphoneCall *call);
void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_muted, bool_t send_ringbacktone);
void linphone_call_start_media_streams(LinphoneCall *call, LinphoneCallState target_state);
void linphone_call_start_media_streams_for_ice_gathering(LinphoneCall *call);
void linphone_call_stop_media_streams(LinphoneCall *call);
void linphone_call_delete_ice_session(LinphoneCall *call);
@ -586,7 +588,7 @@ struct _LinphoneFriend{
belle_sip_object_t base;
void *user_data;
LinphoneAddress *uri;
SalOp *insub;
MSList *insubs; /*list of SalOp. There can be multiple instances of a same Friend that subscribe to our presence*/
SalOp *outsub;
LinphoneSubscribePolicy pol;
LinphonePresenceModel *presence;
@ -757,6 +759,16 @@ const char *linphone_core_get_tone_file(const LinphoneCore *lc, LinphoneToneID i
int _linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params, LinphoneCallState next_state, const char *state_info);
typedef struct _LinphoneConference LinphoneConference;
typedef struct _LinphoneTaskList{
MSList *hooks;
}LinphoneTaskList;
void linphone_task_list_init(LinphoneTaskList *t);
void linphone_task_list_add(LinphoneTaskList *t, LinphoneCoreIterateHook hook, void *hook_data);
void linphone_task_list_remove(LinphoneTaskList *t, LinphoneCoreIterateHook hook, void *hook_data);
void linphone_task_list_run(LinphoneTaskList *t);
void linphone_task_list_free(LinphoneTaskList *t);
struct _LinphoneCore
{
MSList* vtable_refs;
@ -804,7 +816,7 @@ struct _LinphoneCore
void *preview_window_id;
time_t netup_time; /*time when network went reachable */
struct _EcCalibrator *ecc;
MSList *hooks;
LinphoneTaskList hooks; /*tasks periodically executed in linphone_core_iterate()*/
LinphoneConference conf_ctx;
char* zrtp_secrets_cache;
char* user_certificates_path;
@ -888,11 +900,11 @@ int linphone_core_set_as_current_call(LinphoneCore *lc, LinphoneCall *call);
int linphone_core_get_calls_nb(const LinphoneCore *lc);
void linphone_core_set_state(LinphoneCore *lc, LinphoneGlobalState gstate, const char *message);
void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *call);
void linphone_call_make_local_media_description(LinphoneCall *call);
void linphone_call_make_local_media_description_with_params(LinphoneCore *lc, LinphoneCall *call, LinphoneCallParams *params);
void linphone_call_increment_local_media_description(LinphoneCall *call);
void linphone_call_fill_media_multicast_addr(LinphoneCall *call);
void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMediaDescription *new_md);
void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMediaDescription *new_md, LinphoneCallState target_state);
bool_t linphone_core_is_payload_type_usable_for_bandwidth(LinphoneCore *lc, const PayloadType *pt, int bandwidth_limit);
@ -924,6 +936,8 @@ LinphoneEcCalibratorStatus ec_calibrator_get_status(EcCalibrator *ecc);
void ec_calibrator_destroy(EcCalibrator *ecc);
void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapsed);
void linphone_call_set_broken(LinphoneCall *call);
void linphone_call_repair_if_broken(LinphoneCall *call);
void linphone_core_preempt_sound_resources(LinphoneCore *lc);
int _linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call);

View file

@ -848,101 +848,21 @@ static char *flatten_number(const char *number){
return result;
}
static void replace_plus_with_icp(const char *src, char *dest, size_t destlen, const char *icp){
int i=0;
if (icp && src[0]=='+' && (destlen>(i=strlen(icp))) ){
src++;
strncpy(dest, icp, destlen);
}
for(;(i<destlen-1) && *src!='\0';++i){
dest[i]=*src;
src++;
}
dest[i]='\0';
}
static void replace_icp_with_plus(const char *src, char *dest, size_t destlen, const char *icp){
int i=0;
if (strstr(src, icp) == src){
dest[0]='+';
i++;
}
strncpy(dest+i, src+strlen(icp), destlen-i-1);
}
static char* replace_plus_with_icp_new(char *phone, const char* icp){
static char* replace_plus_with_icp(char *phone, const char* icp){
return (icp && phone[0]=='+') ? ms_strdup_printf("%s%s", icp, phone+1) : ms_strdup(phone);
}
static char* replace_icp_with_plus_new(char *phone, const char *icp){
static char* replace_icp_with_plus(char *phone, const char *icp){
return (strstr(phone, icp) == phone) ? ms_strdup_printf("+%s", phone+strlen(icp)) : ms_strdup(phone);
}
bool_t linphone_proxy_config_normalize_number(LinphoneProxyConfig *proxy, const char *username, char *result, size_t result_len){
bool_t ret;
LinphoneProxyConfig *tmpproxy = proxy ? proxy : linphone_proxy_config_new();
char * normalized_phone = linphone_proxy_config_normalize_phone_number(proxy, username);
const char * output = normalized_phone ? normalized_phone : username;
memset(result, 0, result_len);
if (linphone_proxy_config_is_phone_number(tmpproxy, username)){
dial_plan_t dialplan = {0};
char *flatten=flatten_number(username);
ms_debug("Flattened number is '%s'",flatten);
/*username does not contain a dial prefix nor the tmpproxy, nothing else to do*/
if (tmpproxy->dial_prefix==NULL || tmpproxy->dial_prefix[0]=='\0'){
strncpy(result,flatten,result_len-1);
} else {
lookup_dial_plan_by_ccc(tmpproxy->dial_prefix,&dialplan);
ms_debug("Using dial plan '%s'",dialplan.country);
/* the number has international prefix or +, so nothing to do*/
if (flatten[0]=='+'){
ms_debug("Prefix already present.");
/*eventually replace the plus by the international calling prefix of the country*/
if (tmpproxy->dial_escape_plus) {
replace_plus_with_icp(flatten,result,result_len,dialplan.icp);
}else{
strncpy(result, flatten, result_len-1);
}
}else if (strstr(flatten,dialplan.icp)==flatten){
if (tmpproxy->dial_escape_plus){
strncpy(result, flatten, result_len-1);
}else{
replace_icp_with_plus(flatten, result, result_len, dialplan.icp);
}
}else{
int numlen;
int i=0;
int skip;
numlen=strlen(flatten);
/*keep at most national number significant digits */
skip=numlen-dialplan.nnl;
if (skip<0) skip=0;
/*first prepend international calling prefix or +*/
if (tmpproxy->dial_escape_plus){
strncpy(result,dialplan.icp,result_len);
i+=strlen(dialplan.icp);
}else{
strncpy(result,"+",result_len);
i+=1;
}
/*add prefix*/
if (result_len-i>strlen(dialplan.ccc)){
strcpy(result+i,dialplan.ccc);
i+=strlen(dialplan.ccc);
}
/*add user digits */
strncpy(result+i,flatten+skip,result_len-i-1);
}
}
ms_free(flatten);
ret = TRUE;
} else {
strncpy(result,username,result_len-1);
ret = FALSE;
}
if (proxy==NULL) ms_free(tmpproxy);
return ret;
memcpy(result, output, MIN(strlen(output) + 1, result_len));
ms_free(normalized_phone);
return output != username;
}
char* linphone_proxy_config_normalize_phone_number(LinphoneProxyConfig *proxy, const char *username) {
@ -961,9 +881,9 @@ char* linphone_proxy_config_normalize_phone_number(LinphoneProxyConfig *proxy, c
if (flatten[0]=='+'||strstr(flatten,dialplan.icp)==flatten){
ms_debug("Prefix already present.");
if (tmpproxy->dial_escape_plus) {
result = replace_plus_with_icp_new(flatten,dialplan.icp);
result = replace_plus_with_icp(flatten,dialplan.icp);
} else {
result = replace_icp_with_plus_new(flatten,dialplan.icp);
result = replace_icp_with_plus(flatten,dialplan.icp);
}
}else{
/*0. keep at most national number significant digits */
@ -1003,7 +923,7 @@ LinphoneAddress* linphone_proxy_config_normalize_sip_uri(LinphoneProxyConfig *pr
char *tmpurl;
LinphoneAddress *uri;
if (*username=='\0') return NULL;
if (!username || *username=='\0') return NULL;
if (is_enum(username,&enum_domain)){
if (proxy) {
@ -1036,16 +956,16 @@ LinphoneAddress* linphone_proxy_config_normalize_sip_uri(LinphoneProxyConfig *pr
}
if (proxy!=NULL){
/* append the proxy domain suffix */
/* append the proxy domain suffix but remove any custom parameters/headers */
LinphoneAddress *uri=linphone_address_clone(linphone_proxy_config_get_identity_address(proxy));
linphone_address_clean(uri);
if (uri==NULL){
return NULL;
} else {
char normalized_username[128];
char* normalized_phone = linphone_proxy_config_normalize_phone_number(proxy,username);
linphone_address_set_display_name(uri,NULL);
linphone_proxy_config_normalize_number(proxy,username,normalized_username,
sizeof(normalized_username));
linphone_address_set_username(uri,normalized_username);
linphone_address_set_username(uri,normalized_phone ? normalized_phone : username);
ms_free(normalized_phone);
return _linphone_core_destroy_addr_if_not_sip(uri);
}
} else {
@ -1511,8 +1431,13 @@ void linphone_proxy_config_set_state(LinphoneProxyConfig *cfg, LinphoneRegistrat
if (update_friends){
linphone_core_update_friends_subscriptions(lc,cfg,TRUE);
}
if (lc)
if (lc){
linphone_core_notify_registration_state_changed(lc,cfg,state,message);
if (lc->calls && lp_config_get_int(lc->config, "sip", "repair_broken_calls", 1)){
/*if we are registered and there were broken calls due to a past network disconnection, attempt to repair them*/
ms_list_for_each(lc->calls, (MSIterateFunc) linphone_call_repair_if_broken);
}
}
} else {
/*state already reported*/
}

View file

@ -160,26 +160,27 @@ static bool_t is_null_address(const char *addr){
/*check for the presence of at least one stream with requested direction */
static bool_t has_dir(const SalMediaDescription *md, SalStreamDir stream_dir){
int i;
/* we are looking for at least one stream with requested direction, inactive streams are ignored*/
for(i=0;i<md->nb_streams;++i){
const SalStreamDescription *ss=&md->streams[i];
if (!sal_stream_description_active(ss)) continue;
if (ss->dir==stream_dir) return TRUE;
/*compatibility check for phones that only used the null address and no attributes */
if (ss->dir==SalStreamSendRecv && stream_dir==SalStreamSendOnly && (is_null_address(md->addr) || is_null_address(ss->rtp_addr)))
if (ss->dir==stream_dir) {
return TRUE;
}
/*compatibility check for phones that only used the null address and no attributes */
if (ss->dir==SalStreamSendRecv && stream_dir==SalStreamSendOnly && (is_null_address(md->addr) || is_null_address(ss->rtp_addr))){
return TRUE;
}
}
return FALSE;
}
bool_t sal_media_description_has_dir(const SalMediaDescription *md, SalStreamDir stream_dir){
if (stream_dir==SalStreamRecvOnly){
if (has_dir(md,SalStreamSendOnly) || has_dir(md,SalStreamSendRecv)) return FALSE;
else return TRUE;
return has_dir(md, SalStreamRecvOnly) && !(has_dir(md,SalStreamSendOnly) || has_dir(md,SalStreamSendRecv));
}else if (stream_dir==SalStreamSendOnly){
if (has_dir(md,SalStreamRecvOnly) || has_dir(md,SalStreamSendRecv)) return FALSE;
else return TRUE;
return has_dir(md, SalStreamSendOnly) && !(has_dir(md,SalStreamRecvOnly) || has_dir(md,SalStreamSendRecv));
}else if (stream_dir==SalStreamSendRecv){
return has_dir(md,SalStreamSendRecv);
}else{

View file

@ -1,104 +0,0 @@
/*
linphone
Copyright (C) 2010 Simon MORLAT (simon.morlat@linphone.org)
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/* Linphone Sound Daemon: is a lightweight utility to play sounds to speaker during a conversation.
This is useful for embedded platforms, where sound apis are not performant enough to allow
simultaneous sound access.
This file is a test program that plays several sound files and places a call simultatenously.
*/
#include "linphonecore_utils.h"
static void play_finished(LsdPlayer *p){
const char *filename=(const char *)lsd_player_get_user_pointer (p);
ms_message("Playing of %s is finished.",filename);
if (!lsd_player_loop_enabled (p)){
linphone_sound_daemon_release_player (lsd_player_get_daemon(p),p);
}
}
static void wait_a_bit(LinphoneCore *lc, int seconds){
time_t orig=ms_time(NULL);
while(ms_time(NULL)-orig<seconds){
/* we need to call iterate to receive notifications */
linphone_core_iterate(lc);
ms_usleep (50000);
}
}
int main(int argc, char *argv[]){
LinphoneCore *lc;
LinphoneCoreVTable vtable={0};
LinphoneSoundDaemon *lsd;
LsdPlayer *p;
linphone_core_enable_logs(stdout);
lc=linphone_core_new(&vtable,NULL,NULL,NULL);
lsd=linphone_sound_daemon_new (NULL,44100,1);
linphone_core_use_sound_daemon(lc,lsd);
/* start a play */
p=linphone_sound_daemon_get_player(lsd);
lsd_player_set_callback (p,play_finished);
lsd_player_set_user_pointer (p,"share/hello8000.wav");
lsd_player_play (p,"share/hello8000.wav");
wait_a_bit (lc,2);
/*start another one */
p=linphone_sound_daemon_get_player(lsd);
lsd_player_set_callback (p,play_finished);
lsd_player_set_user_pointer (p,"share/hello16000.wav");
lsd_player_enable_loop (p,TRUE);
lsd_player_play (p,"share/hello16000.wav");
/* after a few seconds decrease the volume */
wait_a_bit (lc,3);
lsd_player_set_gain (p,0.3);
wait_a_bit(lc,5);
/*now play some stereo music*/
p=linphone_sound_daemon_get_player(lsd);
lsd_player_set_callback (p,play_finished);
lsd_player_set_user_pointer (p,"share/rings/rock.wav");
lsd_player_play(p,"share/rings/rock.wav");
wait_a_bit(lc,2);
/*now play some stereo music at 22khz in order to test
stereo resampling */
p=linphone_sound_daemon_get_player(lsd);
lsd_player_set_callback (p,play_finished);
lsd_player_set_user_pointer (p,"share/rings/bigben.wav");
lsd_player_play(p,"share/rings/bigben.wav");
wait_a_bit(lc,6);
/* now place an outgoing call if sip address argument is given */
if (argc>1){
linphone_core_invite(lc,argv[1]);
wait_a_bit(lc,10);
linphone_core_terminate_call(lc,NULL);
}
linphone_core_use_sound_daemon(lc,NULL);
linphone_sound_daemon_destroy(lsd);
linphone_core_destroy(lc);
return 0;
}

View file

@ -1,48 +0,0 @@
/*
linphone
Copyright (C) 2012 Belledonne Communications SARL
Author: Simon MORLAT (simon.morlat@linphone.org)
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "linphonecore.h"
#include "linphonecore_utils.h"
int main(int argc , char *argv[]){
LinphoneProxyConfig *cfg;
char normalized_number[32];
if (argc<2){
fprintf(stderr,"Usage:\n%s <phone number> [<country code>] [--escape-plus]\nReturns normalized number.", argv[0]);
return -1;
}
linphone_core_enable_logs(stderr);
cfg=linphone_proxy_config_new();
if (argc>2)
linphone_proxy_config_set_dial_prefix(cfg,argv[2]);
if (argc>3 && strcmp(argv[3],"--escape-plus")==0)
linphone_proxy_config_set_dial_escape_plus(cfg,TRUE);
linphone_proxy_config_normalize_number(cfg,argv[1],normalized_number,sizeof(normalized_number));
printf("Normalized number is %s\n",normalized_number);
/*check extracted ccc*/
if (linphone_dial_plan_lookup_ccc_from_e164(normalized_number) != atoi(linphone_proxy_config_get_dial_prefix(cfg))) {
printf("Error ccc [%i] not correctly parsed\n",linphone_dial_plan_lookup_ccc_from_e164(normalized_number));
} else {
printf("Extracted ccc is [%i] \n",linphone_dial_plan_lookup_ccc_from_e164(normalized_number));
}
return 0;
}

View file

@ -97,6 +97,10 @@ if(ENABLE_NOTIFY)
target_link_libraries(linphone-gtk ${NOTIFY_LIBRARIES})
endif()
if (HAVE_LIBUDEV_H)
target_link_libraries(linphone-gtk udev)
endif()
install(TARGETS linphone-gtk
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib

View file

@ -280,8 +280,7 @@ void linphone_gtk_call_log_update(GtkWidget *w){
LinphoneFriend *lf=NULL;
int duration=linphone_call_log_get_duration(cl);
time_t start_date_time=linphone_call_log_get_start_date(cl);
GdkPixbuf *incoming;
GdkPixbuf *outgoing;
GdkPixbuf *pbuf;
#if GLIB_CHECK_VERSION(2,26,0)
if (start_date_time){
@ -346,14 +345,13 @@ void linphone_gtk_call_log_update(GtkWidget *w){
g_free(seconds);
if (start_date) g_free(start_date);
gtk_tree_store_append (store,&iter,NULL);
incoming = create_pixbuf("call_status_incoming.png");
outgoing = create_pixbuf("call_status_outgoing.png");
pbuf = linphone_call_log_get_dir(cl)==LinphoneCallOutgoing ? create_pixbuf("call_status_outgoing.png") : create_pixbuf("call_status_incoming.png");
gtk_tree_store_set (store,&iter,
0, linphone_call_log_get_dir(cl)==LinphoneCallOutgoing ? outgoing : incoming,
0, pbuf,
1, headtxt,2,cl,-1);
gtk_tree_store_append (store,&iter2,&iter);
gtk_tree_store_set (store,&iter2,1,logtxt,-1);
g_object_unref(pbuf);
ms_free(addr);
g_free(logtxt);
g_free(headtxt);

View file

@ -31,13 +31,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define CONFIG_FILE ".linphone-history.db"
const char *linphone_gtk_message_storage_get_db_file(const char *filename){
char *linphone_gtk_message_storage_get_db_file(const char *filename){
const int path_max=1024;
static char *db_file=NULL;
char *db_file=NULL;
if (db_file) return db_file;
db_file=(char *)malloc(path_max*sizeof(char));
db_file=(char *)g_malloc(path_max*sizeof(char));
if (filename==NULL) filename=CONFIG_FILE;
/*try accessing a local file first if exists*/
if (access(CONFIG_FILE,F_OK)==0){
@ -66,7 +64,6 @@ void linphone_gtk_quit_chatroom(LinphoneChatRoom *cr) {
GtkWidget *friendlist=linphone_gtk_get_widget(main_window,"contact_list");
GtkWidget *w=g_object_get_data(G_OBJECT(friendlist),"chatview");
gchar *from;
GHashTable *table=g_object_get_data(G_OBJECT(w),"table");
g_return_if_fail(w!=NULL);
gtk_notebook_remove_page(GTK_NOTEBOOK(nb),gtk_notebook_page_num(GTK_NOTEBOOK(nb),w));
@ -78,7 +75,6 @@ void linphone_gtk_quit_chatroom(LinphoneChatRoom *cr) {
g_object_set_data(G_OBJECT(w),"from_message",NULL);
g_free(from);
}
g_hash_table_destroy(table);
g_object_set_data(G_OBJECT(w),"cr",NULL);
linphone_gtk_friend_list_set_active_address(NULL);
gtk_widget_destroy(w);
@ -192,7 +188,7 @@ void linphone_gtk_push_text(GtkWidget *w, const LinphoneAddress *from,
int tnow_year;
gtk_text_buffer_get_end_iter(buffer, &iter);
if(g_strcmp0(from_message,from_str)!=0){
if (g_strcmp0(from_message,from_str)!=0){
gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, get_display_name(from), -1,
"from", me ? "me" : NULL, NULL);
gtk_text_buffer_insert_with_tags_by_name(buffer,&iter, " : ", -1,
@ -200,8 +196,8 @@ void linphone_gtk_push_text(GtkWidget *w, const LinphoneAddress *from,
gtk_text_buffer_insert(buffer,&iter,"\n",-1);
g_free(from_message);
g_object_set_data(G_OBJECT(w),"from_message",g_strdup(from_str));
ms_free(from_str);
}
ms_free(from_str);
link_start_mark = gtk_text_buffer_create_mark(buffer, NULL, &iter, TRUE);
gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, linphone_chat_message_get_text(msg), -1,
@ -217,7 +213,7 @@ void linphone_gtk_push_text(GtkWidget *w, const LinphoneAddress *from,
g_hash_table_insert(table,(gpointer)msg,GINT_TO_POINTER(gtk_text_iter_get_line(&iter)));
gtk_text_buffer_insert_with_tags_by_name(buffer,&iter,"Sending ..",-1,
"status", me ? "me" : NULL, NULL);
g_object_set_data(G_OBJECT(w),"table",table);
//g_object_set_data(G_OBJECT(w),"table",table);
break;
case LinphoneChatMessageStateDelivered:
tnow=time(NULL);
@ -295,7 +291,7 @@ void update_chat_state_message(LinphoneChatMessageState state,LinphoneChatMessag
}
gtk_text_buffer_insert_with_tags_by_name(b,&iter,result,-1,
"status", "me", NULL);
g_object_set_data(G_OBJECT(page),"table",table);
//g_object_set_data(G_OBJECT(page),"table",table);
}
}
@ -350,7 +346,7 @@ void linphone_gtk_free_list(MSList *messages){
}
void display_history_message(GtkWidget *chat_view,MSList *messages,const LinphoneAddress *with){
if(messages != NULL){
if (messages != NULL){
MSList *it;
char *from_str;
char *with_str;
@ -363,14 +359,15 @@ void display_history_message(GtkWidget *chat_view,MSList *messages,const Linphon
linphone_chat_message_get_from(msg),
strcmp(from_str,with_str)==0? FALSE : TRUE,
linphone_chat_message_get_chat_room(msg),msg,TRUE);
ms_free(from_str);
ms_free(with_str);
}
tmp=g_object_get_data(G_OBJECT(chat_view),"from_message");
if (tmp){
g_object_set_data(G_OBJECT(chat_view),"from_message",NULL);
g_free(tmp);
}
ms_free(from_str);
ms_free(with_str);
linphone_gtk_free_list(messages);
}
}
@ -411,12 +408,7 @@ static gboolean link_event_handler(GtkTextTag *tag, GObject *text_view,GdkEvent
gtk_text_iter_forward_to_tag_toggle(&uri_end, tag);
uri = gtk_text_iter_get_slice(&uri_begin, &uri_end);
if(((GdkEventButton *)event)->button == 1) {
GError *error = NULL;
gtk_show_uri(NULL, uri, gdk_event_get_time(event), &error);
if(error) {
g_warning("Could not open %s from chat: %s", uri, error->message);
g_error_free(error);
}
linphone_gtk_open_browser(uri);
} else if(((GdkEventButton *)event)->button == 3) {
GtkMenu *menu = GTK_MENU(g_object_get_data(text_view, "link_ctx_menu"));
g_object_set_data_full(G_OBJECT(menu), "uri", g_strdup(uri), g_free);
@ -504,7 +496,7 @@ GtkWidget* linphone_gtk_init_chatroom(LinphoneChatRoom *cr, const LinphoneAddres
table=g_hash_table_new_full(g_direct_hash,g_direct_equal,NULL,NULL);
g_object_set_data(G_OBJECT(chat_view),"cr",cr);
g_object_set_data(G_OBJECT(chat_view),"from_message",NULL);
g_object_set_data(G_OBJECT(chat_view),"table",table);
g_object_set_data_full(G_OBJECT(chat_view),"table",table,(GDestroyNotify)g_hash_table_destroy);
gtk_text_buffer_create_tag(
gtk_text_view_get_buffer(GTK_TEXT_VIEW(text)),
@ -560,9 +552,7 @@ GtkWidget* linphone_gtk_init_chatroom(LinphoneChatRoom *cr, const LinphoneAddres
}
LinphoneChatRoom * linphone_gtk_create_chatroom(const LinphoneAddress *with){
char *tmp=linphone_address_as_string(with);
LinphoneChatRoom *cr=linphone_core_get_or_create_chat_room(linphone_gtk_get_core(),tmp);
ms_free(tmp);
LinphoneChatRoom *cr=linphone_core_get_chat_room(linphone_gtk_get_core(), with);
return cr;
}

View file

@ -216,9 +216,7 @@ static gboolean grab_focus(GtkWidget *w){
void linphone_gtk_friend_list_set_active_address(const LinphoneAddress *addr){
GtkWidget *w=linphone_gtk_get_main_window();
GtkWidget *friendlist=linphone_gtk_get_widget(w,"contact_list");
LinphoneAddress *old_addr=(LinphoneAddress*)g_object_get_data(G_OBJECT(friendlist),"from");
g_object_set_data(G_OBJECT(friendlist),"from", addr ? linphone_address_clone(addr) : NULL);
if (old_addr) linphone_address_unref(old_addr);
g_object_set_data_full(G_OBJECT(friendlist),"from", addr ? linphone_address_clone(addr) : NULL, (GDestroyNotify)linphone_address_destroy);
}
const LinphoneAddress *linphone_gtk_friend_list_get_active_address(void){

View file

@ -29,7 +29,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "linphone.h"
gboolean linphone_gtk_use_in_call_view(){
static int val=-1;
if (val==-1) val=linphone_gtk_get_ui_config_int("use_incall_view",1);
@ -360,10 +359,49 @@ void linphone_gtk_enable_video_button(LinphoneCall *call, gboolean sensitive, gb
gtk_widget_set_visible(GTK_WIDGET(button),sensitive);
}
typedef enum { VOLUME_CTRL_PLAYBACK, VOLUME_CTRL_RECORD } VolumeControlType;
static void volume_control_value_changed(GtkScaleButton *button, gdouble value, gpointer user_data) {
LinphoneCall *call = (LinphoneCall *)g_object_get_data(G_OBJECT(button), "call");
VolumeControlType type = (VolumeControlType)g_object_get_data(G_OBJECT(button), "type");
if(type == VOLUME_CTRL_PLAYBACK) {
linphone_call_set_speaker_volume_gain(call, value);
} else if(type == VOLUME_CTRL_RECORD) {
linphone_call_set_microphone_volume_gain(call, value);
}
}
static void volume_control_button_update_value(GtkWidget *widget) {
LinphoneCall *call = (LinphoneCall *)g_object_get_data(G_OBJECT(widget), "call");
VolumeControlType type = (VolumeControlType)g_object_get_data(G_OBJECT(widget), "type");
if(type == VOLUME_CTRL_PLAYBACK) {
gtk_scale_button_set_value(GTK_SCALE_BUTTON(widget), linphone_call_get_speaker_volume_gain(call));
} else if(type == VOLUME_CTRL_RECORD) {
gtk_scale_button_set_value(GTK_SCALE_BUTTON(widget), linphone_call_get_microphone_volume_gain(call));
}
}
static gboolean volume_control_button_enter_event_handler(GtkWidget *widget) {
volume_control_button_update_value(widget);
return FALSE;
}
static void volume_control_init(GtkWidget *vol_ctrl, VolumeControlType type, LinphoneCall *call) {
g_object_set_data(G_OBJECT(vol_ctrl), "call", call);
g_object_set_data(G_OBJECT(vol_ctrl), "type", (gpointer)type);
g_signal_connect(G_OBJECT(vol_ctrl), "enter-notify-event", G_CALLBACK(volume_control_button_enter_event_handler), NULL);
g_signal_connect(G_OBJECT(vol_ctrl), "value-changed", G_CALLBACK(volume_control_value_changed), NULL);
}
void linphone_gtk_create_in_call_view(LinphoneCall *call){
GtkWidget *call_view=linphone_gtk_create_widget("in_call_frame");
GtkWidget *main_window=linphone_gtk_get_main_window ();
GtkNotebook *notebook=(GtkNotebook *)linphone_gtk_get_widget(main_window,"viewswitch");
GtkWidget *spk_vol_ctrl = linphone_gtk_get_widget(call_view, "incall_spk_vol_ctrl_button");
GtkWidget *mic_vol_ctrl = linphone_gtk_get_widget(call_view, "incall_mic_vol_ctrl_button");
static int call_index=1;
int idx;
GtkWidget *transfer;
@ -407,6 +445,9 @@ void linphone_gtk_create_in_call_view(LinphoneCall *call){
gtk_button_set_image(GTK_BUTTON(button),image);
gtk_widget_show(image);
g_signal_connect_swapped(G_OBJECT(linphone_gtk_get_widget(call_view,"quality_indicator")),"button-press-event",(GCallback)linphone_gtk_show_call_stats,call);
volume_control_init(spk_vol_ctrl, VOLUME_CTRL_PLAYBACK, call);
volume_control_init(mic_vol_ctrl, VOLUME_CTRL_RECORD, call);
}
static void video_button_clicked(GtkWidget *button, LinphoneCall *call){
@ -510,7 +551,7 @@ void linphone_gtk_in_call_view_set_calling(LinphoneCall *call){
gtk_label_set_markup(GTK_LABEL(status),_("<b>Calling...</b>"));
display_peer_name_in_label(callee,linphone_call_get_remote_address (call));
gtk_label_set_text(GTK_LABEL(duration),_("00::00::00"));
gtk_label_set_text(GTK_LABEL(duration),_("00:00:00"));
linphone_gtk_in_call_set_animation_spinner(callview);
}
@ -637,55 +678,15 @@ void linphone_gtk_uninit_audio_meter(GtkWidget *w){
}
}
typedef enum { VOLUME_CTRL_PLAYBACK, VOLUME_CTRL_RECORD } VolumeControlType;
static void volume_control_value_changed(GtkScaleButton *button, gdouble value, gpointer user_data) {
LinphoneCall *call = (LinphoneCall *)g_object_get_data(G_OBJECT(button), "call");
VolumeControlType type = (VolumeControlType)g_object_get_data(G_OBJECT(button), "type");
if(type == VOLUME_CTRL_PLAYBACK) {
linphone_call_set_speaker_volume_gain(call, value);
} else if(type == VOLUME_CTRL_RECORD) {
linphone_call_set_microphone_volume_gain(call, value);
}
}
static void volume_control_button_update_value(GtkWidget *widget) {
LinphoneCall *call = (LinphoneCall *)g_object_get_data(G_OBJECT(widget), "call");
VolumeControlType type = (VolumeControlType)g_object_get_data(G_OBJECT(widget), "type");
if(type == VOLUME_CTRL_PLAYBACK) {
gtk_scale_button_set_value(GTK_SCALE_BUTTON(widget), linphone_call_get_speaker_volume_gain(call));
} else if(type == VOLUME_CTRL_RECORD) {
gtk_scale_button_set_value(GTK_SCALE_BUTTON(widget), linphone_call_get_microphone_volume_gain(call));
}
}
static gboolean volume_control_button_enter_event_handler(GtkWidget *widget) {
volume_control_button_update_value(widget);
return FALSE;
}
static void volume_control_init(GtkWidget *vol_ctrl, VolumeControlType type, LinphoneCall *call) {
g_object_set_data(G_OBJECT(vol_ctrl), "call", call);
g_object_set_data(G_OBJECT(vol_ctrl), "type", (gpointer)type);
g_signal_connect(G_OBJECT(vol_ctrl), "enter-notify-event", G_CALLBACK(volume_control_button_enter_event_handler), NULL);
g_signal_connect(G_OBJECT(vol_ctrl), "value-changed", G_CALLBACK(volume_control_value_changed), NULL);
}
void linphone_gtk_in_call_view_enable_audio_view(LinphoneCall *call, gboolean val){
GtkWidget *callview=(GtkWidget*)linphone_call_get_user_pointer(call);
GtkWidget *audio_view=linphone_gtk_get_widget(callview,"incall_audioview");
GtkWidget *mic_level=linphone_gtk_get_widget(callview,"mic_audiolevel");
GtkWidget *spk_level=linphone_gtk_get_widget(callview,"spk_audiolevel");
GtkWidget *spk_vol_ctrl = linphone_gtk_get_widget(callview, "incall_spk_vol_ctrl_button");
GtkWidget *mic_vol_ctrl = linphone_gtk_get_widget(callview, "incall_mic_vol_ctrl_button");
if (val){
linphone_gtk_init_audio_meter(mic_level,(get_volume_t)linphone_call_get_record_volume,call);
linphone_gtk_init_audio_meter(spk_level,(get_volume_t)linphone_call_get_play_volume,call);
volume_control_init(spk_vol_ctrl, VOLUME_CTRL_PLAYBACK, call);
volume_control_init(mic_vol_ctrl, VOLUME_CTRL_RECORD, call);
gtk_widget_show_all(audio_view);
}else{
linphone_gtk_uninit_audio_meter(mic_level);
@ -764,7 +765,7 @@ void linphone_gtk_in_call_view_set_in_call(LinphoneCall *call){
gtk_widget_set_sensitive(linphone_gtk_get_widget(callview,"conference_button"),!in_conf);
gtk_widget_set_sensitive(linphone_gtk_get_widget(callview,"transfer_button"),!in_conf);
gtk_label_set_text(GTK_LABEL(duration),_("00::00::00"));
gtk_label_set_text(GTK_LABEL(duration),_("00:00:00"));
linphone_gtk_in_call_set_animation_image(callview,GTK_STOCK_MEDIA_PLAY,TRUE);
linphone_gtk_call_update_tab_header(call,FALSE);
linphone_gtk_enable_mute_button(
@ -794,10 +795,12 @@ void linphone_gtk_in_call_view_set_in_call(LinphoneCall *call){
void linphone_gtk_in_call_view_set_paused(LinphoneCall *call){
GtkWidget *callview=(GtkWidget*)linphone_call_get_user_pointer(call);
GtkWidget *status=linphone_gtk_get_widget(callview,"in_call_status");
GtkWidget *record_bar = linphone_gtk_get_widget(callview, "record_hbox");
gtk_widget_hide(linphone_gtk_get_widget(callview,"answer_decline_panel"));
gtk_label_set_markup(GTK_LABEL(status),_("<b>Paused call</b>"));
linphone_gtk_in_call_show_video(call);
linphone_gtk_in_call_set_animation_image(callview,GTK_STOCK_MEDIA_PAUSE,TRUE);
gtk_widget_show_all(record_bar);
}
void linphone_gtk_in_call_view_update_duration(LinphoneCall *call){

View file

@ -100,7 +100,7 @@ LINPHONE_PUBLIC GtkWidget *linphone_gtk_create_window(const char *window_name, G
LINPHONE_PUBLIC GtkWidget *linphone_gtk_get_widget(GtkWidget *window, const char *name);
LINPHONE_PUBLIC GtkWidget *linphone_gtk_create_widget(const char* widget_name);
const char *linphone_gtk_message_storage_get_db_file(const char *filename);
char *linphone_gtk_message_storage_get_db_file(const char *filename);
LINPHONE_PUBLIC void linphone_gtk_show_assistant(GtkWidget* parent);
LINPHONE_PUBLIC void linphone_gtk_close_assistant(void);
@ -336,3 +336,6 @@ LINPHONE_PUBLIC void linphone_gtk_proxy_cancel(GtkButton *button);
LINPHONE_PUBLIC void linphone_gtk_proxy_address_changed(GtkEditable *editable);
LINPHONE_PUBLIC void linphone_gtk_proxy_transport_changed(GtkWidget *combo);
LINPHONE_PUBLIC void linphone_gtk_tunnel_ok(GtkButton *button);
LINPHONE_PUBLIC void linphone_gtk_notebook_current_page_changed(GtkNotebook *notebook, GtkWidget *page, guint page_num, gpointer user_data);
LINPHONE_PUBLIC void linphone_gtk_reload_sound_devices(void);
LINPHONE_PUBLIC void linphone_gtk_reload_video_devices(void);

View file

@ -1466,18 +1466,29 @@ static void linphone_gtk_registration_state_changed(LinphoneCore *lc, LinphonePr
update_registration_status(cfg,rs);
}
void linphone_gtk_open_browser(const char *url){
/*in gtk 2.16, gtk_show_uri does not work...*/
#ifndef WIN32
#if GTK_CHECK_VERSION(2,18,3)
gtk_show_uri(NULL,url,GDK_CURRENT_TIME,NULL);
void linphone_gtk_open_browser(const char *uri) {
#ifdef __APPLE__
GError *error = NULL;
char cmd_line[256];
g_snprintf(cmd_line, sizeof(cmd_line), "%s %s", "/usr/bin/open", uri);
g_spawn_command_line_async(cmd_line, &error);
if (error) {
g_warning("Could not open %s: %s", uri, error->message);
g_error_free(error);
}
#elif defined(WIN32)
HINSTANCE instance = ShellExecute(NULL, "open", uri, NULL, NULL, SW_SHOWNORMAL);
if ((int)instance <= 32) {
g_warning("Could not open %s (error #%i)", uri, (int)instance);
}
#else
char cl[255];
snprintf(cl,sizeof(cl),"/usr/bin/x-www-browser %s",url);
g_spawn_command_line_async(cl,NULL);
#endif
#else /*WIN32*/
ShellExecute(0,"open",url,NULL,NULL,1);
GError *error = NULL;
gtk_show_uri(NULL, uri, GDK_CURRENT_TIME, &error);
if (error) {
g_warning("Could not open %s: %s", uri, error->message);
g_error_free(error);
}
#endif
}
@ -1739,7 +1750,7 @@ static void linphone_gtk_configure_main_window(){
gchar *tmp;
GtkWidget *menu_item=linphone_gtk_get_widget(w,"home_item");
tmp=g_strdup(home);
g_object_set_data(G_OBJECT(menu_item),"home",tmp);
g_object_set_data_full(G_OBJECT(menu_item),"home",tmp, (GDestroyNotify)g_free);
}
{
/*
@ -2043,6 +2054,10 @@ static void linphone_gtk_init_ui(void){
linphone_gtk_monitor_usb();
}
static void sigint_handler(int signum){
gtk_main_quit();
}
int main(int argc, char *argv[]){
char *config_file;
const char *factory_config_file;
@ -2052,7 +2067,7 @@ int main(int argc, char *argv[]){
GdkPixbuf *pbuf;
const char *app_name="Linphone";
LpConfig *factory;
const char *db_file;
char *db_file;
GError *error=NULL;
const char *tmp;
@ -2071,18 +2086,6 @@ int main(int argc, char *argv[]){
/*for pulseaudio:*/
g_setenv("PULSE_PROP_media.role", "phone", TRUE);
#endif
/* Add the data directory of the install prefix to XDG_DATA_DIRS
* This environment variable is used by GTK+ to locate the directory
* which stores icon images. */
tmp = g_getenv("XDG_DATA_DIRS");
if(tmp && strlen(tmp) > 0) {
char *xdg_data_dirs = g_strdup_printf("%s:%s", PACKAGE_DATA_DIR, tmp);
g_setenv("XDG_DATA_DIRS", xdg_data_dirs, TRUE);
g_free(xdg_data_dirs);
} else {
g_setenv("XDG_DATA_DIRS", PACKAGE_DATA_DIR, FALSE);
}
lang=linphone_gtk_get_lang(config_file);
if (lang == NULL || lang[0]=='\0'){
@ -2203,13 +2206,15 @@ core_start:
linphone_core_enable_logs_with_cb(linphone_gtk_log_handler);
db_file=linphone_gtk_message_storage_get_db_file(NULL);
linphone_gtk_init_liblinphone(config_file, factory_config_file, db_file);
g_free(db_file);
/* do not lower timeouts under 30 ms because it exhibits a bug on gtk+/win32, with cpu running 20% all the time...*/
gtk_timeout_add(30,(GtkFunction)linphone_gtk_iterate,(gpointer)linphone_gtk_get_core());
gtk_timeout_add(30,(GtkFunction)linphone_gtk_check_logs,(gpointer)linphone_gtk_get_core());
signal(SIGINT, sigint_handler);
gtk_main();
linphone_gtk_quit();

View file

@ -211,6 +211,7 @@
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<signal name="switch-page" handler="linphone_gtk_notebook_current_page_changed" swapped="no"/>
<child>
<object class="GtkVBox" id="sip_tab">
<property name="visible">True</property>

View file

@ -557,9 +557,9 @@ static void bitrate_edited(GtkCellRendererText *renderer, gchar *path, gchar *ne
GtkListStore *store=(GtkListStore*)userdata;
GtkTreeIter iter;
float newbitrate=0;
if (!new_text) return;
if (sscanf(new_text, "%f", &newbitrate)!=1) return;
if (gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(store),&iter,path)){
@ -606,10 +606,10 @@ static void linphone_gtk_init_codec_list(GtkTreeView *listview){
"foreground",CODEC_COLOR,
NULL);
gtk_tree_view_append_column (listview, column);
g_value_init(&editable, G_TYPE_BOOLEAN);
g_value_set_boolean(&editable, TRUE);
renderer = gtk_cell_renderer_text_new ();
g_object_set_property(G_OBJECT(renderer), "editable", &editable);
column = gtk_tree_view_column_new_with_attributes (
@ -620,7 +620,7 @@ static void linphone_gtk_init_codec_list(GtkTreeView *listview){
NULL);
g_signal_connect(G_OBJECT(renderer),"edited",G_CALLBACK(bitrate_edited),store);
gtk_tree_view_append_column (listview, column);
renderer = gtk_cell_renderer_text_new ();
g_object_set_property(G_OBJECT(renderer), "editable", &editable);
column = gtk_tree_view_column_new_with_attributes (
@ -785,13 +785,13 @@ static void linphone_gtk_codec_move(GtkWidget *button, int dir, int type){ /* 0=
if (gtk_tree_selection_count_selected_rows(sel) == 1){
MSList *sel_elem,*before;
MSList *codec_list;
GList *selected_rows = gtk_tree_selection_get_selected_rows(sel, &mod);
gtk_tree_model_get_iter(mod, &iter, (GtkTreePath *)g_list_nth_data(selected_rows, 0));
gtk_tree_model_get(mod,&iter,CODEC_PRIVDATA,&pt,-1);
g_list_foreach(selected_rows, _g_list_func_destroy_tree_path, NULL);
g_list_free(selected_rows);
if (pt->type==PAYLOAD_VIDEO)
codec_list=ms_list_copy(linphone_core_get_video_codecs(lc));
else codec_list=ms_list_copy(linphone_core_get_audio_codecs(lc));
@ -887,7 +887,7 @@ void linphone_gtk_show_sip_accounts(GtkWidget *w){
GtkTreeSelection *select;
const LinphoneProxyConfig *default_pc = linphone_core_get_default_proxy_config(linphone_gtk_get_core());
GtkTreePath *default_pc_path = NULL;
const MSList *elem;
if (!model){
GtkCellRenderer *renderer;
@ -1901,3 +1901,15 @@ void linphone_gtk_auto_answer_delay_changed(GtkSpinButton *spinbutton, gpointer
int delay = gtk_spin_button_get_value(spinbutton);
linphone_gtk_set_ui_config_int("auto_answer_delay", delay);
}
void linphone_gtk_notebook_current_page_changed (GtkNotebook *notebook, GtkWidget *page, guint page_num, gpointer user_data) {
#ifndef HAVE_LIBUDEV_H
if (page_num == 1) {
// Multimedia settings - we reload audio and video devices to detect
// hot-plugged devices
g_message("Opened multimedia page... reloading audio and video devices!");
linphone_gtk_reload_sound_devices();
linphone_gtk_reload_video_devices();
}
#endif
}

@ -1 +1 @@
Subproject commit 2b6697069c534acf64f12771ba63ec3c1700edd0
Subproject commit 19d44b552f46272f43a57f3370badd1a66663f58

2
oRTP

@ -1 +1 @@
Subproject commit 714ae33119397055bc0509ea78a3651a3d1b58d5
Subproject commit bb95930a77e8a1432e5c31dc170f05ecd15518e5

609
po/ar.po

File diff suppressed because it is too large Load diff

562
po/cs.po

File diff suppressed because it is too large Load diff

635
po/de.po

File diff suppressed because it is too large Load diff

553
po/es.po

File diff suppressed because it is too large Load diff

627
po/fr.po

File diff suppressed because it is too large Load diff

561
po/he.po

File diff suppressed because it is too large Load diff

573
po/hu.po

File diff suppressed because it is too large Load diff

690
po/it.po

File diff suppressed because it is too large Load diff

571
po/ja.po

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

591
po/nl.po

File diff suppressed because it is too large Load diff

526
po/pl.po

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

637
po/ru.po

File diff suppressed because it is too large Load diff

616
po/sr.po

File diff suppressed because it is too large Load diff

537
po/sv.po

File diff suppressed because it is too large Load diff

561
po/tr.po

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -144,7 +144,7 @@ void linphone_transfer_state_changed(LinphoneCore *lc, LinphoneCall *transfered,
}
void linphone_call_cb(LinphoneCall *call,void * user_data) {
void linphone_call_iframe_decoded_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;
@ -288,9 +288,9 @@ bool_t call_with_params2(LinphoneCoreManager* caller_mgr
BC_ASSERT_TRUE(wait_for(callee_mgr->lc,caller_mgr->lc,&callee_mgr->stat.number_of_LinphoneCallConnected,initial_callee.number_of_LinphoneCallConnected+1));
BC_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)
result = wait_for_until(callee_mgr->lc,caller_mgr->lc,&caller_mgr->stat.number_of_LinphoneCallStreamsRunning,initial_caller.number_of_LinphoneCallStreamsRunning+1, 2000)
&&
wait_for(callee_mgr->lc,caller_mgr->lc,&callee_mgr->stat.number_of_LinphoneCallStreamsRunning,initial_callee.number_of_LinphoneCallStreamsRunning+1);
wait_for_until(callee_mgr->lc,caller_mgr->lc,&callee_mgr->stat.number_of_LinphoneCallStreamsRunning,initial_callee.number_of_LinphoneCallStreamsRunning+1, 2000);
if (linphone_core_get_media_encryption(caller_mgr->lc) != LinphoneMediaEncryptionNone
|| linphone_core_get_media_encryption(callee_mgr->lc) != LinphoneMediaEncryptionNone) {
@ -925,7 +925,9 @@ static void call_declined(void) {
BC_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallEnd,1, int, "%d");
BC_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallEnd,1, int, "%d");
BC_ASSERT_EQUAL(linphone_call_get_reason(in_call),LinphoneReasonDeclined, int, "%d");
BC_ASSERT_EQUAL(linphone_call_log_get_status(linphone_call_get_call_log(in_call)),LinphoneCallDeclined, int, "%d");
BC_ASSERT_EQUAL(linphone_call_get_reason(out_call),LinphoneReasonDeclined, int, "%d");
BC_ASSERT_EQUAL(linphone_call_log_get_status(linphone_call_get_call_log(out_call)),LinphoneCallDeclined, int, "%d");
linphone_call_unref(in_call);
}
linphone_call_unref(out_call);
@ -1240,6 +1242,74 @@ end:
static void call_paused_resumed(void) {
call_paused_resumed_base(FALSE);
}
static void call_paused_by_both() {
LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc");
LinphoneCall* call_pauline, *call_marie;
const rtp_stats_t * stats;
MSList *lcs = NULL;
bool_t call_ok;
lcs = ms_list_append(lcs, pauline->lc);
lcs = ms_list_append(lcs, marie->lc);
BC_ASSERT_TRUE((call_ok=call(pauline,marie)));
if (!call_ok) goto end;
call_pauline = linphone_core_get_current_call(pauline->lc);
call_marie = linphone_core_get_current_call(marie->lc);
wait_for_until(pauline->lc, marie->lc, NULL, 5, 2000);
linphone_core_pause_call(pauline->lc,call_pauline);
BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallPausing,1));
BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallPausedByRemote,1));
BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->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);
/*marie pauses the call also*/
linphone_core_pause_call(marie->lc, call_marie);
BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallPausing,1));
BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallPaused,1));
wait_for_until(pauline->lc, marie->lc, NULL, 5, 2000);
/*pauline must stay in paused state*/
BC_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallPaused, 1, int, "%i");
check_media_direction(pauline, call_pauline, lcs, LinphoneMediaDirectionInactive, LinphoneMediaDirectionInvalid);
check_media_direction(marie, call_marie, lcs, LinphoneMediaDirectionInactive, LinphoneMediaDirectionInvalid);
/*now pauline wants to resume*/
linphone_core_resume_call(pauline->lc, call_pauline);
BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallResuming,1));
BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallPausedByRemote,1));
/*Marie must stay in paused state*/
wait_for_until(pauline->lc, marie->lc, NULL, 5, 2000);
BC_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallPaused, 1, int, "%i");
/*now marie wants to resume also*/
linphone_core_resume_call(marie->lc, call_marie);
BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallResuming,1));
BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,2));
BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2));
/*same here: wait a while for a bit of a traffic, we need to receive a RTCP packet*/
wait_for_until(pauline->lc, marie->lc, NULL, 5, 5000);
/*since RTCP streams are reset when call is paused/resumed, there should be no loss at all*/
stats = rtp_session_get_stats(call_pauline->sessions->rtp_session);
BC_ASSERT_EQUAL(stats->cum_packet_loss, 0, int, "%d");
end_call(marie, pauline);
end:
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
ms_list_free(lcs);
}
#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*/ \
@ -1496,7 +1566,7 @@ bool_t add_video(LinphoneCoreManager* caller,LinphoneCoreManager* callee, bool_t
}
if (video_policy->automatically_accept) {
linphone_call_set_next_video_frame_decoded_callback(call_obj,linphone_call_cb,callee->lc);
linphone_call_set_next_video_frame_decoded_callback(call_obj,linphone_call_iframe_decoded_cb,callee->lc);
/*send vfu*/
linphone_call_send_vfu_request(call_obj);
return wait_for(caller->lc,callee->lc,&callee->stat.number_of_IframeDecoded,initial_callee_stat.number_of_IframeDecoded+1);
@ -1791,7 +1861,7 @@ void video_call_base_2(LinphoneCoreManager* pauline,LinphoneCoreManager* marie,
BC_ASSERT_TRUE(linphone_call_log_video_enabled(linphone_call_get_call_log(pauline_call)));
/*check video path*/
linphone_call_set_next_video_frame_decoded_callback(marie_call,linphone_call_cb,marie->lc);
linphone_call_set_next_video_frame_decoded_callback(marie_call,linphone_call_iframe_decoded_cb,marie->lc);
linphone_call_send_vfu_request(marie_call);
BC_ASSERT_TRUE( wait_for(marie->lc,pauline->lc,&marie->stat.number_of_IframeDecoded,1));
} else {
@ -2345,7 +2415,7 @@ static void call_with_file_player(void) {
end_call(marie, pauline);
/*cannot run on iphone simulator because locks main loop beyond permitted time (should run
on another thread) */
BC_ASSERT_EQUAL(ms_audio_diff(hellopath,recordpath,&similar,audio_cmp_max_shift,NULL,NULL), 0, int, "%d");
BC_ASSERT_EQUAL(ms_audio_diff(hellopath,recordpath,&similar,&audio_cmp_params,NULL,NULL), 0, int, "%d");
if (similar>=threshold)
break;
}
@ -2422,7 +2492,7 @@ static void call_with_mkv_file_player(void) {
}
end_call(marie, pauline);
#ifdef DO_AUDIO_CMP
BC_ASSERT_EQUAL(ms_audio_diff(hellowav,recordpath,&similar,audio_cmp_max_shift,NULL,NULL),0,int,"%d");
BC_ASSERT_EQUAL(ms_audio_diff(hellowav,recordpath,&similar,&audio_cmp_params,NULL,NULL),0,int,"%d");
BC_ASSERT_GREATER(similar,threshold,double,"%f");
BC_ASSERT_LOWER(similar,1.0,double,"%f");
if(similar>threshold && similar<=1.0) {
@ -3225,48 +3295,59 @@ void check_media_direction(LinphoneCoreManager* mgr, LinphoneCall *call, MSList*
if (call) {
const LinphoneCallParams *params = linphone_call_get_current_params(call);
#ifdef VIDEO_ENABLED
int current_recv_iframe = mgr->stat.number_of_IframeDecoded;
int expected_recv_iframe=0;
int dummy = 0;
if (video_dir != LinphoneMediaDirectionInvalid){
int current_recv_iframe = mgr->stat.number_of_IframeDecoded;
int expected_recv_iframe=0;
int dummy = 0;
BC_ASSERT_EQUAL(video_dir,linphone_call_params_get_video_direction(params), int, "%d");
linphone_call_set_next_video_frame_decoded_callback(call,linphone_call_cb,mgr->lc);
linphone_call_send_vfu_request(call);
if (video_dir != LinphoneMediaDirectionInactive){
BC_ASSERT_TRUE(linphone_call_params_video_enabled(params));
}
BC_ASSERT_EQUAL(linphone_call_params_get_video_direction(params), video_dir, int, "%d");
linphone_call_set_next_video_frame_decoded_callback(call,linphone_call_iframe_decoded_cb,mgr->lc);
linphone_call_send_vfu_request(call);
wait_for_list(lcs,&dummy,1,2000); /*on some device, it may take 3 to 4s to get audio from mic*/
wait_for_list(lcs,&dummy,1,2000); /*on some device, it may take 3 to 4s to get audio from mic*/
switch (video_dir) {
case LinphoneMediaDirectionInactive:
BC_ASSERT_TRUE(linphone_call_get_video_stats(call)->upload_bandwidth<5);
case LinphoneMediaDirectionSendOnly:
expected_recv_iframe = 0;
BC_ASSERT_TRUE(linphone_call_get_video_stats(call)->download_bandwidth<5);
break;
case LinphoneMediaDirectionRecvOnly:
BC_ASSERT_TRUE(linphone_call_get_video_stats(call)->upload_bandwidth<5);
case LinphoneMediaDirectionSendRecv:
expected_recv_iframe = 1;
break;
}
BC_ASSERT_TRUE(wait_for_list(lcs, &mgr->stat.number_of_IframeDecoded,current_recv_iframe + expected_recv_iframe,3000));
#endif
BC_ASSERT_EQUAL(audio_dir,linphone_call_params_get_audio_direction(params), int, "%d");
switch (audio_dir) {
switch (video_dir) {
case LinphoneMediaDirectionInactive:
BC_ASSERT_TRUE(linphone_call_get_audio_stats(call)->upload_bandwidth<5);
BC_ASSERT_TRUE(linphone_call_get_video_stats(call)->upload_bandwidth<5);
case LinphoneMediaDirectionSendOnly:
expected_recv_iframe = 0;
BC_ASSERT_TRUE(linphone_call_get_video_stats(call)->download_bandwidth<5);
if (audio_dir == LinphoneMediaDirectionSendOnly) BC_ASSERT_TRUE(wait_for_list(lcs,mgr->stat.current_audio_upload_bandwidth,70,4000));
break;
case LinphoneMediaDirectionRecvOnly:
BC_ASSERT_TRUE(linphone_call_get_audio_stats(call)->upload_bandwidth<5);
BC_ASSERT_TRUE(linphone_call_get_video_stats(call)->upload_bandwidth<5);
case LinphoneMediaDirectionSendRecv:
BC_ASSERT_TRUE(wait_for_list(lcs,mgr->stat.current_audio_download_bandwidth,70,4000));
if (audio_dir == LinphoneMediaDirectionSendRecv) BC_ASSERT_TRUE(wait_for_list(lcs,mgr->stat.current_audio_upload_bandwidth,70,4000));
expected_recv_iframe = 1;
break;
default:
break;
}
BC_ASSERT_TRUE(wait_for_list(lcs, &mgr->stat.number_of_IframeDecoded,current_recv_iframe + expected_recv_iframe,3000));
}
#endif
if (audio_dir != LinphoneMediaDirectionInvalid){
BC_ASSERT_EQUAL(linphone_call_params_get_audio_direction(params), audio_dir, int, "%d");
switch (audio_dir) {
case LinphoneMediaDirectionInactive:
BC_ASSERT_TRUE(linphone_call_get_audio_stats(call)->upload_bandwidth<5);
case LinphoneMediaDirectionSendOnly:
BC_ASSERT_TRUE(linphone_call_get_video_stats(call)->download_bandwidth<5);
if (audio_dir == LinphoneMediaDirectionSendOnly) BC_ASSERT_TRUE(wait_for_list(lcs,mgr->stat.current_audio_upload_bandwidth,70,4000));
break;
case LinphoneMediaDirectionRecvOnly:
BC_ASSERT_TRUE(linphone_call_get_audio_stats(call)->upload_bandwidth<5);
case LinphoneMediaDirectionSendRecv:
BC_ASSERT_TRUE(wait_for_list(lcs,mgr->stat.current_audio_download_bandwidth,70,4000));
if (audio_dir == LinphoneMediaDirectionSendRecv) BC_ASSERT_TRUE(wait_for_list(lcs,mgr->stat.current_audio_upload_bandwidth,70,4000));
break;
default:
break;
}
}
}
}
@ -3281,14 +3362,14 @@ static void accept_call_in_send_only_base(LinphoneCoreManager* pauline, Linphone
linphone_core_enable_video(pauline->lc,TRUE,TRUE);
linphone_core_set_video_policy(pauline->lc,&pol);
linphone_core_set_video_device(pauline->lc,"Mire: Mire (synthetic moving picture)");
linphone_core_set_video_device(pauline->lc,liblinphone_tester_mire_id);
linphone_core_enable_video(marie->lc,TRUE,TRUE);
linphone_core_set_video_policy(marie->lc,&pol);
linphone_core_set_video_device(marie->lc,"Mire: Mire (synthetic moving picture)");
linphone_core_set_video_device(marie->lc,liblinphone_tester_mire_id);
linphone_call_set_next_video_frame_decoded_callback(linphone_core_invite_address(pauline->lc,marie->identity)
,linphone_call_cb
,linphone_call_iframe_decoded_cb
,pauline->lc);
@ -4095,8 +4176,8 @@ static void video_call_with_re_invite_inactive_followed_by_re_invite_base(Linpho
marie = linphone_core_manager_new( "marie_rc");
pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc");
linphone_core_set_avpf_mode(pauline->lc,TRUE);
linphone_core_set_video_device(pauline->lc,"Mire: Mire (synthetic moving picture)");
linphone_core_set_video_device(marie->lc,"Mire: Mire (synthetic moving picture)");
linphone_core_set_video_device(pauline->lc,liblinphone_tester_mire_id);
linphone_core_set_video_device(marie->lc,liblinphone_tester_mire_id);
linphone_core_set_avpf_mode(marie->lc,TRUE);
lcs=ms_list_append(lcs,pauline->lc);
lcs=ms_list_append(lcs,marie->lc);
@ -4112,7 +4193,7 @@ static void video_call_with_re_invite_inactive_followed_by_re_invite_base(Linpho
linphone_call_params_destroy(params);
BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallUpdating,1));
BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallPaused,1));
BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,2));
BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallPausedByRemote,1));
check_media_direction(marie,linphone_core_get_current_call(marie->lc),lcs,LinphoneMediaDirectionInactive,LinphoneMediaDirectionInactive);
@ -4122,19 +4203,13 @@ static void video_call_with_re_invite_inactive_followed_by_re_invite_base(Linpho
linphone_core_enable_sdp_200_ack(marie->lc,TRUE);
}
/*
currently update call cannot be used in paused state, might not be good.
params=linphone_core_create_call_params(marie->lc,linphone_core_get_current_call(marie->lc));
linphone_call_params_set_audio_direction(params,LinphoneMediaDirectionSendRecv);
linphone_call_params_set_video_direction(params,LinphoneMediaDirectionSendRecv);
linphone_core_update_call(marie->lc,linphone_core_get_current_call(marie->lc),params);
linphone_call_params_destroy(params);
*/
linphone_core_resume_call(marie->lc,linphone_core_get_current_call(marie->lc));
BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallResuming,1));
BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,2));
BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,3));
BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2));
check_media_direction(marie,linphone_core_get_current_call(marie->lc),lcs,LinphoneMediaDirectionSendRecv,LinphoneMediaDirectionSendRecv);
@ -4244,14 +4319,14 @@ static void simple_stereo_call(const char *codec_name, int clock_rate, int bitra
}else{
#if !defined(__arm__) && !defined(__arm64__) && !TARGET_IPHONE_SIMULATOR && !defined(ANDROID)
double similar;
double min_threshold = .7f;
double min_threshold = .6f;
double max_threshold = 1.f;
if (!stereo){
/*when opus doesn't transmit stereo, the cross correlation is around 0.54 : as expected, it is not as good as in full stereo mode*/
min_threshold = .4f;
max_threshold = .6f;
}
BC_ASSERT_EQUAL(ms_audio_diff(recordpath, stereo_file,&similar,audio_cmp_max_shift,completion_cb,NULL), 0, int, "%d");
BC_ASSERT_EQUAL(ms_audio_diff(stereo_file, recordpath,&similar,&audio_cmp_params,completion_cb,NULL), 0, int, "%d");
BC_ASSERT_GREATER(similar, min_threshold, double, "%g");
BC_ASSERT_LOWER(similar, max_threshold, double, "%g");
if (similar<min_threshold || similar>max_threshold){
@ -4281,6 +4356,112 @@ static void simple_stereo_call_opus(void){
simple_stereo_call("opus", 48000, 150, TRUE);
}
static void call_with_complex_late_offering(void){
LinphoneCallParams *params;
LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc");
LinphoneCall* call_pauline;
LinphoneCall* call_marie;
LinphoneVideoPolicy vpol = {TRUE, TRUE};
bool_t call_ok;
linphone_core_enable_video(pauline->lc, TRUE, TRUE);
linphone_core_enable_video(marie->lc, TRUE, TRUE);
linphone_core_set_video_policy(pauline->lc, &vpol);
linphone_core_set_video_policy(marie->lc, &vpol);
linphone_core_set_video_device(pauline->lc,liblinphone_tester_mire_id);
linphone_core_set_video_device(marie->lc,liblinphone_tester_mire_id);
BC_ASSERT_TRUE((call_ok=call(pauline,marie)));
if (!call_ok) goto end;
call_pauline = linphone_core_get_current_call(pauline->lc);
call_marie = linphone_core_get_current_call(marie->lc);
//Invite inactive Audio/video (Marie pause Pauline)
ms_message("CONTEXT: Marie sends INVITE with SDP with all streams inactive");
params=linphone_core_create_call_params(marie->lc,call_marie);
linphone_call_params_set_audio_direction(params,LinphoneMediaDirectionInactive);
linphone_call_params_set_video_direction(params,LinphoneMediaDirectionInactive);
linphone_core_update_call(marie->lc, call_marie ,params);
linphone_call_params_destroy(params);
BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallUpdating,1));
BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallPausedByRemote,1));
BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,2));
//Marie sends INVITE without SDP
ms_message("CONTEXT: Marie sends INVITE without SDP for setting streams in send-only mode");
linphone_core_enable_sdp_200_ack(marie->lc,TRUE);
params=linphone_core_create_call_params(marie->lc,call_marie);
linphone_call_params_set_audio_direction(params,LinphoneMediaDirectionSendOnly);
linphone_call_params_set_video_direction(params,LinphoneMediaDirectionSendOnly);
linphone_core_update_call(marie->lc, call_marie , params);
linphone_call_params_destroy(params);
//Pauline OK with sendonly
BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallUpdating,2));
BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,3));
BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallPausedByRemote,2));
linphone_core_enable_sdp_200_ack(marie->lc,FALSE);
//Pauline pause Marie
ms_message("CONTEXT: Pauline pauses the call");
linphone_core_pause_call(pauline->lc,call_pauline);
BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallPausing,1));
BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallPaused,1));
BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallPausedByRemote,1));
//Pauline resume Marie
ms_message("CONTEXT: Pauline resumes the call");
wait_for_until(pauline->lc, marie->lc, NULL, 5, 2000);
linphone_core_resume_call(pauline->lc,call_pauline);
BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,4));
BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallResuming,1));
BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallPausedByRemote,3));
wait_for_until(pauline->lc, marie->lc, NULL, 0, 2000);
//Marie invite inactive Audio/Video
ms_message("CONTEXT: Marie sends INVITE with SDP with all streams inactive");
params=linphone_core_create_call_params(marie->lc,call_marie);
linphone_call_params_set_audio_direction(params,LinphoneMediaDirectionInactive);
linphone_call_params_set_video_direction(params,LinphoneMediaDirectionInactive);
linphone_core_update_call(marie->lc, call_marie,params);
BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallUpdating,3));
linphone_call_params_destroy(params);
BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallPausedByRemote,4));
BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,5));
//Marie sends INVITE without SDP
ms_message("CONTEXT: Marie sends INVITE without SDP in the purpose of re-enabling streams in sendrecv mode");
linphone_core_enable_sdp_200_ack(marie->lc,TRUE);
params=linphone_core_create_call_params(marie->lc,call_marie);
linphone_call_params_set_audio_direction(params,LinphoneMediaDirectionSendRecv);
linphone_call_params_set_video_direction(params,LinphoneMediaDirectionSendRecv);
linphone_core_update_call(marie->lc, call_marie,params);
BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallUpdating,3));
linphone_call_params_destroy(params);
BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallUpdatedByRemote,1));
BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2));
BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,5));
linphone_core_enable_sdp_200_ack(marie->lc,FALSE);
end_call(marie,pauline);
end:
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
}
static void simple_mono_call_opus(void){
/*actually a call where input/output is made with stereo but opus transmits everything as mono*/
simple_stereo_call("opus", 48000, 150, FALSE);
@ -4363,7 +4544,7 @@ static void call_with_rtp_io_mode(void) {
wait_for_until(pauline->lc,marie->lc,NULL,0,1000);
end_call(pauline,marie);
BC_ASSERT_EQUAL(ms_audio_diff(hellopath, recordpath, &similar, audio_cmp_max_shift, NULL, NULL), 0, int, "%d");
BC_ASSERT_EQUAL(ms_audio_diff(hellopath, recordpath, &similar, &audio_cmp_params, NULL, NULL), 0, int, "%d");
if (similar>=threshold) break;
}
BC_ASSERT_GREATER(similar, threshold, double, "%g");
@ -4430,6 +4611,347 @@ end:
linphone_core_manager_destroy(pauline);
}
// This is a custom structure used for the tests using custom RTP transport modifier.
// It is only used to count the number of sent and received packets
typedef struct _RtpTransportModifierData {
uint64_t packetSentCount;
uint64_t packetReceivedCount;
} RtpTransportModifierData;
const char *XOR_KEY = "BELLEDONNECOMMUNICATIONS";
// Callback called when a packet is on it's way to be sent
// This is where we can do some changes on it, like encrypt it
static int rtptm_on_send(RtpTransportModifier *rtptm, mblk_t *msg) {
RtpTransportModifierData *data = rtptm->data;
rtp_header_t *rtp = (rtp_header_t*)msg->b_rptr;
int i = 0;
unsigned char *src;
int size = 0;
if (rtp->version == 0) {
// This is probably a STUN packet, so don't count it (oRTP won't) and don't encrypt it either
return msgdsize(msg);
}
// Mediastream can create a mblk_t with only the RTP header and setting the b_cont pointer to the actual RTP content buffer
// In this scenario, the result of rtp_get_payload will be 0, and we won't be able to do our XOR encryption on the payload
// The call to msgpullup will trigger a memcpy of the header and the payload in the same buffer in the msg mblk_t
msgpullup(msg, -1);
// Now that the mblk_t buffer directly contains the header and the payload, we can get the size of the payload and a pointer to it's start (we don't encrypt the RTP header)
size = rtp_get_payload(msg, &src);
// Just for fun, let's do a XOR encryption
for (i = 0; i < size; i++) {
src[i] ^= (unsigned char) XOR_KEY[i % strlen(XOR_KEY)];
}
data->packetSentCount += 1;
/* /!\ DO NOT RETURN 0 or the packet will never leave /!\ */
return msgdsize(msg);
}
// Callback called when a packet is on it's way to be received
// This is where we can do some changes on it, like decrypt it
static int rtptm_on_receive(RtpTransportModifier *rtptm, mblk_t *msg) {
RtpTransportModifierData *data = rtptm->data;
rtp_header_t *rtp = (rtp_header_t*)msg->b_rptr;
int i = 0;
unsigned char *src;
int size = 0;
if (rtp->version == 0) {
// This is probably a STUN packet, so don't count it (oRTP won't) and don't decrypt it either
return msgdsize(msg);
}
// On the receiving side, there is no need for a msgpullup, the mblk_t contains the header and the payload in the same buffer
// We just ask for the size and a pointer to the payload buffer
size = rtp_get_payload(msg, &src);
// Since we did a XOR encryption on the send side, we have to do it again to decrypt the payload
for (i = 0; i < size; i++) {
src[i] ^= (unsigned char) XOR_KEY[i % strlen(XOR_KEY)];
}
data->packetReceivedCount += 1;
/* /!\ DO NOT RETURN 0 or the packet will be dropped /!\ */
return msgdsize(msg);
}
// This callback is called when the transport modifier is being destroyed
// It is a good place to free the resources allocated for the transport modifier
static void rtptm_destroy(RtpTransportModifier *rtptm) {
// Do nothing, we'll free it later because we need to access the RtpTransportModifierData structure after the call is ended
}
// This is the callback called when the state of the call change
void static call_state_changed_4(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate, const char *msg) {
int i = 0;
// To add a custom RTP transport modifier, we have to do it before the call is running, but after the RTP session is created.
if (cstate == LinphoneCallIncomingReceived || cstate == LinphoneCallOutgoingProgress) {
RtpTransport *rtpt = NULL;
RtpTransportModifierData *data = ms_new0(RtpTransportModifierData, 1);
RtpTransportModifier *rtptm = ms_new0(RtpTransportModifier, 1);
rtptm->data = data;
rtptm->t_process_on_send = rtptm_on_send;
rtptm->t_process_on_receive = rtptm_on_receive;
rtptm->t_destroy = rtptm_destroy;
// Here we iterate on each meta rtp transport available
for (i = 0; i < linphone_call_get_stream_count(call); i++) {
MSFormatType type;
rtpt = linphone_call_get_meta_rtp_transport(call, i);
// If we wanted, we also could get the RTCP meta transports like this:
// rtcpt = linphone_call_get_meta_rtcp_transport(call, i);
// If you want to know which stream meta RTP transport is the current one, you can use
type = linphone_call_get_stream_type(call, i);
// Currently there is only MSAudio and MSVideo types, but this could change later
if (type == MSAudio) {
// And now we append our RTP transport modifier to the current list of modifiers
meta_rtp_transport_append_modifier(rtpt, rtptm);
} else if (type == MSVideo) {
// Because the call of this test is audio only, we don't have to append our modifier to the meta RTP transport from the video stream
}
}
// We save the pointer to our RtpTransportModifier in the call user_data to be able to get to it later
call->user_data = rtptm;
}
}
static void custom_rtp_modifier(bool_t pauseResumeTest, bool_t recordTest) {
// This will initialize two linphone core using information contained in the marie_rc and pauline_rc files and wait for them to be correctly registered
LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc");
LinphoneCall* call_pauline = NULL;
LinphoneCall* call_marie = NULL;
const rtp_stats_t * stats;
bool_t call_ok;
LinphoneCoreVTable * v_table;
RtpTransportModifier *rtptm_marie = NULL;
RtpTransportModifier *rtptm_pauline = NULL;
RtpTransportModifierData *data_marie = NULL;
RtpTransportModifierData *data_pauline = NULL;
// The following are only used for the record test
LinphonePlayer *player;
char *hellopath = bc_tester_res("sounds/ahbahouaismaisbon.wav"); // File to be played
char *recordpath = create_filepath(bc_tester_get_writable_dir_prefix(), "record-call_with_file_player", "wav"); // File to record the received sound
double similar = 1; // The factor of similarity between the played file and the one recorded
const double threshold = 0.9; // Minimum similarity value to consider the record file equal to the one sent
// We create a new vtable to listen only to the call state changes, in order to plug our RTP Transport Modifier when the call will be established
v_table = linphone_core_v_table_new();
v_table->call_state_changed = call_state_changed_4;
linphone_core_add_listener(pauline->lc,v_table);
v_table = linphone_core_v_table_new();
v_table->call_state_changed = call_state_changed_4;
linphone_core_add_listener(marie->lc,v_table);
if (recordTest) { // When we do the record test, we need a file player to play the content of a sound file
/*make sure the record file doesn't already exists, otherwise this test will append new samples to it*/
unlink(recordpath);
linphone_core_use_files(pauline->lc,TRUE);
linphone_core_set_play_file(pauline->lc,NULL);
linphone_core_set_record_file(pauline->lc,NULL);
/*callee is recording and plays file*/
linphone_core_use_files(marie->lc,TRUE);
linphone_core_set_play_file(marie->lc,NULL);
linphone_core_set_record_file(marie->lc,recordpath);
}
// Now the the call should be running (call state StreamsRunning)
BC_ASSERT_TRUE((call_ok=call(pauline,marie)));
if (!call_ok) goto end;
// Ref the call to keep the pointer valid even after the call is release
call_pauline = linphone_call_ref(linphone_core_get_current_call(pauline->lc));
call_marie = linphone_call_ref(linphone_core_get_current_call(marie->lc));
// This is for the pause/resume test, we don't do it in the call record test to be able to check the recorded call matches the file played
if (pauseResumeTest) {
// This only wait for 3 seconds in order to generate traffic for the test
wait_for_until(pauline->lc, marie->lc, NULL, 5, 3000);
linphone_core_pause_call(pauline->lc,call_pauline);
BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &pauline->stat.number_of_LinphoneCallPausing, 1));
BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &marie->stat.number_of_LinphoneCallPausedByRemote, 1));
BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &pauline->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);
linphone_core_resume_call(pauline->lc,call_pauline);
BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &pauline->stat.number_of_LinphoneCallStreamsRunning, 2));
BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &marie->stat.number_of_LinphoneCallStreamsRunning, 2));
/*same here: wait a while for a bit of a traffic, we need to receive a RTCP packet*/
wait_for_until(pauline->lc, marie->lc, NULL, 5, 5000);
/*since RTCP streams are reset when call is paused/resumed, there should be no loss at all*/
stats = rtp_session_get_stats(call_pauline->sessions->rtp_session);
BC_ASSERT_EQUAL(stats->cum_packet_loss, 0, int, "%d");
end_call(pauline, marie);
} else if (recordTest) {
player = linphone_call_get_player(call_pauline);
BC_ASSERT_PTR_NOT_NULL(player);
if (player) {
// This will ask pauline to play the file
BC_ASSERT_EQUAL(linphone_player_open(player, hellopath, on_eof, pauline),0, int, "%d");
BC_ASSERT_EQUAL(linphone_player_start(player), 0, int, "%d");
}
/* This assert should be modified to be at least as long as the WAV file */
BC_ASSERT_TRUE(wait_for_until(pauline->lc, marie->lc, &pauline->stat.number_of_player_eof, 1, 10000));
/*wait one second more for transmission to be fully ended (transmission time + jitter buffer)*/
wait_for_until(pauline->lc, marie->lc, NULL, 0, 1000);
end_call(pauline, marie);
// Now we compute a similarity factor between the original file and the one we recorded on the callee side
BC_ASSERT_EQUAL(ms_audio_diff(hellopath, recordpath, &similar, &audio_cmp_params, NULL, NULL), 0, int, "%d");
BC_ASSERT_GREATER(similar, threshold, double, "%g");
BC_ASSERT_LOWER(similar, 1.0, double, "%g");
if (similar >= threshold && similar <= 1.0) {
// If the similarity value is between perfect (1) and our threshold (0.9), then we delete the file used for the record
remove(recordpath);
}
} else {
// This only wait for 3 seconds in order to generate traffic for the test
wait_for_until(pauline->lc, marie->lc, NULL, 5, 3000);
// We termine the call and check the stats to see if the call is correctly ended on both sides
end_call(pauline, marie);
}
// Now we can go fetch our custom structure and check the number of packets sent/received is the same on both sides
rtptm_marie = (RtpTransportModifier *)call_marie->user_data;
rtptm_pauline = (RtpTransportModifier *)call_pauline->user_data;
data_marie = (RtpTransportModifierData *)rtptm_marie->data;
data_pauline = (RtpTransportModifierData *)rtptm_pauline->data;
BC_ASSERT_PTR_NOT_NULL(data_marie);
BC_ASSERT_PTR_NOT_NULL(data_pauline);
ms_message("Marie sent %i RTP packets and received %i (through our modifier)", (int)data_marie->packetSentCount, (int)data_marie->packetReceivedCount);
ms_message("Pauline sent %i RTP packets and received %i (through our modifier)", (int)data_pauline->packetSentCount, (int)data_pauline->packetReceivedCount);
// There will be a few RTP packets sent on marie's side before the call is ended at pauline's request, so we need the threshold
BC_ASSERT_TRUE(data_marie->packetSentCount - data_pauline->packetReceivedCount < 50);
BC_ASSERT_TRUE(data_marie->packetReceivedCount == data_pauline->packetSentCount);
// At this point, we know each packet that has been processed in the send callback of our RTP modifier also go through the recv callback of the remote.
// Now we want to ensure that all sent RTP packets actually go through our RTP transport modifier and thus no packet leave without being processed (by any operation we might want to do on it)
{
const LinphoneCallStats *marie_stats = linphone_call_get_audio_stats(call_marie);
const LinphoneCallStats *pauline_stats = linphone_call_get_audio_stats(call_pauline);
rtp_stats_t marie_rtp_stats = linphone_call_stats_get_rtp_stats(marie_stats);
rtp_stats_t pauline_rtp_stats = linphone_call_stats_get_rtp_stats(pauline_stats);
ms_message("Marie sent %i RTP packets and received %i (for real)", (int)marie_rtp_stats.packet_sent, (int)marie_rtp_stats.packet_recv);
ms_message("Pauline sent %i RTP packets and received %i (for real)", (int)pauline_rtp_stats.packet_sent, (int)pauline_rtp_stats.packet_recv);
BC_ASSERT_TRUE(data_marie->packetReceivedCount == marie_rtp_stats.packet_recv);
BC_ASSERT_TRUE(data_marie->packetSentCount == marie_rtp_stats.packet_sent);
BC_ASSERT_TRUE(data_pauline->packetReceivedCount == pauline_rtp_stats.packet_recv);
BC_ASSERT_TRUE(data_pauline->packetSentCount == pauline_rtp_stats.packet_sent);
}
end:
// Since we didn't free the resources of our RTP transport modifier in the rtptm_destroy callback, we'll do it here
if (data_pauline) {
ms_free(data_pauline);
}
ms_free(rtptm_pauline);
if (data_marie) {
ms_free(data_marie);
}
ms_free(rtptm_marie);
// Unref the previously ref calls
if (call_marie) {
linphone_call_unref(call_marie);
}
if (call_pauline) {
linphone_call_unref(call_pauline);
}
// The test is finished, the linphone core are no longer needed, we can safely free them
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
ms_free(recordpath);
ms_free(hellopath);
}
static void call_with_custom_rtp_modifier(void) {
custom_rtp_modifier(FALSE, FALSE);
}
static void call_paused_resumed_with_custom_rtp_modifier(void) {
custom_rtp_modifier(TRUE, FALSE);
}
static void call_record_with_custom_rtp_modifier(void) {
custom_rtp_modifier(FALSE, TRUE);
}
static void _call_with_network_switch(bool_t use_ice){
LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc");
bool_t call_ok;
if (use_ice){
linphone_core_set_firewall_policy(marie->lc,LinphonePolicyUseIce);
linphone_core_set_firewall_policy(pauline->lc,LinphonePolicyUseIce);
}
BC_ASSERT_TRUE((call_ok=call(pauline,marie)));
if (!call_ok) goto end;
wait_for_until(marie->lc, pauline->lc, NULL, 0, 2000);
if (use_ice) BC_ASSERT_TRUE(check_ice(pauline,marie,LinphoneIceStateHostConnection));
/*marie looses the network and reconnects*/
linphone_core_set_network_reachable(marie->lc, FALSE);
wait_for_until(marie->lc, pauline->lc, NULL, 0, 1000);
/*marie will reconnect and register*/
linphone_core_set_network_reachable(marie->lc, TRUE);
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneRegistrationOk, 2));
/*pauline shall receive a reINVITE to update the session*/
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallUpdatedByRemote, 1));
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallStreamsRunning, 2));
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallStreamsRunning, 2));
liblinphone_tester_check_rtcp(pauline, marie);
if (use_ice) BC_ASSERT_TRUE(check_ice(pauline,marie,LinphoneIceStateHostConnection));
/*pauline shall be able to end the call without problem now*/
end_call(pauline, marie);
end:
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
}
static void call_with_network_switch(void){
_call_with_network_switch(FALSE);
}
#if 0
static void call_with_network_switch_and_ice(void){
_call_with_network_switch(TRUE);
}
#endif
test_t call_tests[] = {
{ "Early declined call", early_declined_call },
{ "Call declined", call_declined },
@ -4458,6 +4980,7 @@ test_t call_tests[] = {
{ "Call without SDP", call_with_no_sdp},
{ "Call without SDP and ACK without SDP", call_with_no_sdp_ack_without_sdp},
{ "Call paused resumed", call_paused_resumed },
{ "Call paused by both parties", call_paused_by_both },
{ "Call paused resumed with loss", call_paused_resumed_with_loss },
{ "Call paused resumed from callee", call_paused_resumed_from_callee },
{ "SRTP call", srtp_call },
@ -4557,7 +5080,16 @@ test_t call_tests[] = {
{ "Simple mono call with opus", simple_mono_call_opus },
{ "Call with FQDN in SDP", call_with_fqdn_in_sdp},
{ "Call with RTP IO mode", call_with_rtp_io_mode },
{ "Call with generic NACK RTCP feedback", call_with_generic_nack_rtcp_feedback }
{ "Call with generic NACK RTCP feedback", call_with_generic_nack_rtcp_feedback },
{ "Call with complex late offering", call_with_complex_late_offering },
{ "Call with custom RTP Modifier", call_with_custom_rtp_modifier },
{ "Call paused resumed with custom RTP Modifier", call_paused_resumed_with_custom_rtp_modifier },
{ "Call record with custom RTP Modifier", call_record_with_custom_rtp_modifier },
{ "Call with network switch", call_with_network_switch }
#if 0
,
{ "Call with network switch and ICE", call_with_network_switch_and_ice }
#endif
};
test_suite_t call_test_suite = {

View file

@ -27,6 +27,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "CUnit/Basic.h"
#include "CUnit/Automated.h"
#ifdef _WIN32
#if defined(__MINGW32__) || !defined(WINAPI_FAMILY_PARTITION) || !defined(WINAPI_PARTITION_DESKTOP)
#define BC_TESTER_WINDOWS_DESKTOP 1
@ -43,6 +44,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#endif
#endif
#ifdef __linux
/*for monitoring total space allocated via malloc*/
#include <malloc.h>
#endif
static char *bc_tester_resource_dir_prefix = NULL;
static char *bc_tester_writable_dir_prefix = NULL;
@ -62,6 +68,8 @@ char* xml_file = "CUnitAutomated-Results.xml";
int xml_enabled = 0;
char * suite_name;
char * test_name;
static long max_vm_kb = 0;
void (*tester_printf_va)(int level, const char *fmt, va_list args);
void bc_tester_printf(int level, const char *fmt, ...) {
@ -186,6 +194,22 @@ static void test_complete_message_handler(const CU_pTest pTest,
}
}
bc_tester_printf(bc_printf_verbosity_info,"%s\n", result);
#ifdef __linux
/* use mallinfo() to monitor allocated space. It is linux specific but other methods don't work:
* setrlimit() RLIMIT_DATA doesn't count memory allocated via mmap() (which is used internally by malloc)
* setrlimit() RLIMIT_AS works but also counts virtual memory allocated by thread stacks, which is very big and hardly controllable.
* setrlimit() RLIMIT_RSS does nothing interesting on linux.
* getrusage() of RSS is unreliable: memory blocks can be leaked without being read or written, which would not appear in RSS.
* mallinfo() itself is the less worse solution. Allocated bytes are returned as 'int' so limited to 2GB
*/
if (max_vm_kb){
struct mallinfo minfo = mallinfo();
if (minfo.uordblks > max_vm_kb * 1024){
bc_tester_printf(bc_printf_verbosity_error, "The program exceeded the maximum ammount of memory allocatable (%i bytes), aborting now.\n", minfo.uordblks);
abort();
}
}
#endif
}
#endif
@ -256,6 +280,10 @@ int bc_tester_run_tests(const char *suite_name, const char *test_name) {
}
}
}
#ifdef __linux
bc_tester_printf(bc_printf_verbosity_info, "Still %i kilobytes allocated when all tests are finished.", mallinfo().uordblks/1024);
#endif
return CU_get_number_of_tests_failed()!=0;
}
@ -272,6 +300,7 @@ void bc_tester_helper(const char *name, const char* additionnal_helper) {
#endif
"\t\t\t--xml\n"
"\t\t\t--xml-file <xml file name>\n"
"\t\t\t--max-alloc <size in ko> (maximum ammount of memory obtained via malloc allocator)\n"
"And additionally:\n"
"%s"
, name
@ -300,9 +329,19 @@ void bc_tester_init(void (*ftester_printf)(int level, const char *fmt, va_list a
bc_printf_verbosity_info = iverbosity_info;
}
void bc_tester_set_max_vm(long max_vm_kb){
#ifdef __linux
max_vm_kb = max_vm_kb;
bc_tester_printf(bc_printf_verbosity_info, "Maximum virtual memory space set to %li kilo bytes", max_vm_kb);
#else
bc_tester_printf(bc_printf_verbosity_error,"Maximum virtual memory space setting is only implemented on Linux.");
#endif
}
int bc_tester_parse_args(int argc, char **argv, int argid)
{
int i = argid;
if (strcmp(argv[i],"--help")==0){
return -1;
} else if (strcmp(argv[i],"--test")==0){
@ -325,7 +364,10 @@ int bc_tester_parse_args(int argc, char **argv, int argid)
xml_enabled = 1;
} else if (strcmp(argv[i], "--xml") == 0){
xml_enabled = 1;
}else {
} else if (strcmp(argv[i], "--max-alloc") == 0){
CHECK_ARG("--max-alloc", ++i, argc);
max_vm_kb = atol(argv[i]);
} else {
bc_tester_printf(bc_printf_verbosity_error, "Unknown option \"%s\"\n", argv[i]);
return -1;
}
@ -341,6 +383,10 @@ int bc_tester_parse_args(int argc, char **argv, int argid)
int bc_tester_start(void) {
int ret;
if (max_vm_kb)
bc_tester_set_max_vm(max_vm_kb);
if( xml_enabled ){
size_t size = strlen(xml_file) + strlen(".tmp") + 1;
char * xml_tmp_file = malloc(sizeof(char) * size);
@ -399,11 +445,8 @@ void bc_tester_uninit(void) {
}
static void bc_tester_set_dir_prefix(char **prefix, const char *name) {
size_t len = strlen(name);
if (*prefix != NULL) free(*prefix);
*prefix = malloc(len + 1);
strncpy(*prefix, name, len);
(*prefix)[len] = '\0';
*prefix = strdup(name);
}
const char * bc_tester_get_resource_dir_prefix(void) {
@ -428,7 +471,6 @@ static char * bc_tester_path(const char *prefix, const char *name) {
size_t len = strlen(prefix) + 1 + strlen(name) + 1;
file = malloc(len);
snprintf(file, len, "%s/%s", prefix, name);
file[strlen(file)] = '\0';
}
return file;
}

View file

@ -63,8 +63,7 @@ static void message_forking(void) {
LinphoneCoreManager* pauline = linphone_core_manager_new( transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc");
LinphoneCoreManager* marie2 = linphone_core_manager_new( "marie_rc");
MSList* lcs=ms_list_append(NULL,marie->lc);
char* to = linphone_address_as_string(marie->identity);
LinphoneChatRoom* chat_room = linphone_core_create_chat_room(pauline->lc,to);
LinphoneChatRoom* chat_room = linphone_core_get_chat_room(pauline->lc, marie->identity);
LinphoneChatMessage* message = linphone_chat_room_create_message(chat_room,"Bli bli bli \n blu");
lcs=ms_list_append(lcs,pauline->lc);
@ -78,7 +77,6 @@ static void message_forking(void) {
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(marie2);
linphone_core_manager_destroy(pauline);
ms_free(to);
ms_list_free(lcs);
}
@ -88,8 +86,7 @@ static void message_forking_with_unreachable_recipients(void) {
LinphoneCoreManager* marie2 = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* marie3 = linphone_core_manager_new( "marie_rc");
MSList* lcs=ms_list_append(NULL,marie->lc);
char* to = linphone_address_as_string(marie->identity);
LinphoneChatRoom* chat_room = linphone_core_create_chat_room(pauline->lc,to);
LinphoneChatRoom* chat_room = linphone_core_get_chat_room(pauline->lc, marie->identity);
LinphoneChatMessage* message = linphone_chat_room_create_message(chat_room,"Bli bli bli \n blu");
lcs=ms_list_append(lcs,pauline->lc);
@ -121,7 +118,6 @@ static void message_forking_with_unreachable_recipients(void) {
linphone_core_manager_destroy(marie2);
linphone_core_manager_destroy(marie3);
linphone_core_manager_destroy(pauline);
ms_free(to);
ms_list_free(lcs);
}
@ -131,8 +127,7 @@ static void message_forking_with_all_recipients_unreachable(void) {
LinphoneCoreManager* marie2 = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* marie3 = linphone_core_manager_new( "marie_rc");
MSList* lcs=ms_list_append(NULL,marie->lc);
char* to = linphone_address_as_string(marie->identity);
LinphoneChatRoom* chat_room = linphone_core_create_chat_room(pauline->lc,to);
LinphoneChatRoom* chat_room = linphone_core_get_chat_room(pauline->lc, marie->identity);
LinphoneChatMessage* message = linphone_chat_room_create_message(chat_room,"Bli bli bli \n blu");
lcs=ms_list_append(lcs,pauline->lc);
@ -172,7 +167,6 @@ static void message_forking_with_all_recipients_unreachable(void) {
linphone_core_manager_destroy(marie2);
linphone_core_manager_destroy(marie3);
linphone_core_manager_destroy(pauline);
ms_free(to);
ms_list_free(lcs);
}
@ -729,7 +723,6 @@ static void call_with_ipv6(void) {
static void file_transfer_message_rcs_to_external_body_client(void) {
if (transport_supported(LinphoneTransportTls)) {
LinphoneCoreManager* marie = linphone_core_manager_init( "marie_rc");
char* to;
LinphoneChatRoom* chat_room;
LinphoneChatMessage* message;
LinphoneChatMessageCbs *cbs;
@ -758,9 +751,8 @@ static void file_transfer_message_rcs_to_external_body_client(void) {
linphone_core_set_file_transfer_server(pauline->lc,"https://www.linphone.org:444/lft.php");
/* create a chatroom on pauline's side */
to = linphone_address_as_string(marie->identity);
chat_room = linphone_core_create_chat_room(pauline->lc,to);
ms_free(to);
chat_room = linphone_core_get_chat_room(pauline->lc, marie->identity);
/* create a file transfer message */
content = linphone_core_create_content(pauline->lc);
linphone_content_set_type(content,"image");
@ -803,14 +795,12 @@ static void file_transfer_message_rcs_to_external_body_client(void) {
}
void send_file_transfer_message_using_external_body_url(LinphoneCoreManager *marie, LinphoneCoreManager *pauline) {
char *to;
LinphoneChatMessageCbs *cbs;
LinphoneChatRoom *chat_room;
LinphoneChatMessage *message;
/* create a chatroom on pauline's side */
to = linphone_address_as_string(marie->identity);
chat_room = linphone_core_create_chat_room(pauline->lc,to);
chat_room = linphone_core_get_chat_room(pauline->lc, marie->identity);
message = linphone_chat_room_create_message(chat_room, NULL);
@ -876,7 +866,6 @@ static void file_transfer_message_external_body_to_rcs_client(void) {
}
static void dos_module_trigger(void) {
char *to;
LinphoneChatRoom *chat_room;
int i = 0;
const char* passmsg = "This one should pass through";
@ -887,8 +876,7 @@ static void dos_module_trigger(void) {
reset_counters(&marie->stat);
reset_counters(&pauline->stat);
to = linphone_address_as_string(marie->identity);
chat_room = linphone_core_create_chat_room(pauline->lc,to);
chat_room = linphone_core_get_chat_room(pauline->lc, marie->identity);
do {
char msg[128];
@ -913,7 +901,6 @@ static void dos_module_trigger(void) {
}
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
ms_free(to);
}
test_t flexisip_tests[] = {

View file

@ -196,12 +196,14 @@ int main (int argc, char *argv[])
liblinphone_tester_init(NULL);
// this allows to launch tester from outside of tester directory
if (strstr(argv[0], ".libs")) {
char res_dir[128] = {0};
// this allows to launch liblinphone_tester from outside of tester directory
strncpy(res_dir, argv[0], strstr(argv[0], ".libs")-argv[0]);
bc_tester_set_resource_dir_prefix(res_dir);
bc_tester_set_writable_dir_prefix(res_dir);
int prefix_length = strstr(argv[0], ".libs") - argv[0] + 1;
char *prefix = ms_strdup_printf("%s%.*s", argv[0][0] == '/' ? "" : "./", prefix_length, argv[0]);
ms_warning("Resource prefix set to %s", prefix);
bc_tester_set_resource_dir_prefix(prefix);
bc_tester_set_writable_dir_prefix(prefix);
ms_free(prefix);
}
for(i = 1; i < argc; ++i) {

View file

@ -24,6 +24,7 @@
#include "bc_tester_utils.h"
#include "linphonecore.h"
#include <mediastreamer2/msutils.h>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
@ -310,7 +311,7 @@ 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);
void linphone_call_cb(LinphoneCall *call,void * user_data);
void linphone_call_iframe_decoded_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_with_configfile(LinphoneMediaEncryption mode, bool_t enable_video,bool_t enable_relay,LinphoneFirewallPolicy policy,bool_t enable_tunnel, const char *marie_rc, const char *pauline_rc);
@ -320,7 +321,7 @@ bool_t pause_call_1(LinphoneCoreManager* mgr_1,LinphoneCall* call_1,LinphoneCore
bool_t compare_files(const char *path1, const char *path2);
void check_media_direction(LinphoneCoreManager* mgr, LinphoneCall *call, MSList* lcs,LinphoneMediaDirection audio_dir, LinphoneMediaDirection video_dir);
static const int audio_cmp_max_shift=10;
extern const MSAudioDiffParams audio_cmp_params;
/*
* this function return max value in the last 3 seconds*/
@ -335,6 +336,8 @@ int liblinphone_tester_setup();
void liblinphone_tester_init(void(*ftester_printf)(int level, const char *fmt, va_list args));
void liblinphone_tester_uninit(void);
extern const char *liblinphone_tester_mire_id;
#ifdef __cplusplus
};

View file

@ -183,12 +183,9 @@ void liblinphone_tester_chat_message_msg_state_changed(LinphoneChatMessage *msg,
static void text_message(void) {
LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc");
char* to;
LinphoneChatRoom* chat_room;
to = linphone_address_as_string(marie->identity);
chat_room = linphone_core_create_chat_room(pauline->lc,to);
ms_free(to);
chat_room = linphone_core_get_chat_room(pauline->lc,marie->identity);
{
int dummy=0;
wait_for_until(marie->lc,pauline->lc,&dummy,1,100); /*just to have time to purge message stored in the server*/
@ -206,16 +203,13 @@ static void text_message(void) {
}
static void text_message_within_dialog(void) {
char* to;
LinphoneChatRoom* chat_room;
LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc");
lp_config_set_int(pauline->lc->config,"sip","chat_use_call_dialogs",1);
to = linphone_address_as_string(marie->identity);
chat_room = linphone_core_create_chat_room(pauline->lc,to);
ms_free(to);
chat_room = linphone_core_get_chat_room(pauline->lc, marie->identity);
{
int dummy=0;
wait_for_until(marie->lc,pauline->lc,&dummy,1,100); /*just to have time to purge message stored in the server*/
@ -243,7 +237,6 @@ static void text_message_with_credential_from_auth_cb_auth_info_requested(Linpho
static void text_message_with_credential_from_auth_cb(void) {
char* to;
LinphoneChatRoom* chat_room;
LinphoneCoreVTable* vtable = linphone_core_v_table_new();
LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc");
@ -255,9 +248,7 @@ static void text_message_with_credential_from_auth_cb(void) {
vtable->auth_info_requested=text_message_with_credential_from_auth_cb_auth_info_requested;
linphone_core_add_listener(pauline->lc, vtable);
to = linphone_address_as_string(marie->identity);
chat_room = linphone_core_create_chat_room(pauline->lc,to);
ms_free(to);
chat_room = linphone_core_get_chat_room(pauline->lc, marie->identity);
{
int dummy=0;
wait_for_until(marie->lc,pauline->lc,&dummy,1,100); /*just to have time to purge message stored in the server*/
@ -275,16 +266,13 @@ static void text_message_with_credential_from_auth_cb(void) {
}
static void text_message_with_privacy(void) {
char *to;
LinphoneChatRoom* chat_room;
LinphoneProxyConfig* pauline_proxy;
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc");
to = linphone_address_as_string(marie->identity);
chat_room = linphone_core_create_chat_room(pauline->lc,to);
ms_free(to);
chat_room = linphone_core_get_chat_room(pauline->lc, marie->identity);
/*test proxy config privacy*/
linphone_core_get_default_proxy(pauline->lc,&pauline_proxy);
@ -313,7 +301,6 @@ static void text_message_compatibility_mode(void) {
LinphoneAddress* proxy_address;
char*tmp;
LCSipTransports transport;
char* to = linphone_address_as_string(pauline->identity);
LinphoneChatRoom* chat_room;
linphone_core_get_default_proxy(marie->lc,&proxy);
@ -336,7 +323,7 @@ static void text_message_compatibility_mode(void) {
BC_ASSERT_TRUE (wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphoneRegistrationOk,1));
chat_room = linphone_core_create_chat_room(marie->lc,to);
chat_room = linphone_core_get_chat_room(marie->lc, pauline->identity);
{
int dummy=0;
wait_for_until(marie->lc,pauline->lc,&dummy,1,100); /*just to have time to purge message stored in the server*/
@ -363,8 +350,7 @@ static void text_message_with_ack(void) {
pauline = linphone_core_manager_new( "pauline_tcp_rc");
{
char* to = linphone_address_as_string(marie->identity);
LinphoneChatRoom* chat_room = linphone_core_create_chat_room(pauline->lc,to);
LinphoneChatRoom* chat_room = linphone_core_get_chat_room(pauline->lc, marie->identity);
LinphoneChatMessage* message = linphone_chat_room_create_message(chat_room,"Bli bli bli \n blu");
LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(message);
int dummy=0;
@ -376,7 +362,6 @@ static void text_message_with_ack(void) {
BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceived,1));
BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneMessageDelivered,1));
BC_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageInProgress,1, int, "%d");
ms_free(to);
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
}
@ -390,8 +375,7 @@ static void text_message_with_ack(void) {
static void text_message_with_external_body(void) {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc");
char *to = linphone_address_as_string(marie->identity);
LinphoneChatRoom* chat_room = linphone_core_create_chat_room(pauline->lc,to);
LinphoneChatRoom* chat_room = linphone_core_get_chat_room(pauline->lc, marie->identity);
LinphoneChatMessage* message = linphone_chat_room_create_message(chat_room,"Bli bli bli \n blu");
LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(message);
@ -420,7 +404,6 @@ static void text_message_with_external_body(void) {
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
ms_free(to);
}
bool_t compare_files(const char *path1, const char *path2) {
@ -441,7 +424,6 @@ bool_t compare_files(const char *path1, const char *path2) {
static void file_transfer_message(void) {
if (transport_supported(LinphoneTransportTls)) {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
char* to;
LinphoneChatRoom* chat_room;
LinphoneChatMessage* message;
LinphoneChatMessageCbs *cbs;
@ -464,9 +446,7 @@ static void file_transfer_message(void) {
linphone_core_set_file_transfer_server(pauline->lc,"https://www.linphone.org:444/lft.php");
/* create a chatroom on pauline's side */
to = linphone_address_as_string(marie->identity);
chat_room = linphone_core_create_chat_room(pauline->lc,to);
ms_free(to);
chat_room = linphone_core_get_chat_room(pauline->lc, marie->identity);
/* create a file transfer message */
content = linphone_core_create_content(pauline->lc);
linphone_content_set_type(content,"image");
@ -514,7 +494,6 @@ static void small_file_transfer_message(void) {
if (transport_supported(LinphoneTransportTls)) {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
int i;
char* to;
LinphoneChatRoom* chat_room;
LinphoneChatMessage* message;
LinphoneChatMessageCbs *cbs;
@ -534,9 +513,7 @@ static void small_file_transfer_message(void) {
linphone_core_set_file_transfer_server(pauline->lc,"https://www.linphone.org:444/lft.php");
/* create a chatroom on pauline's side */
to = linphone_address_as_string(marie->identity);
chat_room = linphone_core_create_chat_room(pauline->lc,to);
ms_free(to);
chat_room = linphone_core_get_chat_room(pauline->lc, marie->identity);
/* create a file transfer message */
content = linphone_core_create_content(pauline->lc);
linphone_content_set_type(content,"text");
@ -584,7 +561,6 @@ static FILE* fopen_from_write_dir(const char * name, const char * mode) {
static void lime_file_transfer_message_base(bool_t encrypt_file) {
int i;
char *to;
FILE *ZIDCacheMarieFD, *ZIDCachePaulineFD;
LinphoneCoreManager *marie, *pauline;
LinphoneChatRoom *chat_room;
@ -639,9 +615,8 @@ static void lime_file_transfer_message_base(bool_t encrypt_file) {
linphone_core_set_file_transfer_server(pauline->lc,"https://www.linphone.org:444/lft.php");
/* create a chatroom on pauline's side */
to = linphone_address_as_string(marie->identity);
chat_room = linphone_core_create_chat_room(pauline->lc,to);
ms_free(to);
chat_room = linphone_core_get_chat_room(pauline->lc, marie->identity);
/* create a file transfer message */
content = linphone_core_create_content(pauline->lc);
linphone_content_set_type(content,"text");
@ -869,7 +844,6 @@ static void lime_unit(void) {
}
static void lime_text_message(void) {
char* to;
FILE *ZIDCacheMarieFD, *ZIDCachePaulineFD;
LinphoneChatRoom* chat_room;
char* filepath;
@ -896,9 +870,7 @@ static void lime_text_message(void) {
linphone_core_set_zrtp_secrets_file(pauline->lc, filepath);
ms_free(filepath);
to = linphone_address_as_string(marie->identity);
chat_room = linphone_core_create_chat_room(pauline->lc,to);
ms_free(to);
chat_room = linphone_core_get_chat_room(pauline->lc, marie->identity);
linphone_chat_room_send_message(chat_room,"Bla bla bla bla");
BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceived,1));
@ -916,7 +888,6 @@ static void file_transfer_message_io_error_upload(void) {
if (transport_supported(LinphoneTransportTls)) {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
int i;
char* to;
LinphoneChatRoom* chat_room;
LinphoneChatMessage* message;
LinphoneChatMessageCbs *cbs;
@ -938,8 +909,7 @@ static void file_transfer_message_io_error_upload(void) {
linphone_core_set_file_transfer_server(pauline->lc,"https://www.linphone.org:444/lft.php");
/* create a chatroom on pauline's side */
to = linphone_address_as_string(marie->identity);
chat_room = linphone_core_create_chat_room(pauline->lc,to);
chat_room = linphone_core_get_chat_room(pauline->lc, marie->identity);
/* create a file transfer message */
content = linphone_core_create_content(pauline->lc);
@ -986,7 +956,6 @@ static void file_transfer_message_io_error_download(void) {
if (transport_supported(LinphoneTransportTls)) {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
int i;
char* to;
LinphoneChatRoom* chat_room;
LinphoneChatMessage* message;
LinphoneContent content;
@ -1007,9 +976,7 @@ static void file_transfer_message_io_error_download(void) {
linphone_core_set_file_transfer_server(pauline->lc,"https://www.linphone.org:444/lft.php");
/* create a chatroom on pauline's side */
to = linphone_address_as_string(marie->identity);
chat_room = linphone_core_create_chat_room(pauline->lc,to);
ms_free(to);
chat_room = linphone_core_get_chat_room(pauline->lc, marie->identity);
/* create a file transfer message */
memset(&content,0,sizeof(content));
@ -1054,7 +1021,6 @@ static void file_transfer_message_upload_cancelled(void) {
if (transport_supported(LinphoneTransportTls)) {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
int i;
char* to;
LinphoneChatRoom* chat_room;
LinphoneChatMessage* message;
LinphoneChatMessageCbs *cbs;
@ -1076,8 +1042,7 @@ static void file_transfer_message_upload_cancelled(void) {
linphone_core_set_file_transfer_server(pauline->lc,"https://www.linphone.org:444/lft.php");
/* create a chatroom on pauline's side */
to = linphone_address_as_string(marie->identity);
chat_room = linphone_core_create_chat_room(pauline->lc,to);
chat_room = linphone_core_get_chat_room(pauline->lc, marie->identity);
/* create a file transfer message */
content = linphone_core_create_content(pauline->lc);
@ -1182,7 +1147,6 @@ static void file_transfer_message_download_cancelled(void) {
static void file_transfer_using_external_body_url(void) {
if (transport_supported(LinphoneTransportTls)) {
LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc");
char *to;
LinphoneChatMessageCbs *cbs;
LinphoneChatRoom *chat_room;
LinphoneChatMessage *message;
@ -1195,8 +1159,7 @@ static void file_transfer_using_external_body_url(void) {
linphone_core_enable_lime(pauline->lc, FALSE);
/* create a chatroom on pauline's side */
to = linphone_address_as_string(marie->identity);
chat_room = linphone_core_create_chat_room(pauline->lc,to);
chat_room = linphone_core_get_chat_room(pauline->lc, marie->identity);
message = linphone_chat_room_create_message(chat_room, NULL);
@ -1212,7 +1175,6 @@ static void file_transfer_using_external_body_url(void) {
}
BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &marie->stat.number_of_LinphoneMessageExtBodyReceived, 1));
BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &pauline->stat.number_of_LinphoneMessageInProgress, 1));
ms_free(to);
linphone_core_manager_destroy(pauline);
linphone_core_manager_destroy(marie);
}
@ -1221,7 +1183,6 @@ static void file_transfer_using_external_body_url(void) {
static void file_transfer_2_messages_simultaneously() {
if (transport_supported(LinphoneTransportTls)) {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
char* to;
LinphoneChatRoom* pauline_room;
LinphoneChatMessage* message;
LinphoneChatMessage* message2;
@ -1245,9 +1206,7 @@ static void file_transfer_2_messages_simultaneously() {
linphone_core_set_file_transfer_server(pauline->lc,"https://www.linphone.org:444/lft.php");
/* create a chatroom on pauline's side */
to = linphone_address_as_string(marie->identity);
pauline_room = linphone_core_create_chat_room(pauline->lc,to);
ms_free(to);
pauline_room = linphone_core_get_chat_room(pauline->lc, marie->identity);
/* create a file transfer message */
content = linphone_core_create_content(pauline->lc);
linphone_content_set_type(content,"image");
@ -1288,7 +1247,7 @@ static void file_transfer_2_messages_simultaneously() {
BC_ASSERT_EQUAL(ms_list_size(linphone_core_get_chat_rooms(marie->lc)), 1, int, "%d");
if (ms_list_size(linphone_core_get_chat_rooms(marie->lc)) != 1) {
char * buf = ms_strdup_printf("Found %d rooms instead of 1: ", ms_list_size(linphone_core_get_chat_rooms(marie->lc)));
MSList *it = linphone_core_get_chat_rooms(marie->lc);
const MSList *it = linphone_core_get_chat_rooms(marie->lc);
while (it) {
const LinphoneAddress * peer = linphone_chat_room_get_peer_address(it->data);
buf = ms_strcat_printf("%s, ", linphone_address_get_username(peer));
@ -1325,8 +1284,7 @@ static void text_message_with_send_error(void) {
LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc");
char *to = linphone_address_as_string(pauline->identity);
LinphoneChatRoom* chat_room = linphone_core_create_chat_room(marie->lc,to);
LinphoneChatRoom* chat_room = linphone_core_get_chat_room(marie->lc, pauline->identity);
LinphoneChatMessage* message = linphone_chat_room_create_message(chat_room,"Bli bli bli \n blu");
LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(message);
reset_counters(&marie->stat);
@ -1361,7 +1319,6 @@ static void text_message_with_send_error(void) {
linphone_core_refresh_registers(marie->lc);
BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneRegistrationOk,marie->stat.number_of_LinphoneRegistrationOk + 1));
ms_free(to);
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
}
@ -1369,9 +1326,7 @@ static void text_message_with_send_error(void) {
static void text_message_denied(void) {
LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc");
char *to = linphone_address_as_string(pauline->identity);
LinphoneChatRoom* chat_room = linphone_core_create_chat_room(marie->lc,to);
LinphoneChatRoom* chat_room = linphone_core_get_chat_room(marie->lc, pauline->identity);
LinphoneChatMessage* message = linphone_chat_room_create_message(chat_room,"Bli bli bli \n blu");
LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(message);
@ -1388,7 +1343,6 @@ static void text_message_denied(void) {
BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageNotDelivered,1));
BC_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageReceived,0, int, "%d");
ms_free(to);
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
}
@ -1471,17 +1425,13 @@ static void info_message_with_body(){
}
static void is_composing_notification(void) {
char* to;
LinphoneChatRoom* chat_room;
int dummy = 0;
LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc");
to = linphone_address_as_string(marie->identity);
chat_room = linphone_core_create_chat_room(pauline->lc, to);
ms_free(to);
chat_room = linphone_core_get_chat_room(pauline->lc, marie->identity);
linphone_core_get_chat_room(marie->lc, pauline->identity); /*make marie create the chatroom with pauline, which is necessary for receiving the is-composing*/
{
int dummy=0;
wait_for_until(marie->lc,pauline->lc,&dummy,1,100); /*just to have time to purge message stored in the server*/
@ -1557,7 +1507,7 @@ static void message_storage_migration() {
LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc");
char *src_db = bc_tester_res("messages.db");
char *tmp_db = bc_tester_file("tmp.db");
MSList* chatrooms;
const MSList* chatrooms;
BC_ASSERT_EQUAL_FATAL(message_tester_copy_file(src_db, tmp_db), 0, int, "%d");
@ -1694,6 +1644,16 @@ static void history_messages_count() {
#endif
static void text_status_after_destroying_chat_room() {
LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc");
LinphoneChatRoom *chatroom = linphone_core_get_chat_room_from_uri(marie->lc, "<sip:Jehan@sip.linphone.org>");
LinphoneChatMessage *message = linphone_chat_room_create_message(chatroom, "hello");
linphone_chat_room_send_chat_message(chatroom, message);
linphone_chat_room_unref(chatroom);
wait_for_until(marie->lc, NULL, &marie->stat.number_of_LinphoneMessageNotDelivered, 1, 1000);
linphone_core_manager_destroy(marie);
}
test_t message_tests[] = {
{ "Text message", text_message },
{ "Text message within call's dialog", text_message_within_dialog},
@ -1726,6 +1686,7 @@ test_t message_tests[] = {
,{ "History count", history_messages_count }
,{ "History range", history_range_full_test }
#endif
,{ "Text status after destroying chat room", text_status_after_destroying_chat_room },
};
test_suite_t message_test_suite = {

View file

@ -58,7 +58,7 @@ static void call_multicast_base(bool_t video) {
BC_ASSERT_GREATER(linphone_core_manager_get_max_audio_down_bw(marie),70,int,"%d");
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_set_next_video_frame_decoded_callback(linphone_core_get_current_call(marie->lc),linphone_call_iframe_decoded_cb,marie->lc);
linphone_call_send_vfu_request(linphone_core_get_current_call(marie->lc));
BC_ASSERT_TRUE( wait_for(marie->lc,pauline->lc,&marie->stat.number_of_IframeDecoded,1));
}
@ -147,7 +147,7 @@ static void early_media_with_multicast_base(bool_t video) {
/* 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_call_set_next_video_frame_decoded_callback(linphone_core_get_current_call(pauline->lc),linphone_call_iframe_decoded_cb,pauline->lc);
}
linphone_core_accept_early_media(pauline->lc, linphone_core_get_current_call(pauline->lc));
@ -158,7 +158,7 @@ static void early_media_with_multicast_base(bool_t video) {
/* 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_call_set_next_video_frame_decoded_callback(linphone_core_get_current_call(pauline2->lc),linphone_call_iframe_decoded_cb,pauline2->lc);
}
linphone_core_accept_early_media(pauline2->lc, linphone_core_get_current_call(pauline2->lc));

View file

@ -18,10 +18,18 @@
#include "liblinphone_tester.h"
#include <stdlib.h>
const char* phone_normalization(LinphoneProxyConfig *proxy, const char* in) {
static char result[255];
linphone_proxy_config_normalize_number(proxy, in, result, 255-1);
return result;
char * output = linphone_proxy_config_normalize_phone_number(proxy, in);
if (output) {
memcpy(result, output, strlen(output)+1);
ms_free(output);
return result;
} else {
return NULL;
}
}
static void phone_normalization_without_proxy() {
@ -32,7 +40,7 @@ static void phone_normalization_without_proxy() {
BC_ASSERT_STRING_EQUAL(phone_normalization(NULL, "+33012345678"), "+33012345678");
BC_ASSERT_STRING_EQUAL(phone_normalization(NULL, "+3301234567891"), "+3301234567891");
BC_ASSERT_STRING_EQUAL(phone_normalization(NULL, "+33 01234567891"), "+3301234567891");
BC_ASSERT_STRING_EQUAL(phone_normalization(NULL, "I_AM_NOT_A_NUMBER"), "I_AM_NOT_A_NUMBER"); // invalid phone number
BC_ASSERT_PTR_NULL(phone_normalization(NULL, "I_AM_NOT_A_NUMBER")); // invalid phone number
}
static void phone_normalization_with_proxy() {
@ -50,7 +58,7 @@ static void phone_normalization_with_proxy() {
BC_ASSERT_STRING_EQUAL(phone_normalization(proxy, "0012345678"), "+12345678");
BC_ASSERT_STRING_EQUAL(phone_normalization(proxy, "01 2345678"), "+33012345678");
BC_ASSERT_STRING_EQUAL(phone_normalization(proxy, "01234567891"), "+33234567891"); // invalid phone number (too long)
BC_ASSERT_STRING_EQUAL(phone_normalization(proxy, "I_AM_NOT_A_NUMBER"), "I_AM_NOT_A_NUMBER"); // invalid phone number
BC_ASSERT_PTR_NULL(phone_normalization(proxy, "I_AM_NOT_A_NUMBER")); // invalid phone number
BC_ASSERT_STRING_EQUAL(phone_normalization(proxy, "+990012345678"), "+990012345678");
@ -60,7 +68,7 @@ static void phone_normalization_with_proxy() {
BC_ASSERT_STRING_EQUAL(phone_normalization(proxy, "+31952636505"), "+31952636505");
BC_ASSERT_STRING_EQUAL(phone_normalization(proxy, "0033952636505"), "+33952636505");
BC_ASSERT_STRING_EQUAL(phone_normalization(proxy, "0033952636505"), "+33952636505");
BC_ASSERT_STRING_EQUAL(phone_normalization(proxy, "toto"), "toto");
BC_ASSERT_PTR_NULL(phone_normalization(proxy, "toto"));
linphone_proxy_config_set_dial_prefix(proxy, "99");
BC_ASSERT_STRING_EQUAL(phone_normalization(proxy, "0012345678"), "+12345678");

View file

@ -233,13 +233,13 @@ void linphone_proxy_config_is_server_config_changed_test() {
linphone_proxy_config_destroy(proxy_config);
}
static void chat_root_test(void) {
static void chat_room_test(void) {
LinphoneCoreVTable v_table;
LinphoneCore* lc;
memset (&v_table,0,sizeof(v_table));
lc = linphone_core_new(&v_table,NULL,NULL,NULL);
BC_ASSERT_PTR_NOT_NULL_FATAL(lc);
linphone_core_create_chat_room(lc,"sip:toto@titi.com");
BC_ASSERT_PTR_NOT_NULL(linphone_core_get_chat_room_from_uri(lc,"sip:toto@titi.com"));
linphone_core_destroy(lc);
}
@ -301,7 +301,7 @@ test_t setup_tests[] = {
{ "LPConfig zero_len value from buffer", linphone_lpconfig_from_buffer_zerolen_value },
{ "LPConfig zero_len value from file", linphone_lpconfig_from_file_zerolen_value },
{ "LPConfig zero_len value from XML", linphone_lpconfig_from_xml_zerolen_value },
{ "Chat room", chat_root_test },
{ "Chat room", chat_room_test },
{ "Devices reload", devices_reload_test },
{ "Codec usability", codec_usability_test }
};

View file

@ -37,6 +37,8 @@ static int liblinphone_tester_keep_accounts_flag = 0;
static int liblinphone_tester_keep_record_files = FALSE;
int manager_count = 0;
const MSAudioDiffParams audio_cmp_params = {10,2000};
const char* test_domain="sipopen.example.org";
const char* auth_domain="sip.example.org";
const char* test_username="liblinphone_tester";
@ -44,6 +46,8 @@ const char* test_password="secret";
const char* test_route="sip2.linphone.org";
const char *userhostsfile = "tester_hosts";
const char *liblinphone_tester_mire_id="Mire: Mire (synthetic moving picture)";
static void network_reachable(LinphoneCore *lc, bool_t reachable) {
stats* counters;
ms_message("Network reachable [%s]",reachable?"TRUE":"FALSE");
@ -237,6 +241,10 @@ bool_t transport_supported(LinphoneTransportType transport) {
}
static void display_status(LinphoneCore *lc, const char *status){
ms_message("display_status(): %s",status);
}
LinphoneCoreManager* linphone_core_manager_init(const char* rc_file) {
LinphoneCoreManager* mgr= ms_new0(LinphoneCoreManager,1);
char *rc_path = NULL;
@ -260,6 +268,7 @@ LinphoneCoreManager* linphone_core_manager_init(const char* rc_file) {
mgr->v_table.network_reachable=network_reachable;
mgr->v_table.dtmf_received=dtmf_received;
mgr->v_table.call_stats_updated=call_stats_updated;
mgr->v_table.display_status=display_status;
reset_counters(&mgr->stat);
if (rc_file) rc_path = ms_strdup_printf("rcfiles/%s", rc_file);

View file

@ -430,28 +430,44 @@ static void forked_outgoing_early_media_video_call_with_inactive_audio_test(void
linphone_core_invite_address_with_params(pauline->lc, marie1->identity, pauline_params);
linphone_call_params_destroy(pauline_params);
BC_ASSERT_TRUE(wait_for_list(lcs, &marie1->stat.number_of_LinphoneCallIncomingReceived, 1, 3000));
BC_ASSERT_TRUE(wait_for_list(lcs, &marie2->stat.number_of_LinphoneCallIncomingReceived, 1, 3000));
marie1_call = linphone_core_get_current_call(marie1->lc);
marie2_call = linphone_core_get_current_call(marie2->lc);
if (marie1_call){
linphone_call_set_next_video_frame_decoded_callback(marie1_call, linphone_call_iframe_decoded_cb, marie1->lc);
}
if (marie2_call){
linphone_call_set_next_video_frame_decoded_callback(marie2_call, linphone_call_iframe_decoded_cb, marie2->lc);
}
BC_ASSERT_TRUE(wait_for_list(lcs, &marie1->stat.number_of_LinphoneCallIncomingEarlyMedia, 1, 3000));
BC_ASSERT_TRUE(wait_for_list(lcs, &marie2->stat.number_of_LinphoneCallIncomingEarlyMedia, 1, 3000));
BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallOutgoingEarlyMedia, 1, 3000));
pauline_call = linphone_core_get_current_call(pauline->lc);
marie1_call = linphone_core_get_current_call(marie1->lc);
marie2_call = linphone_core_get_current_call(marie2->lc);
BC_ASSERT_PTR_NOT_NULL(pauline_call);
BC_ASSERT_PTR_NOT_NULL(marie1_call);
BC_ASSERT_PTR_NOT_NULL(marie2_call);
if (pauline_call && marie1_call && marie2_call) {
linphone_call_set_next_video_frame_decoded_callback(pauline_call, linphone_call_iframe_decoded_cb, pauline->lc);
/* wait a bit that streams are established */
wait_for_list(lcs, &dummy, 1, 6000);
wait_for_list(lcs, &dummy, 1, 3000);
BC_ASSERT_EQUAL(linphone_call_get_audio_stats(pauline_call)->download_bandwidth, 0, float, "%f");
BC_ASSERT_EQUAL(linphone_call_get_audio_stats(marie1_call)->download_bandwidth, 0, float, "%f");
BC_ASSERT_EQUAL(linphone_call_get_audio_stats(marie2_call)->download_bandwidth, 0, float, "%f");
BC_ASSERT_EQUAL(linphone_call_get_video_stats(pauline_call)->download_bandwidth, 0, float, "%f");
BC_ASSERT_LOWER(linphone_call_get_video_stats(pauline_call)->download_bandwidth, 11, float, "%f"); /* because of stun packets*/
BC_ASSERT_GREATER(linphone_call_get_video_stats(marie1_call)->download_bandwidth, 0, float, "%f");
BC_ASSERT_GREATER(linphone_call_get_video_stats(marie2_call)->download_bandwidth, 0, float, "%f");
BC_ASSERT_GREATER(marie1->stat.number_of_IframeDecoded, 1, int, "%i");
BC_ASSERT_GREATER(marie2->stat.number_of_IframeDecoded, 1, int, "%i");
linphone_call_params_set_audio_direction(marie1_params, LinphoneMediaDirectionSendRecv);
linphone_core_accept_call_with_params(marie1->lc, linphone_core_get_current_call(marie1->lc), marie1_params);
@ -467,6 +483,7 @@ static void forked_outgoing_early_media_video_call_with_inactive_audio_test(void
BC_ASSERT_GREATER(linphone_call_get_audio_stats(marie1_call)->download_bandwidth, 71, float, "%f");
BC_ASSERT_GREATER(linphone_call_get_video_stats(pauline_call)->download_bandwidth, 0, float, "%f");
BC_ASSERT_GREATER(linphone_call_get_video_stats(marie1_call)->download_bandwidth, 0, float, "%f");
BC_ASSERT_GREATER(pauline->stat.number_of_IframeDecoded, 1, int, "%i");
/* send an INFO in reverse side to check that dialogs are properly established */
info = linphone_core_create_info_message(marie1->lc);

View file

@ -50,4 +50,20 @@ lp_autoanswer_LDADD=\
endif
if ENABLE_TESTS
noinst_PROGRAMS=test_lsd test_ecc test_numbers
test_lsd_SOURCES=test_lsd.c
test_lsd_CFLAGS=$(COMMON_CFLAGS)
test_lsd_LDADD=$(top_builddir)/coreapi/liblinphone.la
test_ecc_SOURCES=test_ecc.c
test_ecc_CFLAGS=$(COMMON_CFLAGS)
test_ecc_LDADD=$(top_builddir)/coreapi/liblinphone.la
test_numbers_SOURCES=test_numbers.c
test_numbers_CFLAGS=$(COMMON_CFLAGS)
test_numbers_LDADD=$(top_builddir)/coreapi/liblinphone.la
endif

View file

@ -18,47 +18,46 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "linphonecore.h"
#include "linphonecore_utils.h"
#if _MSC_VER
#include <io.h>
#endif
static void calibration_finished(LinphoneCore *lc, LinphoneEcCalibratorStatus status, int delay, void *data){
ms_message("echo calibration finished %s.",status==LinphoneEcCalibratorDone ? "successfully" : "with faillure");
if (status==LinphoneEcCalibratorDone) ms_message("Measured delay is %i",delay);
static void calibration_finished(LinphoneCore *lc, LinphoneEcCalibratorStatus status, int delay, void *data) {
ms_message("echo calibration finished %s.", status == LinphoneEcCalibratorDone ? "successfully" : "with faillure");
if (status == LinphoneEcCalibratorDone)
ms_message("Measured delay is %i", delay);
}
static char config_file[1024];
void parse_args(int argc, char *argv[]){
void parse_args(int argc, char *argv[]) {
#ifndef F_OK
#define F_OK 4
#endif
if (argc != 3 || strncmp("-c",argv[1], 2) || access(argv[2],F_OK)!=0) {
if (argc != 3 || strncmp("-c", argv[1], 2) || access(argv[2], F_OK) != 0) {
printf("Usage: test_ecc [-c config_file] where config_file will be written with the detected value\n");
exit(-1);
}
strncpy(config_file,argv[2],1024);
strncpy(config_file, argv[2], 1024);
}
int main(int argc, char *argv[]){
int count=0;
LinphoneCoreVTable vtable={0};
int main(int argc, char *argv[]) {
int count = 0;
LinphoneCoreVTable vtable = {0};
LinphoneCore *lc;
if (argc>1) parse_args(argc,argv);
lc=linphone_core_new(&vtable,config_file,NULL,NULL);
if (argc > 1)
parse_args(argc, argv);
lc = linphone_core_new(&vtable, config_file, NULL, NULL);
linphone_core_enable_logs(NULL);
linphone_core_start_echo_calibration(lc,calibration_finished,NULL,NULL,NULL);
while(count++<1000){
linphone_core_start_echo_calibration(lc, calibration_finished, NULL, NULL, NULL);
while (count++ < 1000) {
linphone_core_iterate(lc);
ms_usleep(10000);
}
linphone_core_destroy(lc);
return 0;
}

103
tools/test_lsd.c Normal file
View file

@ -0,0 +1,103 @@
/*
linphone
Copyright (C) 2010 Simon MORLAT (simon.morlat@linphone.org)
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/* Linphone Sound Daemon: is a lightweight utility to play sounds to speaker during a conversation.
This is useful for embedded platforms, where sound apis are not performant enough to allow
simultaneous sound access.
This file is a test program that plays several sound files and places a call simultatenously.
*/
#include "linphonecore_utils.h"
static void play_finished(LsdPlayer *p) {
const char *filename = (const char *)lsd_player_get_user_pointer(p);
ms_message("Playing of %s is finished.", filename);
if (!lsd_player_loop_enabled(p)) {
linphone_sound_daemon_release_player(lsd_player_get_daemon(p), p);
}
}
static void wait_a_bit(LinphoneCore *lc, int seconds) {
time_t orig = ms_time(NULL);
while (ms_time(NULL) - orig < seconds) {
/* we need to call iterate to receive notifications */
linphone_core_iterate(lc);
ms_usleep(50000);
}
}
int main(int argc, char *argv[]) {
LinphoneCore *lc;
LinphoneCoreVTable vtable = {0};
LinphoneSoundDaemon *lsd;
LsdPlayer *p;
linphone_core_enable_logs(stdout);
lc = linphone_core_new(&vtable, NULL, NULL, NULL);
lsd = linphone_sound_daemon_new(NULL, 44100, 1);
linphone_core_use_sound_daemon(lc, lsd);
/* start a play */
p = linphone_sound_daemon_get_player(lsd);
lsd_player_set_callback(p, play_finished);
lsd_player_set_user_pointer(p, "share/hello8000.wav");
lsd_player_play(p, "share/hello8000.wav");
wait_a_bit(lc, 2);
/*start another one */
p = linphone_sound_daemon_get_player(lsd);
lsd_player_set_callback(p, play_finished);
lsd_player_set_user_pointer(p, "share/hello16000.wav");
lsd_player_enable_loop(p, TRUE);
lsd_player_play(p, "share/hello16000.wav");
/* after a few seconds decrease the volume */
wait_a_bit(lc, 3);
lsd_player_set_gain(p, 0.3);
wait_a_bit(lc, 5);
/*now play some stereo music*/
p = linphone_sound_daemon_get_player(lsd);
lsd_player_set_callback(p, play_finished);
lsd_player_set_user_pointer(p, "share/rings/rock.wav");
lsd_player_play(p, "share/rings/rock.wav");
wait_a_bit(lc, 2);
/*now play some stereo music at 22khz in order to test
stereo resampling */
p = linphone_sound_daemon_get_player(lsd);
lsd_player_set_callback(p, play_finished);
lsd_player_set_user_pointer(p, "share/rings/bigben.wav");
lsd_player_play(p, "share/rings/bigben.wav");
wait_a_bit(lc, 6);
/* now place an outgoing call if sip address argument is given */
if (argc > 1) {
linphone_core_invite(lc, argv[1]);
wait_a_bit(lc, 10);
linphone_core_terminate_call(lc, NULL);
}
linphone_core_use_sound_daemon(lc, NULL);
linphone_sound_daemon_destroy(lsd);
linphone_core_destroy(lc);
return 0;
}

57
tools/test_numbers.c Normal file
View file

@ -0,0 +1,57 @@
/*
linphone
Copyright (C) 2012 Belledonne Communications SARL
Author: Simon MORLAT (simon.morlat@linphone.org)
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "linphonecore.h"
#include "linphonecore_utils.h"
int main(int argc, char *argv[]) {
LinphoneProxyConfig *cfg;
char *normalized_number;
if (argc < 2) {
fprintf(stderr, "Usage:\n%s <phone number> [<country code>] [--escape-plus]\nReturns normalized number.",
argv[0]);
return -1;
}
linphone_core_enable_logs(stderr);
linphone_core_set_log_level(ORTP_DEBUG);
cfg = linphone_proxy_config_new();
if (argc > 2)
linphone_proxy_config_set_dial_prefix(cfg, argv[2]);
if (argc > 3 && strcmp(argv[3], "--escape-plus") == 0)
linphone_proxy_config_set_dial_escape_plus(cfg, TRUE);
normalized_number = linphone_proxy_config_normalize_phone_number(cfg, argv[1]);
if (!normalized_number) {
printf("Invalid phone number: %s\n", argv[1]);
} else {
printf("Normalized number is %s\n", normalized_number);
/*check extracted ccc*/
if (linphone_proxy_config_get_dial_prefix(cfg) != NULL) {
if (linphone_dial_plan_lookup_ccc_from_e164(normalized_number) !=
atoi(linphone_proxy_config_get_dial_prefix(cfg))) {
printf("Error ccc [%i] not correctly parsed\n",
linphone_dial_plan_lookup_ccc_from_e164(normalized_number));
} else {
printf("Extracted ccc is [%i] \n", linphone_dial_plan_lookup_ccc_from_e164(normalized_number));
}
}
}
return 0;
}