diff --git a/Makefile.am b/Makefile.am index e0c306806..da3a8d7e3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -3,13 +3,20 @@ # let make re-run automake upon need ACLOCAL_AMFLAGS = -I m4 $(ACLOCAL_MACOS_FLAGS) -if EXTERNAL_ORTP -ORTP_DIR = +if EXTERNAL_MEDIASTREAMER +MS2_DIR= else -ORTP_DIR = oRTP +MS2_DIR=mediastreamer2 endif -SUBDIRS = m4 pixmaps po $(ORTP_DIR) mediastreamer2\ +if EXTERNAL_ORTP +ORTP_DIR= +else +ORTP_DIR=oRTP +endif + + +SUBDIRS = m4 pixmaps po $(ORTP_DIR) $(MS2_DIR) \ coreapi console gtk share scripts diff --git a/configure.in b/configure.ac similarity index 89% rename from configure.in rename to configure.ac index fc1c4c0a7..14d5a3566 100644 --- a/configure.in +++ b/configure.ac @@ -1,7 +1,8 @@ dnl Process this file with autoconf to produce a configure script. -AC_INIT([linphone],[3.3.99.3],[linphone-developers@nongnu.org]) +AC_INIT([linphone],[3.3.99.4],[linphone-developers@nongnu.org]) AC_CANONICAL_SYSTEM +AC_CONFIG_SRCDIR([coreapi/linphonecore.c]) dnl Source packaging numbers @@ -28,7 +29,8 @@ AC_SUBST(LINPHONE_VERSION) AC_MSG_NOTICE([$PACKAGE_NAME-$PACKAGE_VERSION A full featured audio/video sip phone.]) AC_MSG_NOTICE([licensed under the terms of the General Public License (GPL)]) -AM_INIT_AUTOMAKE([tar-ustar]) +AM_INIT_AUTOMAKE +AC_SUBST([LIBTOOL_DEPS]) m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])],) AC_CONFIG_HEADER(config.h) AC_CONFIG_MACRO_DIR([m4]) @@ -67,7 +69,8 @@ AC_SUBST(CONSOLE_FLAGS) AC_SUBST(GUI_FLAGS) dnl localization tools -ifdef([IT_PROG_INTLTOOL],[IT_PROG_INTLTOOL],[AC_PROG_INTLTOOL]) +IT_PROG_INTLTOOL([0.40], [no-xml]) + dnl Initialize libtool AC_LIBTOOL_WIN32_DLL AC_PROG_LIBTOOL @@ -374,15 +377,40 @@ fi AC_SUBST(STRICT_OPTIONS) -AC_CONFIG_SUBDIRS( mediastreamer2 ) +top_srcdir=`dirname $0` + +AC_ARG_ENABLE([external-mediastreamer], + [AS_HELP_STRING([--enable-external-mediastreamer],[Use external mediastreamer library])],, + [enable_external_mediastreamer=no]) + +AS_CASE($enable_external_mediastreamer, + [yes],[ + PKG_CHECK_MODULES([MEDIASTREAMER], [mediastreamer]) + MS2_VERSION=`$PKG_CONFIG --modversion mediastreamer` + AM_CONDITIONAL(EXTERNAL_MEDIASTREAMER, [true])], + [no],[ + AC_CONFIG_SUBDIRS( mediastreamer2 ) + MEDIASTREAMER_DIR=${top_srcdir}/mediastreamer2 + MEDIASTREAMER_CFLAGS="-I\$(top_srcdir)/mediastreamer2/include" + MEDIASTREAMER_LIBS="\$(top_builddir)/mediastreamer2/src/libmediastreamer.la" +dnl need to temporary change quotes to allow square brackets + changequote(<<, >>) + MS2_VERSION=`grep -e '^.C_INIT(' $MEDIASTREAMER_DIR/configure.ac | sed -e 's:\([^(]\+\)(\[mediastreamer\],\[\(.*\)\]):\2:g'` + changequote([, ]) + AM_CONDITIONAL(EXTERNAL_MEDIASTREAMER, [false])], + [AC_MSG_ERROR([bad value '${enable_external_mediastreamer}' for --enable-external-mediastreamer])]) + +AC_SUBST(MEDIASTREAMER_CFLAGS) +AC_SUBST(MEDIASTREAMER_LIBS) +AC_SUBST([MS2_VERSION]) dnl check for db2html (docbook) to generate html user manual AC_CHECK_PROG(have_sgmltools,sgmltools, yes, no) AM_CONDITIONAL(ENABLE_MANUAL, test x$have_sgmltools$build_manual = xyesyes ) dnl for external use of linphone libs -LINPHONE_CFLAGS="-I${includedir} -I${includedir}/linphone " -LINPHONE_LIBS="-L${libdir} -llinphone" +LINPHONE_CFLAGS="-I${includedir} -I${includedir}/linphone" +LINPHONE_LIBS="-L${libdir} -llinphone" if test x$mingw_found = xyes ; then LINPHONE_LIBS="$LINPHONE_LIBS $OSIP_LIBS" @@ -390,7 +418,6 @@ fi AC_SUBST(LINPHONE_CFLAGS) AC_SUBST(LINPHONE_LIBS) - AC_DEFINE_UNQUOTED(LINPHONE_VERSION,"$PACKAGE_VERSION",[Linphone's version number]) AC_DEFINE_UNQUOTED(LINPHONE_PLUGINS_DIR, "${package_prefix}/lib/liblinphone/plugins" ,[path of liblinphone plugins, not mediastreamer2 plugins]) @@ -406,7 +433,8 @@ AC_ARG_ENABLE(external-ortp, esac],[external_ortp=false]) if test "$external_ortp" = 'true'; then - LP_CHECK_ORTP + PKG_CHECK_MODULES([ORTP], [ortp]) + ORTP_VERSION=`$PKG_CONFIG --modversion ortp` else AC_CONFIG_SUBDIRS( oRTP ) ORTP_CFLAGS="-I\$(top_srcdir)/oRTP/include" @@ -414,22 +442,16 @@ else if test x$ac_cv_c_bigendian = xyes ; then ORTP_CFLAGS="$ORTP_CFLAGS -DORTP_BIGENDIAN" fi + changequote(<<, >>) + ORTP_VERSION=`grep -E ^[AC]+_INIT ${top_srcdir}/oRTP/configure.ac | sed -e 's:^.*_INIT(.*,\[\(.*\)\]):\1:g'` + changequote([, ]) fi AC_SUBST(ORTP_CFLAGS) AC_SUBST(ORTP_LIBS) +AC_SUBST([ORTP_VERSION]) AM_CONDITIONAL(EXTERNAL_ORTP, [test "$external_ortp" = 'true']) -dnl Packaging: Pick oRTP version from ${top_srcdir}/oRTP/configure.ac -dnl Feel free to propose an alternative & cleaner version... -top_srcdir=`dirname $0` -changequote(, )dnl -ORTP_VERSION=`grep -E ^[AC]+_INIT ${top_srcdir}/oRTP/configure.ac | sed -e 's:^.*_INIT(.*,\[\(.*\)\]):\1:g'` -MS2_VERSION=`grep -E ^[AC]+_INIT ${top_srcdir}/mediastreamer2/configure.ac | sed -e 's:^.*_INIT(.*,\[\(.*\)\]):\1:g'` -changequote([, ])dnl -AC_SUBST([ORTP_VERSION]) -AC_SUBST([MS2_VERSION]) - dnl ################################################## dnl # Check for doxygen dnl ################################################## @@ -441,7 +463,7 @@ AM_CONDITIONAL(HAVE_DOXYGEN, test $DOXYGEN != false) AC_OUTPUT([ Makefile m4/Makefile -po/Makefile.in +po/Makefile.in pixmaps/Makefile coreapi/Makefile coreapi/help/Makefile diff --git a/console/Makefile.am b/console/Makefile.am index 70c2625b4..bef1e90d1 100644 --- a/console/Makefile.am +++ b/console/Makefile.am @@ -9,9 +9,7 @@ INCLUDES = \ -I$(top_srcdir)/coreapi\ $(ORTP_CFLAGS) \ -I$(top_srcdir)/exosip \ - -I$(top_srcdir)/mediastreamer2/include - - + $(MEDIASTREAMER_CFLAGS) bin_PROGRAMS = linphonec linphonecsh @@ -22,7 +20,7 @@ endif linphonec_SOURCES = linphonec.c linphonec.h commands.c linphonec_CFLAGS=$(COMMON_CFLAGS) $(CONSOLE_FLAGS) linphonec_LDADD = $(top_builddir)/coreapi/liblinphone.la $(READLINE_LIBS) \ - $(top_builddir)/mediastreamer2/src/libmediastreamer.la \ + $(MEDIASTREAMER_LIBS) \ $(ORTP_LIBS) \ $(SPEEX_LIBS) \ $(OSIP_LIBS) @@ -41,7 +39,7 @@ sipomatic_CFLAGS= $(COMMON_CFLAGS) $(CONSOLE_FLAGS) sipomatic_LDADD= $(INTLLIBS) \ $(top_builddir)/coreapi/liblinphone.la \ - $(top_builddir)/mediastreamer2/src/libmediastreamer.la \ + $(MEDIASTREAMER_LIBS) \ $(ORTP_LIBS) \ $(SPEEX_LIBS) \ $(OSIP_LIBS) diff --git a/console/commands.c b/console/commands.c index 619746cda..142ac833d 100644 --- a/console/commands.c +++ b/console/commands.c @@ -89,8 +89,13 @@ static int lpc_cmd_resume(LinphoneCore *lc, char *args); static int lpc_cmd_mute_mic(LinphoneCore *lc, char *args); static int lpc_cmd_unmute_mic(LinphoneCore *lc, char *args); static int lpc_cmd_rtp_no_xmit_on_audio_mute(LinphoneCore *lc, char *args); +#ifdef VIDEO_ENABLED +static int lpc_cmd_camera(LinphoneCore *lc, char *args); static int lpc_cmd_video_window(LinphoneCore *lc, char *args); +#endif static int lpc_cmd_states(LinphoneCore *lc, char *args); +static int lpc_cmd_identify(LinphoneCore *lc, char *args); +static int lpc_cmd_ringback(LinphoneCore *lc, char *args); /* Command handler helpers */ static void linphonec_proxy_add(LinphoneCore *lc); @@ -136,9 +141,12 @@ static LPC_COMMAND commands[] = { "'help '\t: displays specific help for command.\n" "'help advanced'\t: shows advanced commands.\n" }, - { "call", lpc_cmd_call, "Call a SIP uri", - "'call ' \t: initiate a call to the specified destination.\n" - "'call show' \t: show all the current calls with their id and status.\n" + { "call", lpc_cmd_call, "Call a SIP uri or number", +#ifdef VIDEO_ENABLED + "'call [--audio-only]' \t: initiate a call to the specified destination.\n" +#else + "'call ' \t: initiate a call to the specified destination.\n" +#endif }, { "calls", lpc_cmd_calls, "Show all the current calls with their id and status.", NULL @@ -163,6 +171,11 @@ static LPC_COMMAND commands[] = { "'resume ' : hold off the call with given id\n"}, { "mute", lpc_cmd_mute_mic, "Mute microphone and suspend voice transmission."}, +#ifdef VIDEO_ENABLED + { "camera", lpc_cmd_camera, "Send camera output for current call.", + "'camera on'\t: allow sending of local camera video to remote end.\n" + "'camera off'\t: disable sending of local camera's video to remote end.\n"}, +#endif { "unmute", lpc_cmd_unmute_mic, "Unmute microphone and resume voice transmission."}, { "duration", lpc_cmd_duration, "Print duration in seconds of the last call.", NULL }, @@ -255,12 +268,14 @@ static LPC_COMMAND advanced_commands[] = { "Set the rtp_no_xmit_on_audio_mute configuration parameter", " If set to 1 then rtp transmission will be muted when\n" " audio is muted , otherwise rtp is always sent."}, +#ifdef VIDEO_ENABLED { "vwindow", lpc_cmd_video_window, "Control video display window", "'vwindow show': shows video window\n" "'vwindow hide': hides video window\n" "'vwindow pos ': Moves video window to x,y pixel coordinates\n" "'vwindow size ': Resizes video window" }, +#endif { "states", lpc_cmd_states, "Show internal states of liblinphone, registrations and calls, according to linphonecore.h definitions", "'states global': shows global state of liblinphone \n" "'states calls': shows state of calls\n" @@ -284,6 +299,14 @@ static LPC_COMMAND advanced_commands[] = { "'staticpic set' : Set path to picture that should be used.\n" "'staticpic fps' : Get/set frames per seconds for picture emission.\n" }, + { "identify", lpc_cmd_identify, "Returns the user-agent string of far end", + "'identify' \t: returns remote user-agent string for current call.\n" + "'identify ' \t: returns remote user-agent string for call with supplied id.\n" + }, + { "ringback", lpc_cmd_ringback, "Specifies a ringback tone to be played to remote end during incoming calls", + "'ringback '\t: Specifies a ringback tone to be played to remote end during incoming calls\n" + "'ringback disable'\t: Disable playing of ringback tone to callers\n" + }, { NULL,NULL,NULL,NULL} }; @@ -503,12 +526,19 @@ lpc_cmd_call(LinphoneCore *lc, char *args) } { LinphoneCall *call; + LinphoneCallParams *cp=linphone_core_create_default_call_parameters (lc); + char *opt; if ( linphone_core_in_call(lc) ) { linphonec_out("Terminate or hold on the current call first.\n"); return 1; } - if ( NULL == (call=linphone_core_invite(lc, args)) ) + opt=strstr(args,"--audio-only"); + if (opt){ + opt[0]='\0'; + linphone_call_params_enable_video (cp,FALSE); + } + if ( NULL == (call=linphone_core_invite_with_params(lc, args,cp)) ) { linphonec_out("Error from linphone_core_invite.\n"); } @@ -516,6 +546,7 @@ lpc_cmd_call(LinphoneCore *lc, char *args) { snprintf(callee_name,sizeof(callee_name),"%s",args); } + linphone_call_params_destroy(cp); } return 1; } @@ -624,7 +655,7 @@ static int lpc_cmd_terminate(LinphoneCore *lc, char *args) { if (linphone_core_get_calls(lc)==NULL){ - linphonec_out("No active calls"); + linphonec_out("No active calls\n"); return 1; } if (!args) @@ -645,7 +676,7 @@ lpc_cmd_terminate(LinphoneCore *lc, char *args) LinphoneCall *call=linphonec_get_call(id); if (call){ if (linphone_core_terminate_call(lc,call)==-1){ - linphonec_out("Could not stop the call with id %li",id); + linphonec_out("Could not stop the call with id %li\n",id); } }else return 0; return 1; @@ -1636,7 +1667,6 @@ linphonec_proxy_remove(LinphoneCore *lc, int index) } linphone_core_remove_proxy_config(lc,cfg); linphonec_out("Proxy %s removed.\n", cfg->reg_proxy); - linphone_proxy_config_destroy(cfg); } static int @@ -2166,11 +2196,11 @@ static int lpc_cmd_rtp_no_xmit_on_audio_mute(LinphoneCore *lc, char *args) return 1; } +#ifdef VIDEO_ENABLED static int lpc_cmd_video_window(LinphoneCore *lc, char *args){ char subcommand[64]; int a,b; int err; -#ifdef VIDEO_ENABLED err=sscanf(args,"%s %i %i",subcommand,&a,&b); if (err>=1){ if (strcmp(subcommand,"pos")==0){ @@ -2191,11 +2221,10 @@ static int lpc_cmd_video_window(LinphoneCore *lc, char *args){ lpc_video_params.refresh=TRUE; }else return 0; } -#else - linphonec_out("Sorry, this version of linphonec wasn't compiled with video support."); -#endif + return 1; } +#endif static void lpc_display_global_state(LinphoneCore *lc){ linphonec_out("Global liblinphone state\n%s\n", @@ -2261,6 +2290,90 @@ static int lpc_cmd_states(LinphoneCore *lc, char *args){ return 0; } +#ifdef VIDEO_ENABLED +static int lpc_cmd_camera(LinphoneCore *lc, char *args){ + LinphoneCall *call=linphone_core_get_current_call(lc); + bool_t activated=FALSE; + + if (linphone_core_video_enabled (lc)==FALSE){ + linphonec_out("Video is disabled, re-run linphonec with -V option."); + return 1; + } + + if (args){ + if (strcmp(args,"on")==0) + activated=TRUE; + else if (strcmp(args,"off")==0) + activated=FALSE; + else + return 0; + } + + if (call==NULL){ + if (args){ + linphonec_camera_enabled=activated; + } + if (linphonec_camera_enabled){ + linphonec_out("Camera is enabled. Video stream will be setup immediately for outgoing and incoming calls.\n"); + }else{ + linphonec_out("Camera is disabled. Calls will be established with audio-only, with the possibility to later add video using 'camera on'.\n"); + } + }else{ + const LinphoneCallParams *cp=linphone_call_get_current_params (call); + if (args){ + linphone_call_enable_camera(call,activated); + if ((activated && !linphone_call_params_video_enabled (cp))){ + /*update the call to add the video stream*/ + LinphoneCallParams *ncp=linphone_call_params_copy(cp); + linphone_call_params_enable_video(ncp,TRUE); + linphone_core_update_call(lc,call,ncp); + linphone_call_params_destroy (ncp); + linphonec_out("Trying to bring up video stream...\n"); + } + } + if (linphone_call_camera_enabled (call)) + linphonec_out("Camera is allowed for current call.\n"); + else linphonec_out("Camera is dis-allowed for current call.\n"); + } + return 1; +} + +#endif + +static int lpc_cmd_identify(LinphoneCore *lc, char *args){ + LinphoneCall *call; + const char *remote_ua; + if (args==NULL){ + call=linphone_core_get_current_call(lc); + if (call==NULL) { + linphonec_out("There is currently running call. Specify call id.\n"); + return 0; + } + }else{ + call=linphonec_get_call(atoi(args)); + if (call==NULL){ + return 0; + } + } + remote_ua=linphone_call_get_remote_user_agent(call); + if (remote_ua){ + linphonec_out("Remote user agent string is: %s\n",remote_ua); + } + return 1; +} + +static int lpc_cmd_ringback(LinphoneCore *lc, char *args){ + if (!args) return 0; + if (strcmp(args,"disable")==0){ + linphone_core_set_remote_ringback_tone(lc,NULL); + linphonec_out("Disabling ringback tone.\n"); + return 1; + } + linphone_core_set_remote_ringback_tone (lc,args); + linphonec_out("Using %s as ringback tone to be played to callers.",args); + return 1; +} + /*************************************************************************** * * Command table management funx diff --git a/console/linphonec.c b/console/linphonec.c index 6985287d6..dbdf16594 100644 --- a/console/linphonec.c +++ b/console/linphonec.c @@ -173,6 +173,8 @@ static bool_t pipe_reader_run=FALSE; static ortp_pipe_t server_sock; #endif /*_WIN32_WCE*/ +bool_t linphonec_camera_enabled=TRUE; + extern VideoParams lpc_video_params; @@ -313,6 +315,13 @@ linphonec_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf, } +static void linphonec_call_updated(LinphoneCall *call){ + const LinphoneCallParams *cp=linphone_call_get_current_params(call); + if (!linphone_call_camera_enabled (call) && linphone_call_params_video_enabled (cp)){ + linphonec_out("Far end requests to share video.\nType 'camera on' if you agree."); + } +} + static void linphonec_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState st, const char *msg){ char *from=linphone_call_get_remote_address_as_string(call); long id=(long)linphone_call_get_user_pointer (call); @@ -337,6 +346,7 @@ static void linphonec_call_state_changed(LinphoneCore *lc, LinphoneCall *call, L break; case LinphoneCallIncomingReceived: linphonec_call_identify(call); + linphone_call_enable_camera (call,linphonec_camera_enabled); id=(long)linphone_call_get_user_pointer (call); linphonec_set_caller(from); if ( auto_answer) { @@ -347,6 +357,9 @@ static void linphonec_call_state_changed(LinphoneCore *lc, LinphoneCall *call, L case LinphoneCallOutgoingInit: linphonec_call_identify(call); break; + case LinphoneCallUpdatedByRemote: + linphonec_call_updated(call); + break; default: break; } @@ -734,7 +747,7 @@ linphonec_finish(int exit_status) { fclose (mylogfile); } - + printf("\n"); exit(exit_status); } diff --git a/console/linphonec.h b/console/linphonec.h index 4a5844b56..5f91b1b50 100644 --- a/console/linphonec.h +++ b/console/linphonec.h @@ -121,6 +121,8 @@ void linphonec_set_caller(const char *caller); LinphoneCall *linphonec_get_call(long id); void linphonec_call_identify(LinphoneCall* call); +extern bool_t linphonec_camera_enabled; + #endif /* def LINPHONEC_H */ /**************************************************************************** diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am index b3cf6df19..0e498053d 100644 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -10,7 +10,7 @@ linphone_include_HEADERS=linphonecore.h linphonecore_utils.h ../config.h lpconfi INCLUDES = \ -I$(top_srcdir)\ - -I$(top_srcdir)/mediastreamer2/include + $(MEDIASTREAMER_CFLAGS) lib_LTLIBRARIES=liblinphone.la @@ -42,7 +42,7 @@ liblinphone_la_LDFLAGS= -version-info $(LIBLINPHONE_SO_VERSION) -no-undefined liblinphone_la_LIBADD= \ $(EXOSIP_LIBS) \ - $(top_builddir)/mediastreamer2/src/libmediastreamer.la \ + $(MEDIASTREAMER_LIBS) \ $(ORTP_LIBS) if BUILD_WIN32 @@ -53,11 +53,14 @@ noinst_PROGRAMS=test_lsd test_lsd_SOURCES=test_lsd.c -test_lsd_LDADD=liblinphone.la +test_lsd_LDADD=liblinphone.la \ + $(MEDIASTREAMER_LIBS) \ + $(ORTP_LIBS) AM_CFLAGS=$(STRICT_OPTIONS) -DIN_LINPHONE \ $(ORTP_CFLAGS) \ $(OSIP_CFLAGS) \ + $(MEDIASTREAMER_CFLAGS) \ $(EXOSIP_CFLAGS) \ -DENABLE_TRACE \ -DLOG_DOMAIN=\"LinphoneCore\" \ diff --git a/coreapi/address.c b/coreapi/address.c index 4d4b1d2d6..7475ab596 100644 --- a/coreapi/address.c +++ b/coreapi/address.c @@ -129,6 +129,29 @@ char *linphone_address_as_string_uri_only(const LinphoneAddress *u){ return sal_address_as_string_uri_only(u); } +static bool_t strings_equals(const char *s1, const char *s2){ + if (s1==NULL && s2==NULL) return TRUE; + if (s1!=NULL && s2!=NULL && strcmp(s1,s2)==0) return TRUE; + return FALSE; +} + +/** + * Compare two LinphoneAddress ignoring tags and headers, basically just domain, username, and port. + * Returns TRUE if they are equal. +**/ +bool_t linphone_address_weak_compare(const LinphoneAddress *a1, const LinphoneAddress *a2){ + const char *u1,*u2; + const char *h1,*h2; + int p1,p2; + u1=linphone_address_get_username(a1); + u2=linphone_address_get_username(a2); + p1=linphone_address_get_port_int(a1); + p2=linphone_address_get_port_int(a2); + h1=linphone_address_get_domain(a1); + h2=linphone_address_get_domain(a2); + return strings_equals(u1,u2) && strings_equals(h1,h2) && p1==p2; +} + /** * Destroys a LinphoneAddress object. **/ @@ -139,6 +162,7 @@ void linphone_address_destroy(LinphoneAddress *u){ int linphone_address_get_port_int(const LinphoneAddress *u) { return sal_address_get_port_int(u); } + const char* linphone_address_get_port(const LinphoneAddress *u) { return sal_address_get_port(u); } diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 642e3d188..53382eb27 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -23,7 +23,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "linphonecore.h" #include "private.h" #include "mediastreamer2/mediastream.h" +#include "lpconfig.h" +static void register_failure(SalOp *op, SalError error, SalReason reason, const char *details); static void linphone_connect_incoming(LinphoneCore *lc, LinphoneCall *call){ if (lc->ringstream!=NULL){ @@ -33,6 +35,18 @@ static void linphone_connect_incoming(LinphoneCore *lc, LinphoneCall *call){ linphone_call_start_media_streams(call); } +static bool_t is_duplicate_call(LinphoneCore *lc, const LinphoneAddress *from, const LinphoneAddress *to){ + MSList *elem; + for(elem=lc->calls;elem!=NULL;elem=elem->next){ + LinphoneCall *call=(LinphoneCall*)elem->data; + if (linphone_address_weak_compare(call->log->from,from) && + linphone_address_weak_compare(call->log->to, to)){ + return TRUE; + } + } + return FALSE; +} + static void call_received(SalOp *h){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h)); char *barmesg; @@ -40,7 +54,9 @@ static void call_received(SalOp *h){ const char *from,*to; char *tmp; LinphoneAddress *from_parsed; - + LinphoneAddress *from_addr, *to_addr; + const char * early_media=linphone_core_get_remote_ringback_tone (lc); + /* first check if we can answer successfully to this invite */ if (lc->presence_mode==LinphoneStatusBusy || lc->presence_mode==LinphoneStatusOffline || @@ -64,9 +80,18 @@ static void call_received(SalOp *h){ } from=sal_op_get_from(h); to=sal_op_get_to(h); + from_addr=linphone_address_new(from); + to_addr=linphone_address_new(to); + + if (is_duplicate_call(lc,from_addr,to_addr)){ + ms_warning("Receiving duplicated call, refusing this one."); + sal_call_decline(h,SalReasonBusy,NULL); + linphone_address_destroy(from_addr); + linphone_address_destroy(to_addr); + return; + } - call=linphone_call_new_incoming(lc,linphone_address_new(from),linphone_address_new(to),h); - + call=linphone_call_new_incoming(lc,from_addr,to_addr,h); sal_call_set_local_media_description(h,call->localdesc); call->resultdesc=sal_call_get_final_media_description(h); if (call->resultdesc) @@ -76,14 +101,11 @@ static void call_received(SalOp *h){ linphone_call_unref(call); return; } + + /* the call is acceptable so we can now add it to our list */ - if(linphone_core_add_call(lc,call)!= 0) - { - ms_warning("we cannot handle anymore call\n"); - sal_call_decline(h,SalReasonMedia,NULL); - linphone_call_unref(call); - return; - } + linphone_core_add_call(lc,call); + from_parsed=linphone_address_new(sal_op_get_from(h)); linphone_address_clean(from_parsed); tmp=linphone_address_as_string(from_parsed); @@ -115,9 +137,12 @@ static void call_received(SalOp *h){ }else{ /*TODO : play a tone within the context of the current call */ } - sal_call_notify_ringing(h); + sal_call_notify_ringing(h,early_media!=NULL); #if !(__IPHONE_OS_VERSION_MIN_REQUIRED >= 40000) linphone_call_init_media_streams(call); + if (early_media!=NULL){ + linphone_call_start_early_media (call); + } #endif ms_free(barmesg); ms_free(tmp); @@ -301,6 +326,8 @@ static void call_updating(SalOp *op){ if (lc->current_call!=call){ ms_error("Inconsitency detected: current call is %p but call %p is being paused !",lc->current_call,call); } + }else{ + linphone_call_set_state(call, LinphoneCallUpdatedByRemote,"Call updated by remote"); } /*accept the modification (sends a 200Ok)*/ sal_call_accept(op); @@ -314,6 +341,8 @@ static void call_updating(SalOp *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); + + if (call==NULL) return; if (linphone_call_get_state(call)==LinphoneCallEnd || linphone_call_get_state(call)==LinphoneCallError){ ms_warning("call_terminated: ignoring."); @@ -426,6 +455,9 @@ static void auth_requested(SalOp *h, const char *realm, const char *username){ sal_op_authenticate(h,&sai); ai->usecount++; }else{ + if (ai && ai->works==FALSE) { + register_failure(h, SalErrorFailure, SalReasonForbidden, _("Authentication failure")); + } if (lc->vtable.auth_info_requested) lc->vtable.auth_info_requested(lc,realm,username); } @@ -446,6 +478,7 @@ static void register_success(SalOp *op, bool_t registered){ char *msg; cfg->registered=registered; + linphone_proxy_config_set_error(cfg,LinphoneErrorNone); linphone_proxy_config_set_state(cfg, registered ? LinphoneRegistrationOk : LinphoneRegistrationCleared , registered ? "Registration sucessful" : "Unregistration done"); if (lc->vtable.display_status){ @@ -473,6 +506,11 @@ static void register_failure(SalOp *op, SalError error, SalReason reason, const lc->vtable.display_status(lc,msg); ms_free(msg); } + if (error== SalErrorFailure && reason == SalReasonForbidden) { + linphone_proxy_config_set_error(cfg, LinphoneErrorBadCredentials); + } else if (error == SalErrorNoResponse) { + linphone_proxy_config_set_error(cfg, LinphoneErrorNoResponse); + } linphone_proxy_config_set_state(cfg,LinphoneRegistrationFailed,details); } diff --git a/coreapi/help/Makefile.am b/coreapi/help/Makefile.am index ebe407ff9..0cdd3f8f0 100644 --- a/coreapi/help/Makefile.am +++ b/coreapi/help/Makefile.am @@ -36,14 +36,17 @@ noinst_PROGRAMS=helloworld helloworld_SOURCES=helloworld.c -helloworld_LDADD=$(top_builddir)/coreapi/liblinphone.la +helloworld_LDADD=$(top_builddir)/coreapi/liblinphone.la \ + $(MEDIASTREAMER_LIBS) \ + $(ORTP_LIBS) INCLUDES=-I$(top_srcdir)/coreapi \ - -I$(top_srcdir)/mediastreamer2/include + $(MEDIASTREAMER_CFLAGS) AM_CFLAGS=$(STRICT_OPTIONS) -DIN_LINPHONE \ $(ORTP_CFLAGS) \ $(OSIP_CFLAGS) \ + $(MEDIASTREAMER_CFLAGS) \ $(EXOSIP_CFLAGS) \ -DENABLE_TRACE \ -DLOG_DOMAIN=\"LinphoneCore\" \ diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 812fa8cf7..f96b4ed74 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -30,7 +30,13 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "mediastreamer2/mediastream.h" #include "mediastreamer2/msvolume.h" #include "mediastreamer2/msequalizer.h" +#include "mediastreamer2/msfileplayer.h" +#ifdef VIDEO_ENABLED +static MSWebCam *get_nowebcam_device(){ + return ms_web_cam_manager_get_cam(ms_web_cam_manager_get(),"StaticImage: Static picture"); +} +#endif static MSList *make_codec_list(LinphoneCore *lc, const MSList *codecs, bool_t only_one_codec){ @@ -46,11 +52,15 @@ static MSList *make_codec_list(LinphoneCore *lc, const MSList *codecs, bool_t on return l; } -static SalMediaDescription *create_local_media_description(LinphoneCore *lc, - LinphoneCall *call, const char *username, bool_t only_one_codec){ +SalMediaDescription *create_local_media_description(LinphoneCore *lc, + LinphoneCall *call, bool_t with_video, bool_t only_one_codec){ MSList *l; PayloadType *pt; + const char *me=linphone_core_get_identity(lc); + LinphoneAddress *addr=linphone_address_new(me); + const char *username=linphone_address_get_username (addr); SalMediaDescription *md=sal_media_description_new(); + md->nstreams=1; strncpy(md->addr,call->localip,sizeof(md->addr)); strncpy(md->username,username,sizeof(md->username)); @@ -69,7 +79,7 @@ static SalMediaDescription *create_local_media_description(LinphoneCore *lc, if (lc->dw_audio_bw>0) md->streams[0].bandwidth=lc->dw_audio_bw; - if (linphone_core_video_enabled (lc)){ + if (with_video){ md->nstreams++; md->streams[1].port=call->video_port; md->streams[1].proto=SalProtoRtpAvp; @@ -79,6 +89,7 @@ static SalMediaDescription *create_local_media_description(LinphoneCore *lc, if (lc->dw_video_bw) md->streams[1].bandwidth=lc->dw_video_bw; } + linphone_address_destroy(addr); return md; } @@ -134,7 +145,7 @@ static void discover_mtu(LinphoneCore *lc, const char *remote){ } } -LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to) +LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, const LinphoneCallParams *params) { LinphoneCall *call=ms_new0(LinphoneCall,1); call->dir=LinphoneCallOutgoing; @@ -143,8 +154,9 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr call->core=lc; linphone_core_get_local_ip(lc,linphone_address_get_domain(to),call->localip); linphone_call_init_common(call,from,to); - call->localdesc=create_local_media_description (lc,call, - linphone_address_get_username(from),FALSE); + call->params=*params; + call->localdesc=create_local_media_description (lc,call,params->has_video,FALSE); + call->camera_active=params->has_video; if (linphone_core_get_firewall_policy(call->core)==LinphonePolicyUseStun) linphone_core_run_stun_tests(call->core,call); discover_mtu(lc,linphone_address_get_domain (to)); @@ -153,7 +165,6 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, SalOp *op){ LinphoneCall *call=ms_new0(LinphoneCall,1); - LinphoneAddress *me=linphone_core_get_primary_contact_parsed(lc); char *to_str; char *from_str; @@ -178,12 +189,13 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro linphone_address_clean(from); linphone_core_get_local_ip(lc,linphone_address_get_domain(from),call->localip); linphone_call_init_common(call, from, to); + call->params.has_video=linphone_core_video_enabled(lc); call->localdesc=create_local_media_description (lc,call, - linphone_address_get_username(me),lc->sip_conf.only_one_codec); + call->params.has_video,lc->sip_conf.only_one_codec); + call->camera_active=call->params.has_video; if (linphone_core_get_firewall_policy(call->core)==LinphonePolicyUseStun) linphone_core_run_stun_tests(call->core,call); discover_mtu(lc,linphone_address_get_domain(from)); - linphone_address_destroy(me); return call; } @@ -259,6 +271,8 @@ const char *linphone_call_state_to_string(LinphoneCallState cs){ return "LinphoneCallEnd"; case LinphoneCallPausedByRemote: return "LinphoneCallPausedByRemote"; + case LinphoneCallUpdatedByRemote: + return "LinphoneCallUpdatedByRemote"; } return "undefined state"; } @@ -336,6 +350,13 @@ void linphone_call_unref(LinphoneCall *obj){ } } +/** + * Returns current parameters associated to the call. +**/ +const LinphoneCallParams * linphone_call_get_current_params(const LinphoneCall *call){ + return &call->params; +} + /** * Returns the remote address associated to this call * @@ -398,10 +419,23 @@ const char *linphone_call_get_refer_to(const LinphoneCall *call){ return call->refer_to; } +/** + * Returns direction of the call (incoming or outgoing). +**/ LinphoneCallDir linphone_call_get_dir(const LinphoneCall *call){ return call->log->dir; } +/** + * Returns the far end's user agent description string, if available. +**/ +const char *linphone_call_get_remote_user_agent(LinphoneCall *call){ + if (call->op){ + return sal_op_get_remote_ua (call->op); + } + return NULL; +} + /** * Returns true if this calls has received a transfer that has not been * executed yet. @@ -422,6 +456,60 @@ int linphone_call_get_duration(const LinphoneCall *call){ return time(NULL)-call->media_start_time; } +/** + * Indicate whether camera input should be sent to remote end. +**/ +void linphone_call_enable_camera (LinphoneCall *call, bool_t enable){ +#ifdef VIDEO_ENABLED + if (call->videostream!=NULL && call->videostream->ticker!=NULL){ + LinphoneCore *lc=call->core; + MSWebCam *nowebcam=get_nowebcam_device(); + if (call->camera_active!=enable && lc->video_conf.device!=nowebcam){ + video_stream_change_camera(call->videostream, + enable ? lc->video_conf.device : nowebcam); + } + } + call->camera_active=enable; +#endif +} + +/** + * +**/ +bool_t linphone_call_camera_enabled (const LinphoneCall *call){ + return call->camera_active; +} + +/** + * +**/ +void linphone_call_params_enable_video(LinphoneCallParams *cp, bool_t enabled){ + cp->has_video=enabled; +} + +/** + * +**/ +bool_t linphone_call_params_video_enabled(const LinphoneCallParams *cp){ + return cp->has_video; +} + +/** + * +**/ +LinphoneCallParams * linphone_call_params_copy(const LinphoneCallParams *cp){ + LinphoneCallParams *ncp=ms_new0(LinphoneCallParams,1); + memcpy(ncp,cp,sizeof(LinphoneCallParams)); + return ncp; +} + +/** + * +**/ +void linphone_call_params_destroy(LinphoneCallParams *p){ + ms_free(p); +} + /** * @} **/ @@ -621,7 +709,13 @@ static RtpProfile *make_profile(LinphoneCore *lc, const SalMediaDescription *md, return prof; } -void linphone_call_start_media_streams(LinphoneCall *call){ +static void setup_ring_player(LinphoneCore *lc, LinphoneCall *call){ + int pause_time=3000; + audio_stream_play(call->audiostream,lc->sound_conf.ringback_tone); + ms_filter_call_method(call->audiostream->soundread,MS_FILE_PLAYER_LOOP,&pause_time); +} + +static void _linphone_call_start_media_streams(LinphoneCall *call, bool_t send_early_media){ LinphoneCore *lc=call->core; LinphoneAddress *me=linphone_core_get_primary_contact_parsed(lc); const char *tool="linphone-" LINPHONE_VERSION; @@ -660,10 +754,12 @@ void linphone_call_start_media_streams(LinphoneCall *call){ if (stream->port==0 || stream->dir==SalStreamRecvOnly){ captcard=NULL; playfile=NULL; - }else if (stream->dir==SalStreamSendOnly){ + }else if (stream->dir==SalStreamSendOnly || send_early_media){ playcard=NULL; captcard=NULL; recfile=NULL; + if (send_early_media) + playfile=NULL; } /*if playfile are supplied don't use soundcards*/ if (lc->use_files) { @@ -682,14 +778,15 @@ void linphone_call_start_media_streams(LinphoneCall *call){ recfile, playcard, captcard, - linphone_core_echo_cancellation_enabled(lc)); + send_early_media ? FALSE : linphone_core_echo_cancellation_enabled(lc)); post_configure_audio_streams(call); + if (send_early_media) setup_ring_player(lc,call); audio_stream_set_rtcp_information(call->audiostream, cname, tool); }else ms_warning("No audio stream accepted ?"); } } #ifdef VIDEO_ENABLED - { + if (!send_early_media){ const SalStreamDescription *stream=sal_media_description_find_stream(call->resultdesc, SalProtoRtpAvp,SalVideo); used_pt=-1; @@ -705,12 +802,14 @@ void linphone_call_start_media_streams(LinphoneCall *call){ VideoStreamDir dir=VideoStreamSendRecv; MSWebCam *cam=lc->video_conf.device; bool_t is_inactive=FALSE; + + call->params.has_video=TRUE; 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 (stream->dir==SalStreamSendOnly && lc->video_conf.capture ){ - cam=ms_web_cam_manager_get_cam(ms_web_cam_manager_get(),"StaticImage: Static picture"); + cam=get_nowebcam_device(); dir=VideoStreamSendOnly; }else if (stream->dir==SalStreamRecvOnly && lc->video_conf.display ){ dir=VideoStreamRecvOnly; @@ -726,6 +825,9 @@ void linphone_call_start_media_streams(LinphoneCall *call){ /*either inactive or incompatible with local capabilities*/ is_inactive=TRUE; } + if (call->camera_active==FALSE){ + cam=get_nowebcam_device(); + } if (!is_inactive){ video_stream_set_direction (call->videostream, dir); video_stream_start(call->videostream, @@ -747,6 +849,13 @@ void linphone_call_start_media_streams(LinphoneCall *call){ } +void linphone_call_start_media_streams(LinphoneCall *call){ + _linphone_call_start_media_streams(call,FALSE); +} + +void linphone_call_start_early_media(LinphoneCall *call){ + _linphone_call_start_media_streams(call,TRUE); +} static void linphone_call_log_fill_stats(LinphoneCallLog *log, AudioStream *st){ audio_stream_get_local_rtp_stats (st,&log->local_stats); @@ -777,4 +886,3 @@ void linphone_call_stop_media_streams(LinphoneCall *call){ } } - diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index b35ea38d7..447f1ab0b 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -467,6 +467,8 @@ static void sound_config_read(LinphoneCore *lc) gain=lp_config_get_float(lc->config,"sound","playback_gain_db",0); linphone_core_set_playback_gain_db (lc,gain); + + linphone_core_set_remote_ringback_tone (lc,lp_config_get_string(lc->config,"sound","ringback_tone",NULL)); } static void sip_config_read(LinphoneCore *lc) @@ -704,6 +706,17 @@ static MSList *add_missing_codecs(SalStreamType mtype, MSList *l){ return l; } +static MSList *codec_append_if_new(MSList *l, PayloadType *pt){ + MSList *elem; + for (elem=l;l!=NULL;l=elem->next){ + PayloadType *ept=(PayloadType*)elem->data; + if (pt==ept) + return l; + } + l=ms_list_append(l,pt); + return l; +} + static void codecs_config_read(LinphoneCore *lc) { int i; @@ -714,7 +727,7 @@ static void codecs_config_read(LinphoneCore *lc) if (pt){ if (!ms_filter_codec_supported(pt->mime_type)){ ms_warning("Codec %s is not supported by mediastreamer2, removed.",pt->mime_type); - }else audio_codecs=ms_list_append(audio_codecs,pt); + }else audio_codecs=codec_append_if_new(audio_codecs,pt); } } audio_codecs=add_missing_codecs(SalAudio,audio_codecs); @@ -722,7 +735,7 @@ static void codecs_config_read(LinphoneCore *lc) if (pt){ if (!ms_filter_codec_supported(pt->mime_type)){ ms_warning("Codec %s is not supported by mediastreamer2, removed.",pt->mime_type); - }else video_codecs=ms_list_append(video_codecs,(void *)pt); + }else video_codecs=codec_append_if_new(video_codecs,(void *)pt); } } video_codecs=add_missing_codecs(SalVideo,video_codecs); @@ -1792,7 +1805,7 @@ LinphoneAddress * linphone_core_interpret_url(LinphoneCore *lc, const char *url) /** * Returns the default identity SIP address. * - * @ingroup proxiesb + * @ingroup proxies * This is an helper function: * * If no default proxy is set, this will return the primary contact ( @@ -1965,12 +1978,39 @@ int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call, LinphonePro * @ingroup call_control * @param lc the LinphoneCore object * @param url the destination of the call (sip address, or phone number). + * + * 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. + * + * @Returns a LinphoneCall object or NULL in case of failure **/ LinphoneCall * linphone_core_invite(LinphoneCore *lc, const char *url){ + LinphoneCall *call; + LinphoneCallParams *p=linphone_core_create_default_call_parameters (lc); + call=linphone_core_invite_with_params(lc,url,p); + linphone_call_params_destroy(p); + return call; +} + + +/** + * Initiates an outgoing call according to supplied call parameters + * + * @ingroup call_control + * @param lc the LinphoneCore object + * @param url the destination of the call (sip address, or phone number). + * @param p call parameters + * + * 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. + * + * @Returns a LinphoneCall object or NULL in case of failure +**/ +LinphoneCall * linphone_core_invite_with_params(LinphoneCore *lc, const char *url, const LinphoneCallParams *p){ LinphoneAddress *addr=linphone_core_interpret_url(lc,url); if (addr){ LinphoneCall *call; - call=linphone_core_invite_address(lc,addr); + call=linphone_core_invite_address_with_params(lc,addr,p); linphone_address_destroy(addr); return call; } @@ -1982,12 +2022,40 @@ LinphoneCall * linphone_core_invite(LinphoneCore *lc, const char *url){ * * @ingroup call_control * @param lc the LinphoneCore object - * @param real_parsed_url the destination of the call (sip address). + * @param addr the destination of the call (sip address). * * 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. + * + * @Returns a LinphoneCall object or NULL in case of failure **/ -LinphoneCall * linphone_core_invite_address(LinphoneCore *lc, const LinphoneAddress *real_parsed_url) +LinphoneCall * linphone_core_invite_address(LinphoneCore *lc, const LinphoneAddress *addr){ + LinphoneCall *call; + LinphoneCallParams *p=linphone_core_create_default_call_parameters (lc); + call=linphone_core_invite_address_with_params (lc,addr,p); + linphone_call_params_destroy(p); + return call; +} + + +/** + * 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. + * + * @Returns a LinphoneCall object or NULL in case of failure +**/ +LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const LinphoneAddress *addr, const LinphoneCallParams *params) { int err=0; const char *route=NULL; @@ -2011,8 +2079,8 @@ LinphoneCall * linphone_core_invite_address(LinphoneCore *lc, const LinphoneAddr linphone_core_get_default_proxy(lc,&proxy); route=linphone_core_get_route(lc); - real_url=linphone_address_as_string(real_parsed_url); - dest_proxy=linphone_core_lookup_known_proxy(lc,real_parsed_url); + real_url=linphone_address_as_string(addr); + dest_proxy=linphone_core_lookup_known_proxy(lc,addr); if (proxy!=dest_proxy && dest_proxy!=NULL) { ms_message("Overriding default proxy setting for this call:"); @@ -2029,7 +2097,7 @@ LinphoneCall * linphone_core_invite_address(LinphoneCore *lc, const LinphoneAddr parsed_url2=linphone_address_new(from); - call=linphone_call_new_outgoing(lc,parsed_url2,linphone_address_clone(real_parsed_url)); + call=linphone_call_new_outgoing(lc,parsed_url2,linphone_address_clone(addr),params); sal_op_set_route(call->op,route); if(linphone_core_add_call(lc,call)!= 0) @@ -2092,6 +2160,27 @@ bool_t linphone_core_inc_invite_pending(LinphoneCore*lc){ return FALSE; } +/** + * Updates a running call according to supplied call parameters. + * + * For the moment, this is limited to enabling or disabling the video stream. + * + * @Returns 0 if successful, -1 otherwise. +**/ +int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, LinphoneCallParams *params){ + int err; + + if (call->localdesc) + sal_media_description_unref(call->localdesc); + call->localdesc=create_local_media_description (lc,call, + params->has_video,FALSE); + if (lc->vtable.display_status) + lc->vtable.display_status(lc,_("Modifying call parameters...")); + sal_call_set_local_media_description (call->op,call->localdesc); + err=sal_call_update(call->op); + return err; +} + /** * Accept an incoming call. @@ -2156,6 +2245,12 @@ int linphone_core_accept_call(LinphoneCore *lc, LinphoneCall *call) sal_op_set_contact(call->op,contact); #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 40000 linphone_call_init_media_streams(call); +#else + if (call->audiostream!=NULL && call->audiostream->ticker!=NULL){ + /*case where we sent early media*/ + linphone_call_stop_media_streams (call); + linphone_call_init_media_streams (call); + } #endif sal_call_accept(call->op); if (lc->vtable.display_status!=NULL) @@ -3392,7 +3487,8 @@ void linphone_core_play_dtmf(LinphoneCore *lc, char dtmf, int duration_ms){ **/ void linphone_core_stop_dtmf(LinphoneCore *lc){ MSFilter *f=get_dtmf_gen(lc); - ms_filter_call_method_noarg (f, MS_DTMF_GEN_STOP); + if (f!=NULL) + ms_filter_call_method_noarg (f, MS_DTMF_GEN_STOP); } @@ -3786,6 +3882,25 @@ int linphone_core_del_call( LinphoneCore *lc, LinphoneCall *call) return 0; } +/** + * Specifiies a ring back tone to be played to far end during incoming calls. +**/ +void linphone_core_set_remote_ringback_tone(LinphoneCore *lc, const char *file){ + if (lc->sound_conf.ringback_tone){ + ms_free(lc->sound_conf.ringback_tone); + lc->sound_conf.ringback_tone=NULL; + } + if (file) + lc->sound_conf.ringback_tone=ms_strdup(file); +} + +/** + * Returns the ring back tone played to far end during incoming calls. +**/ +const char *linphone_core_get_remote_ringback_tone(const LinphoneCore *lc){ + return lc->sound_conf.ringback_tone; +} + static PayloadType* find_payload_type_from_list(const char* type, int rate,const MSList* from) { const MSList *elem; for(elem=from;elem!=NULL;elem=elem->next){ @@ -3838,3 +3953,21 @@ const char *linphone_global_state_to_string(LinphoneGlobalState gs){ LinphoneGlobalState linphone_core_get_global_state(const LinphoneCore *lc){ return lc->state; } + +LinphoneCallParams *linphone_core_create_default_call_parameters(LinphoneCore *lc){ + LinphoneCallParams *p=ms_new0(LinphoneCallParams,1); + p->has_video=linphone_core_video_enabled(lc); + return p; +} + +const char *linphone_error_to_string(LinphoneError err){ + switch(err){ + case LinphoneErrorNone: + return "No error"; + case LinphoneErrorNoResponse: + return "No response"; + case LinphoneErrorBadCredentials: + return "Bad credentials"; + } + return "unknown error"; +} diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index f577ae985..f536bdd71 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -93,6 +93,7 @@ void linphone_address_set_port_int(LinphoneAddress *uri, int port); void linphone_address_clean(LinphoneAddress *uri); char *linphone_address_as_string(const LinphoneAddress *u); char *linphone_address_as_string_uri_only(const LinphoneAddress *u); +bool_t linphone_address_weak_compare(const LinphoneAddress *a1, const LinphoneAddress *a2); void linphone_address_destroy(LinphoneAddress *u); struct _SipSetupContext; @@ -155,6 +156,32 @@ const rtp_stats_t *linphone_call_log_get_remote_stats(const LinphoneCallLog *cl) char * linphone_call_log_to_str(LinphoneCallLog *cl); +/** + * The LinphoneCallParams is an object contaning various call related parameters. + * It can be used to retrieve parameters from a currently running call or modify the call's characterisitcs + * dynamically. +**/ +struct _LinphoneCallParams; +typedef struct _LinphoneCallParams LinphoneCallParams; + +LinphoneCallParams * linphone_call_params_copy(const LinphoneCallParams *cp); +void linphone_call_params_enable_video(LinphoneCallParams *cp, bool_t enabled); +bool_t linphone_call_params_video_enabled(const LinphoneCallParams *cp); +void linphone_call_params_destroy(LinphoneCallParams *cp); + +/** + * Enum describing failure reasons. +**/ +enum _LinphoneError{ + LinphoneErrorNone, + LinphoneErrorNoResponse, /**nstreams;++i){ ms_message("Processing for stream %i",i); ls=&local_offer->streams[i]; - rs=sal_media_description_find_stream(remote_answer,ls->proto,ls->type); + rs=sal_media_description_find_stream((SalMediaDescription*)remote_answer,ls->proto,ls->type); if (rs) { initiate_outgoing(ls,rs,&result->streams[j]); ++j; @@ -194,7 +194,7 @@ int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities for(i=0,j=0;instreams;++i){ rs=&remote_offer->streams[i]; ms_message("Processing for stream %i",i); - ls=sal_media_description_find_stream(local_capabilities,rs->proto,rs->type); + ls=sal_media_description_find_stream((SalMediaDescription*)local_capabilities,rs->proto,rs->type); if (ls){ initiate_incoming(ls,rs,&result->streams[j]); ++j; diff --git a/coreapi/private.h b/coreapi/private.h index b9e33b049..c23351595 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -54,6 +54,12 @@ #endif #endif + +struct _LinphoneCallParams{ + bool_t has_video; + bool_t pad[3]; +}; + struct _LinphoneCall { struct _LinphoneCore *core; @@ -76,12 +82,15 @@ struct _LinphoneCall struct _AudioStream *audiostream; /**/ struct _VideoStream *videostream; char *refer_to; + LinphoneCallParams params; bool_t refer_pending; bool_t media_pending; bool_t audio_muted; + bool_t camera_active; }; -LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to); + +LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, const LinphoneCallParams *params); LinphoneCall * linphone_call_new_incoming(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, SalOp *op); void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const char *message); @@ -174,7 +183,7 @@ void linphone_core_text_received(LinphoneCore *lc, const char *from, const char void linphone_call_init_media_streams(LinphoneCall *call); void linphone_call_start_media_streams(LinphoneCall *call); -void linphone_call_set_media_streams_dir(LinphoneCall *call, SalStreamDir dir); +void linphone_call_start_early_media(LinphoneCall *call); void linphone_call_stop_media_streams(LinphoneCall *call); const char * linphone_core_get_identity(LinphoneCore *lc); @@ -187,7 +196,7 @@ void linphone_core_stop_waiting(LinphoneCore *lc); int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call, LinphoneProxyConfig *dest_proxy); void linphone_core_start_pending_refered_calls(LinphoneCore *lc); extern SalCallbacks linphone_sal_callbacks; - +void linphone_proxy_config_set_error(LinphoneProxyConfig *cfg,LinphoneError error); struct _LinphoneProxyConfig { @@ -211,6 +220,7 @@ struct _LinphoneProxyConfig bool_t dial_escape_plus; void* user_data; time_t deletion_date; + LinphoneError error; }; struct _LinphoneAuthInfo @@ -310,6 +320,7 @@ typedef struct sound_config char source; char *local_ring; char *remote_ring; + char *ringback_tone; bool_t ec; bool_t ea; bool_t agc; @@ -414,6 +425,9 @@ int linphone_core_get_calls_nb(const LinphoneCore *lc); void linphone_core_set_state(LinphoneCore *lc, LinphoneGlobalState gstate, const char *message); +SalMediaDescription *create_local_media_description(LinphoneCore *lc, + LinphoneCall *call, bool_t with_video, bool_t only_one_codec); + #define HOLD_OFF (0) #define HOLD_ON (1) diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 251bdbb13..07a8e6c81 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -829,5 +829,11 @@ LinphoneRegistrationState linphone_proxy_config_get_state(const LinphoneProxyCon } return NULL; } +LinphoneError linphone_proxy_config_get_error(const LinphoneProxyConfig *cfg) { + return cfg->error; +} +void linphone_proxy_config_set_error(LinphoneProxyConfig *cfg,LinphoneError error) { + cfg->error = error; +} diff --git a/coreapi/sal.c b/coreapi/sal.c index ca5b4d815..ac44470a6 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -52,11 +52,11 @@ void sal_media_description_unref(SalMediaDescription *md){ } } -const SalStreamDescription *sal_media_description_find_stream(const SalMediaDescription *md, +SalStreamDescription *sal_media_description_find_stream(SalMediaDescription *md, SalMediaProto proto, SalStreamType type){ int i; for(i=0;instreams;++i){ - const SalStreamDescription *ss=&md->streams[i]; + SalStreamDescription *ss=&md->streams[i]; if (ss->proto==proto && ss->type==type) return ss; } return NULL; @@ -143,6 +143,10 @@ const char *sal_op_get_route(const SalOp *op){ return ((SalOpBase*)op)->route; } +const char *sal_op_get_remote_ua(const SalOp *op){ + return ((SalOpBase*)op)->remote_ua; +} + void *sal_op_get_user_pointer(const SalOp *op){ return ((SalOpBase*)op)->user_pointer; } @@ -187,6 +191,10 @@ void __sal_op_free(SalOp *op){ ms_free(b->origin); b->origin=NULL; } + if (b->remote_ua){ + ms_free(b->remote_ua); + b->remote_ua=NULL; + } if (b->local_media) sal_media_description_unref(b->local_media); if (b->remote_media) diff --git a/coreapi/sal.h b/coreapi/sal.h index 7c6c7867b..9f97c5239 100644 --- a/coreapi/sal.h +++ b/coreapi/sal.h @@ -128,7 +128,7 @@ void sal_media_description_ref(SalMediaDescription *md); void sal_media_description_unref(SalMediaDescription *md); bool_t sal_media_description_empty(const SalMediaDescription *md); bool_t sal_media_description_has_dir(const SalMediaDescription *md, SalStreamDir dir); -const SalStreamDescription *sal_media_description_find_stream(const SalMediaDescription *md, +SalStreamDescription *sal_media_description_find_stream(SalMediaDescription *md, SalMediaProto proto, SalStreamType type); void sal_media_description_set_dir(SalMediaDescription *md, SalStreamDir stream_dir); @@ -140,6 +140,7 @@ typedef struct SalOpBase{ char *from; char *to; char *origin; + char *remote_ua; SalMediaDescription *local_media; SalMediaDescription *remote_media; void *user_pointer; @@ -267,16 +268,19 @@ const char *sal_op_get_route(const SalOp *op); const char *sal_op_get_proxy(const SalOp *op); /*for incoming requests, returns the origin of the packet as a sip uri*/ const char *sal_op_get_network_origin(const SalOp *op); +/*returns far-end "User-Agent" string */ +const char *sal_op_get_remote_ua(const SalOp *op); void *sal_op_get_user_pointer(const SalOp *op); /*Call API*/ int sal_call_set_local_media_description(SalOp *h, SalMediaDescription *desc); int sal_call(SalOp *h, const char *from, const char *to); -int sal_call_notify_ringing(SalOp *h); +int sal_call_notify_ringing(SalOp *h, bool_t early_media); /*accept an incoming call or, during a call accept a reINVITE*/ int sal_call_accept(SalOp*h); int sal_call_decline(SalOp *h, SalReason reason, const char *redirection /*optional*/); int sal_call_hold(SalOp *h, bool_t holdon); +int sal_call_update(SalOp *h); SalMediaDescription * sal_call_get_final_media_description(SalOp *h); int sal_refer(SalOp *h, const char *refer_to); int sal_refer_accept(SalOp *h); diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c index 749bfce6b..428e6aed3 100644 --- a/coreapi/sal_eXosip2.c +++ b/coreapi/sal_eXosip2.c @@ -503,10 +503,31 @@ int sal_call(SalOp *h, const char *from, const char *to){ return 0; } -int sal_call_notify_ringing(SalOp *h){ - eXosip_lock(); - eXosip_call_send_answer(h->tid,180,NULL); - eXosip_unlock(); +int sal_call_notify_ringing(SalOp *h, bool_t early_media){ + osip_message_t *msg; + int err; + + /*if early media send also 180 and 183 */ + if (early_media && h->sdp_answer){ + msg=NULL; + eXosip_lock(); + err=eXosip_call_build_answer(h->tid,180,&msg); + if (msg){ + set_sdp(msg,h->sdp_answer); + eXosip_call_send_answer(h->tid,180,msg); + } + msg=NULL; + err=eXosip_call_build_answer(h->tid,183,&msg); + if (msg){ + set_sdp(msg,h->sdp_answer); + eXosip_call_send_answer(h->tid,183,msg); + } + eXosip_unlock(); + }else{ + eXosip_lock(); + eXosip_call_send_answer(h->tid,180,NULL); + eXosip_unlock(); + } return 0; } @@ -701,6 +722,16 @@ static void set_network_origin(SalOp *op, osip_message_t *req){ __sal_op_set_network_origin(op,origin); } +static void set_remote_ua(SalOp* op, osip_message_t *req){ + if (op->base.remote_ua==NULL){ + osip_header_t *h=NULL; + osip_message_get_user_agent(req,0,&h); + if (h){ + op->base.remote_ua=ms_strdup(h->hvalue); + } + } +} + static SalOp *find_op(Sal *sal, eXosip_event_t *ev){ if (ev->cid>0){ return sal_find_call(sal,ev->cid); @@ -720,6 +751,7 @@ static void inc_new_call(Sal *sal, eXosip_event_t *ev){ sdp_message_t *sdp=eXosip_get_sdp_info(ev->request); set_network_origin(op,ev->request); + set_remote_ua(op,ev->request); if (sdp){ op->sdp_offering=FALSE; @@ -865,7 +897,8 @@ static void call_ringing(Sal *sal, eXosip_event_t *ev){ sdp_message_t *sdp; SalOp *op=find_op(sal,ev); if (call_proceeding(sal, ev)==-1) return; - + + set_remote_ua(op,ev->response); sdp=eXosip_get_sdp_info(ev->response); if (sdp){ op->base.remote_media=sal_media_description_new(); @@ -888,7 +921,8 @@ static void call_accepted(Sal *sal, eXosip_event_t *ev){ } op->did=ev->did; - + set_remote_ua(op,ev->response); + sdp=eXosip_get_sdp_info(ev->response); if (sdp){ op->base.remote_media=sal_media_description_new(); @@ -1771,10 +1805,12 @@ void sal_set_keepalive_period(Sal *ctx,unsigned int value) { ctx->keepalive_period=value; eXosip_set_option (EXOSIP_OPT_UDP_KEEP_ALIVE, &value); } + const char * sal_address_get_port(const SalAddress *addr) { const osip_from_t *u=(const osip_from_t*)addr; return null_if_empty(u->url->port); } + int sal_address_get_port_int(const SalAddress *uri) { const char* port = sal_address_get_port(uri); if (port != NULL) { @@ -1813,3 +1849,29 @@ int sal_call_hold(SalOp *h, bool_t holdon) return err; } +/* sends a reinvite. Local media description may have changed by application since call establishment*/ +int sal_call_update(SalOp *h){ + int err=0; + osip_message_t *reinvite=NULL; + + eXosip_lock(); + if(eXosip_call_build_request(h->did,"INVITE",&reinvite) != OSIP_SUCCESS || reinvite==NULL){ + eXosip_unlock(); + return -1; + } + eXosip_unlock(); + osip_message_set_subject(reinvite,osip_strdup("Phone call parameters updated")); + osip_message_set_allow(reinvite, "INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO"); + if (h->base.root->session_expires!=0){ + osip_message_set_header(reinvite, "Session-expires", "200"); + osip_message_set_supported(reinvite, "timer"); + } + if (h->base.local_media){ + h->sdp_offering=TRUE; + set_sdp_from_desc(reinvite,h->base.local_media); + }else h->sdp_offering=FALSE; + eXosip_lock(); + err = eXosip_call_send_request(h->did, reinvite); + eXosip_unlock(); + return err; +} diff --git a/gtk/Makefile.am b/gtk/Makefile.am index 546e9f494..a2c38b342 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -45,8 +45,8 @@ linphone_3_SOURCES= \ loginframe.c \ linphone.h -linphone_3_LDADD=$(top_builddir)/oRTP/src/libortp.la \ - $(top_builddir)/mediastreamer2/src/libmediastreamer.la \ +linphone_3_LDADD=$(ORTP_LIBS) \ + $(MEDIASTREAMER_LIBS) \ $(top_builddir)/coreapi/liblinphone.la \ $(LIBGTK_LIBS) $(INTLLIBS) @@ -69,13 +69,13 @@ endif AM_CFLAGS= -DIN_LINPHONE -I$(top_srcdir)/coreapi/ \ - -I$(top_srcdir)/mediastreamer2/include/ \ + $(MEDIASTREAMER_CFLAGS) \ $(ORTP_CFLAGS) \ $(STRICT_OPTIONS) $(LIBGTK_CFLAGS) $(IPV6_CFLAGS) \ $(OSIP_CFLAGS) -version_date.h: $(top_srcdir)/configure.in +version_date.h: $(top_srcdir)/configure.ac echo "#define LINPHONE_VERSION_DATE \"$(VERSION)-`date +%y%m%d`\"" > $@ newdate: diff --git a/gtk/incall_view.c b/gtk/incall_view.c index 0ea060241..83df3a447 100644 --- a/gtk/incall_view.c +++ b/gtk/incall_view.c @@ -142,13 +142,14 @@ void linphone_gtk_in_call_view_set_incoming(LinphoneCall *call, bool_t with_paus GtkWidget *callview=(GtkWidget*)linphone_call_get_user_pointer(call); GtkWidget *status=linphone_gtk_get_widget(callview,"in_call_status"); GtkWidget *callee=linphone_gtk_get_widget(callview,"in_call_uri"); - GtkWidget *duration=linphone_gtk_get_widget(callview,"in_call_duration"); GtkWidget *animation=linphone_gtk_get_widget(callview,"in_call_animation"); GdkPixbufAnimation *pbuf=create_pixbuf_animation("calling_anim.gif"); GtkWidget *answer_button; gtk_label_set_markup(GTK_LABEL(status),_("Incoming call")); gtk_widget_show_all(linphone_gtk_get_widget(callview,"answer_decline_panel")); + gtk_widget_hide(linphone_gtk_get_widget(callview,"duration_frame")); + gtk_widget_hide(linphone_gtk_get_widget(callview,"mute_pause_buttons")); display_peer_name_in_label(callee,linphone_call_get_remote_address (call)); answer_button=linphone_gtk_get_widget(callview,"accept_call"); @@ -161,7 +162,6 @@ void linphone_gtk_in_call_view_set_incoming(LinphoneCall *call, bool_t with_paus gtk_button_set_image(GTK_BUTTON(linphone_gtk_get_widget(callview,"decline_call")), create_pixmap (linphone_gtk_get_ui_config("stop_call_icon","stopcall-red.png"))); - gtk_label_set_text(GTK_LABEL(duration),_("00::00::00")); if (pbuf!=NULL){ gtk_image_set_from_animation(GTK_IMAGE(animation),pbuf); g_object_unref(G_OBJECT(pbuf)); @@ -178,6 +178,8 @@ void linphone_gtk_in_call_view_set_in_call(LinphoneCall *call){ display_peer_name_in_label(callee,linphone_call_get_remote_address (call)); + gtk_widget_show(linphone_gtk_get_widget(callview,"duration_frame")); + gtk_widget_show(linphone_gtk_get_widget(callview,"mute_pause_buttons")); gtk_widget_hide(linphone_gtk_get_widget(callview,"answer_decline_panel")); gtk_label_set_markup(GTK_LABEL(status),_("In call")); diff --git a/gtk/linphone.h b/gtk/linphone.h index 5cbf79fb5..637448818 100644 --- a/gtk/linphone.h +++ b/gtk/linphone.h @@ -99,4 +99,5 @@ void linphone_gtk_enable_mute_button(GtkButton *button, gboolean sensitive); void linphone_gtk_enable_hold_button(LinphoneCall *call, gboolean sensitive, gboolean holdon); void linphone_gtk_show_login_frame(LinphoneProxyConfig *cfg); - +void linphone_gtk_exit_login_frame(void); +void linphone_gtk_set_ui_config(const char *key, const char *value); diff --git a/gtk/loginframe.c b/gtk/loginframe.c index 957b26726..f1a67d9d5 100644 --- a/gtk/loginframe.c +++ b/gtk/loginframe.c @@ -27,28 +27,28 @@ enum { NetworkKindOpticalFiber }; -static gboolean check_login_ok(LinphoneProxyConfig *cfg){ - if (linphone_proxy_config_is_registered(cfg)){ - linphone_gtk_exit_login_frame(); - return FALSE; - } - return TRUE; -} - static void do_login(SipSetupContext *ssctx, const char *identity, const char * passwd){ - GtkWidget *mw=linphone_gtk_get_main_window(); if (sip_setup_context_login_account(ssctx,identity,passwd)==0){ - guint t=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(mw),"login_tout")); - if (t!=0) g_source_remove(t); - t=g_timeout_add(50,(GSourceFunc)check_login_ok,sip_setup_context_get_proxy_config(ssctx)); - g_object_set_data(G_OBJECT(mw),"login_tout",GINT_TO_POINTER(t)); } } static gboolean do_login_noprompt(LinphoneProxyConfig *cfg){ SipSetupContext *ssctx=linphone_proxy_config_get_sip_setup_context(cfg); + LinphoneAddress *addr; + const char *username; + char *tmp; if (ssctx==NULL) return TRUE;/*not ready ?*/ - do_login(ssctx,linphone_proxy_config_get_identity(cfg),NULL); + username=linphone_gtk_get_ui_config ("login_username",NULL); + if (username==NULL) { + linphone_gtk_set_ui_config_int("automatic_login",0); + linphone_gtk_show_login_frame(cfg); + return FALSE; + } + addr=linphone_address_new(linphone_proxy_config_get_identity(cfg)); + linphone_address_set_username(addr,username); + tmp=linphone_address_as_string (addr); + do_login(ssctx,tmp,NULL); + linphone_address_destroy(addr); return FALSE; } @@ -96,6 +96,11 @@ void linphone_gtk_show_login_frame(LinphoneProxyConfig *cfg){ g_free(str); from=linphone_address_new(linphone_proxy_config_get_identity(cfg)); + if (linphone_address_get_username(from)[0]=='?'){ + const char *username=linphone_gtk_get_ui_config ("login_username",NULL); + if (username) + linphone_address_set_username(from,username); + } ai=linphone_core_find_auth_info(lc,linphone_proxy_config_get_domain(cfg),linphone_address_get_username(from)); /*display the last entered username, if not '?????'*/ @@ -152,6 +157,7 @@ void linphone_gtk_login_frame_connect_clicked(GtkWidget *button){ autologin=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(mw,"automatic_login"))); linphone_gtk_set_ui_config_int("automatic_login",autologin); + linphone_gtk_set_ui_config("login_username",username); from=linphone_address_new(linphone_proxy_config_get_identity(cfg)); linphone_address_set_username(from,username); diff --git a/gtk/main.c b/gtk/main.c index 452c7783f..ed2b77ba1 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -41,6 +41,7 @@ const char *this_program_ident_string="linphone_ident_string=" LINPHONE_VERSION; static LinphoneCore *the_core=NULL; static GtkWidget *the_ui=NULL; +static void linphone_gtk_registration_state_changed(LinphoneCore *lc, LinphoneProxyConfig *cfg, LinphoneRegistrationState rs, const char *msg); static void linphone_gtk_show(LinphoneCore *lc); static void linphone_gtk_notify_recv(LinphoneCore *lc, LinphoneFriend * fid); static void linphone_gtk_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf, const char *url); @@ -94,7 +95,7 @@ static GOptionEntry linphone_options[]={ .description = N_("if set automatically answer incoming calls") }, #ifdef WIN32 - { /* zsd addition */ + { .long_name = "workdir", .short_name = '\0', .arg = G_OPTION_ARG_STRING, @@ -193,6 +194,7 @@ static void linphone_gtk_init_liblinphone(const char *config_file, LinphoneCoreVTable vtable={0}; vtable.call_state_changed=linphone_gtk_call_state_changed; + vtable.registration_state_changed=linphone_gtk_registration_state_changed; vtable.show=linphone_gtk_show; vtable.notify_presence_recv=linphone_gtk_notify_recv; vtable.new_unknown_subscriber=linphone_gtk_new_unknown_subscriber; @@ -413,8 +415,10 @@ void linphone_gtk_show_about(){ struct stat filestat; const char *license_file=PACKAGE_DATA_DIR "/linphone/COPYING"; GtkWidget *about; + const char *tmp; GdkPixbuf *logo=create_pixbuf( linphone_gtk_get_ui_config("logo","linphone-banner.png")); + static const char *defcfg="defcfg"; about=linphone_gtk_create_window("about"); gtk_about_dialog_set_url_hook(about_url_clicked,NULL,NULL); @@ -436,7 +440,19 @@ void linphone_gtk_show_about(){ gtk_about_dialog_set_program_name(GTK_ABOUT_DIALOG(about),linphone_gtk_get_ui_config("title","Linphone")); gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(about),linphone_gtk_get_ui_config("home","http://www.linphone.org")); if (logo) gtk_about_dialog_set_logo(GTK_ABOUT_DIALOG(about),logo); - + tmp=linphone_gtk_get_ui_config("artists",defcfg); + if (tmp!=defcfg){ + const char *tmp2[2]; + tmp2[0]=tmp; + tmp2[1]=NULL; + gtk_about_dialog_set_artists(GTK_ABOUT_DIALOG(about),tmp2); + } + tmp=linphone_gtk_get_ui_config("translators",defcfg); + if (tmp!=defcfg) + gtk_about_dialog_set_translator_credits (GTK_ABOUT_DIALOG(about),tmp); + tmp=linphone_gtk_get_ui_config("comments",defcfg); + if (tmp!=defcfg) + gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(about),tmp); gtk_widget_show(about); } @@ -977,6 +993,23 @@ static void linphone_gtk_call_state_changed(LinphoneCore *lc, LinphoneCall *call linphone_gtk_update_call_buttons (call); } +static void linphone_gtk_registration_state_changed(LinphoneCore *lc, LinphoneProxyConfig *cfg, + LinphoneRegistrationState rs, const char *msg){ + switch (rs){ + case LinphoneRegistrationOk: + if (cfg){ + SipSetup *ss=linphone_proxy_config_get_sip_setup(cfg); + if (ss && (sip_setup_get_capabilities(ss) & SIP_SETUP_CAP_LOGIN)){ + linphone_gtk_exit_login_frame(); + } + } + break; + default: + break; + } +} + + static void icon_popup_menu(GtkStatusIcon *status_icon, guint button, guint activate_time, gpointer user_data){ GtkWidget *menu=(GtkWidget*)g_object_get_data(G_OBJECT(status_icon),"menu"); gtk_menu_popup(GTK_MENU(menu),NULL,NULL,gtk_status_icon_position_menu,status_icon,button,activate_time); @@ -1138,6 +1171,7 @@ static void linphone_gtk_configure_main_window(){ static const char *search_icon; static gboolean update_check_menu; static gboolean buttons_have_borders; + static gboolean show_abcd; GtkWidget *w=linphone_gtk_get_main_window(); if (!config_loaded){ title=linphone_gtk_get_ui_config("title","Linphone"); @@ -1148,6 +1182,7 @@ static void linphone_gtk_configure_main_window(){ search_icon=linphone_gtk_get_ui_config("directory_search_icon",NULL); update_check_menu=linphone_gtk_get_ui_config_int("update_check_menu",0); buttons_have_borders=linphone_gtk_get_ui_config_int("buttons_border",1); + show_abcd=linphone_gtk_get_ui_config_int("show_abcd",1); config_loaded=TRUE; } linphone_gtk_configure_window(w,"main_window"); @@ -1205,6 +1240,13 @@ static void linphone_gtk_configure_main_window(){ if (update_check_menu){ gtk_widget_show(linphone_gtk_get_widget(w,"versioncheck_item")); } + if (!show_abcd){ + gtk_widget_hide(linphone_gtk_get_widget(w,"dtmf_A")); + gtk_widget_hide(linphone_gtk_get_widget(w,"dtmf_B")); + gtk_widget_hide(linphone_gtk_get_widget(w,"dtmf_C")); + gtk_widget_hide(linphone_gtk_get_widget(w,"dtmf_D")); + gtk_table_resize(GTK_TABLE(linphone_gtk_get_widget(w,"dtmf_table")),4,3); + } } void linphone_gtk_manage_login(void){ @@ -1220,7 +1262,7 @@ void linphone_gtk_manage_login(void){ } -void linphone_gtk_close(GtkWidget *mw){ +gboolean linphone_gtk_close(GtkWidget *mw){ /*shutdown calls if any*/ LinphoneCore *lc=linphone_gtk_get_core(); if (linphone_core_in_call(lc)){ @@ -1228,6 +1270,7 @@ void linphone_gtk_close(GtkWidget *mw){ } linphone_core_enable_video_preview(lc,FALSE); gtk_widget_hide(mw); + return TRUE; } static void linphone_gtk_init_main_window(){ diff --git a/gtk/main.ui b/gtk/main.ui index e1ea351ea..a2c717df5 100644 --- a/gtk/main.ui +++ b/gtk/main.ui @@ -176,7 +176,7 @@ True - Aid_e + _Help True @@ -523,6 +523,28 @@ 2 + + + True + + + Add contact + True + True + image6 + + + + False + False + 0 + + + + + 3 + + @@ -1272,6 +1294,8 @@ + False + False 2 @@ -1381,7 +1405,7 @@ - + True 0 @@ -1414,7 +1438,7 @@ - + True spread @@ -1467,4 +1491,8 @@ + + True + gtk-add + diff --git a/gtk/parameters.ui b/gtk/parameters.ui index 9d7f79e38..c594612cd 100644 --- a/gtk/parameters.ui +++ b/gtk/parameters.ui @@ -1,55 +1,56 @@ + + - 3001 - 500 - 10 - 1 - 10 500 + 500 + 3001 + 1 + 10 + 10 - 65535 - 1 - 10 - 1 - 10 1 + 1 + 65535 + 1 + 10 + 10 - 65535 - 1 - 10 - 1 - 10 1 + 1 + 65535 + 1 + 10 + 10 - 65535 - 1 - 10 - 1 - 10 1 + 1 + 65535 + 1 + 10 + 10 - 100000 -1 - 10 + 100000 1 + 10 10 - 0 - 100000 -1 - 10 + 100000 1 + 10 10 - 0 + @@ -60,6 +61,7 @@ + @@ -70,6 +72,7 @@ + @@ -80,6 +83,7 @@ + @@ -90,6 +94,7 @@ + @@ -100,6 +105,7 @@ + @@ -113,6 +119,7 @@ + @@ -121,8 +128,6 @@ - - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK Settings @@ -166,7 +171,7 @@ True False True - + 0 @@ -177,7 +182,7 @@ True True adjustment1 - + 1 @@ -195,7 +200,7 @@ True False True - + 1 @@ -209,7 +214,7 @@ False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK True - + 2 @@ -255,7 +260,7 @@ True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK adjustment2 - + 1 @@ -270,7 +275,7 @@ True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK adjustment3 - + 1 @@ -285,7 +290,7 @@ True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK adjustment4 - + 1 @@ -359,7 +364,7 @@ False True True - + False @@ -380,7 +385,7 @@ True True no_nat - + 0 @@ -406,7 +411,7 @@ True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - + 1 @@ -437,7 +442,7 @@ True True no_nat - + 0 @@ -463,7 +468,7 @@ True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - + 1 @@ -557,7 +562,7 @@ True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - + 0 @@ -571,7 +576,7 @@ True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK True - + 1 @@ -603,7 +608,7 @@ True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - + 1 @@ -617,8 +622,8 @@ True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - model1 + @@ -638,8 +643,8 @@ True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - model2 + @@ -709,8 +714,8 @@ True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - model3 + @@ -732,7 +737,7 @@ True False True - + 1 @@ -762,7 +767,7 @@ - + True 0 @@ -787,8 +792,8 @@ True - model4 + @@ -815,9 +820,9 @@ True - 0 - model5 + 0 + @@ -837,7 +842,7 @@ - + True <b>Video</b> True @@ -850,6 +855,9 @@ + + 1 + @@ -890,7 +898,7 @@ True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - This section defines your SIP address when not using a SIP account + This section defines your SIP address when not using a SIP account 0 @@ -915,7 +923,7 @@ True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - + 1 @@ -949,7 +957,7 @@ True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - + 1 @@ -1033,7 +1041,7 @@ True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - + True @@ -1073,7 +1081,7 @@ True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - + True @@ -1113,7 +1121,7 @@ True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - + True @@ -1151,7 +1159,7 @@ True True - + True @@ -1227,7 +1235,7 @@ virtual network ! True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - + True @@ -1279,6 +1287,9 @@ virtual network ! + + 2 + @@ -1334,9 +1345,9 @@ virtual network ! True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - model6 + 0 + @@ -1387,7 +1398,7 @@ virtual network ! True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK True - + False @@ -1403,7 +1414,7 @@ virtual network ! True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK True - + False @@ -1417,7 +1428,7 @@ virtual network ! True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - + True @@ -1457,7 +1468,7 @@ virtual network ! True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - + True @@ -1540,9 +1551,9 @@ virtual network ! True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 stands for "unlimited" + 0 stands for "unlimited" adjustment5 - + 1 @@ -1556,9 +1567,9 @@ virtual network ! True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 stands for "unlimited" + 0 stands for "unlimited" adjustment6 - + 1 @@ -1603,6 +1614,9 @@ virtual network ! + + 3 + @@ -1649,8 +1663,8 @@ virtual network ! True - model7 + @@ -1689,7 +1703,7 @@ virtual network ! True False True - + @@ -1708,6 +1722,9 @@ virtual network ! + + 4 + @@ -1753,7 +1770,7 @@ virtual network ! True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - + True diff --git a/gtk/support.c b/gtk/support.c index 2124d2ee8..227d5b42c 100644 --- a/gtk/support.c +++ b/gtk/support.c @@ -192,6 +192,10 @@ void linphone_gtk_set_ui_config_int(const char *key , int val){ lp_config_set_int(cfg,"GtkUi",key,val); } +void linphone_gtk_set_ui_config(const char *key , const char * val){ + LpConfig *cfg=linphone_core_get_config(linphone_gtk_get_core()); + lp_config_set_string(cfg,"GtkUi",key,val); +} static void parse_item(const char *item, const char *window_name, GtkWidget *w, gboolean show){ char tmp[64]; diff --git a/mediastreamer2 b/mediastreamer2 index f2ddc59ed..9492b1141 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit f2ddc59ed02f26ff828243fa400abae925b6f730 +Subproject commit 9492b114126f17d06ca365757ada450ad72d5eb5 diff --git a/pixmaps/Makefile.am b/pixmaps/Makefile.am index b462cf8e7..087e6fcd4 100644 --- a/pixmaps/Makefile.am +++ b/pixmaps/Makefile.am @@ -12,6 +12,6 @@ status-orange.png \ status-red.png \ status-offline.png \ contact-orange.png dialer-orange.png history-orange.png\ -startcall-green.png stopcall-red.png +startcall-green.png stopcall-red.png addcall-green.png EXTRA_DIST=$(pixmap_DATA) diff --git a/share/Makefile.am b/share/Makefile.am index 57f26a8a1..6def02724 100644 --- a/share/Makefile.am +++ b/share/Makefile.am @@ -5,6 +5,7 @@ LINPHONE_SOUNDS=ringback.wav hello8000.wav hello16000.wav LINPHONE_RINGS=rings/orig.wav \ rings/oldphone.wav \ rings/oldphone-mono.wav \ + rings/oldphone-mono-30s.caf \ rings/rock.wav \ rings/bigben.wav \ rings/toy.wav \ diff --git a/share/rings/oldphone-mono-30s.caf b/share/rings/oldphone-mono-30s.caf new file mode 100644 index 000000000..148592939 Binary files /dev/null and b/share/rings/oldphone-mono-30s.caf differ