Merge branch 'master' of git.savannah.nongnu.org:/srv/git/linphone

Conflicts:
	mediastreamer2
This commit is contained in:
Guillaume Beraudo 2011-02-23 16:13:08 +01:00
commit f515a560bc
70 changed files with 9469 additions and 11347 deletions

60
AUTHORS
View file

@ -1,57 +1,13 @@
Simon MORLAT (simon dot morlat at linphone dot org) wrotes:
- main graphical program (gnome)
- RTP library (oRTP)
- SIP user-agent library (osipua)
- audio library (mediastreamer), for codec and i/o handling.
- sipomatic, the automatic sip replier, which is often used for testing.
Main authors:
Florian Wintertein < f-win at gmx dot net > wrotes the console version of linphone (linphonec)
Belledonne Communications SARL team:
Simon Morlat, Jehan Monnier, Guillaume Beraudo
Contributors:
Florian Wintertein < f-win at gmx dot net > originaly wrotes the console version of linphone (linphonec)
in console/ directory.
Aymeric Moizard (jack at atosc dot org) wrotes:
- the oSIP SIP transactionnal stack (not part of linphone)
- some piece of code of the osip distribution have been reused in osipua
- presence information support in osipua
- and contributes to some parts of osipua (digest authentification)
For more information about oSIP, see http://osip.atosc.org
Sharath Udupa is developing the media_api, a usefull library to manage audio and video streams
for basic calls as well as conference.
Sandro Santilli < strk at keybit dot net > wrote enhancements in the
console interface (readline, new commands) and some bug fixes for
the core api.
console interface (readline, new commands).
Bryan Ogawa ( bko at cisco dot com ) sent a patch that made the linphone-0.7.1 release.
This patch fixed several issues in the SIP part while working with proxies.
Koichi KUNITAKE < kunitake at linux-ipv6 dot org > has contributed a patch bringing
full IPv6 support.
The Speex codec is a project from Jean Marc Valin. See http://speex.sourceforge.net for more
information.
The GSM library was written by :
Jutta Degener and Carsten Bormann,Technische Universitaet Berlin.
The LPC10-1.5 library was written by:
Andy Fingerhut
Applied Research Laboratory <-- this line is optional if
Washington University, Campus Box 1045/Bryan 509 you have limited space
One Brookings Drive
Saint Louis, MO 63130-4899
jaf@arl.wustl.edu
http://www.arl.wustl.edu/~jaf/
See text files in gsmlib and lpc10-1.5 directories for further information.
G711 library has some code from the alsa-lib on http://www.alsa-project.org
Icons by Pablo Marcelo Moia.
Translations:
fr: Simon Morlat
en: Simon Morlat and Delphine Perreau
it: Alberto Zanoni <alberto.zanoni@-NO-SPAM-PLEASE!-tiscalinet.it>
de: Jean-Jacques Sarton <jj.sarton@-NO-SPAM-PLEASE-t-online.de>
es: Jesús Benítez <gnelson at inMail dot sk>

View file

@ -39,7 +39,7 @@ ZIP_EXCLUDED=include lib \
SDK_ZIPFILE=$(shell cd $(top_builddir) && pwd)/lib$(PACKAGE)-win32-$(VERSION).zip
SDK_EXCLUDED= \
bin/linphone-3.exe \
bin/linphone.exe \
lib/*.la \
share/linphone \
share/pixmaps \

11
NEWS
View file

@ -1,4 +1,9 @@
linphone-3.4.0 -- XXXXX
linphone-3.4.1 -- February 17th, 2011
* bugfixes
* gtk executable is renamed "linphone" (was linphone-3 before)
Requires mediastreamer-2.7.1
linphone-3.4.0 -- February 7th, 2011
* implement multiple calls feature:
- call hold (with possibility to play a music file)
- call resume
@ -6,8 +11,10 @@ linphone-3.4.0 -- XXXXX
- creation of another outgoing call while already in call
- blind call transfer
- attended call transfer
**CAUTION**: LinphoneCoreVTable has changed: pay attention to this when upgrading an old application to a newer liblinphone.
* improve bandwidth management (one b=AS line is used for audio+video)
* improvements in the echo limiter
* improvements in the echo limiter performance
* implement a echo calibration feature (see linphone_core_start_echo_calibration()).
* stun support bugfixes
* possibility to use two video windows, one for local preview, one for remote video (linphonec only)
* optimize by not re-creating streams when SDP is unchanged during a reinvite

10
README
View file

@ -5,16 +5,16 @@ This is Linphone, a free (GPL) video softphone based on the SIP protocol.
- you need at least:
- libosip2>=3.0.3
- libeXosip2>=3.0.3
- speex>=1.1.6
- libreadline
- speex>=1.2.0 (including libspeexdsp part)
- libreadline (optional: for convenient command line in linphonec)
+ gsm codec (gsm source package or libgsm-dev or gsm-devel) (optional)
+ if you want to gtk/glade interface:
- gtk>=2.16.0
- libglade>=2.2
+ if you want video support:
- SDL>=1.2.10
- libavcodec (ffmpeg) from a year 2007 or later cvs/svn
- libavcodec (ffmpeg)
- libswscale (part of ffmpeg too) for better scaling performance
- theora (optional)
with their corresponding -dev or -devel package if you don't use source packages.
@ -38,7 +38,7 @@ Here is a short description of the content of the source tree.
- coreapi/ is the central point of linphone, which handles relationship between sip signalisation and media
streaming. It contains an easy to use api to create a sip phone.
- gtk-glade/ is the directory that contains the gui frontend of linphone. It uses all libraries descibed above.
- gtk/ is the directory that contains the gui frontend of linphone. It uses all libraries descibed above.
- console/
* linphonec.c is the main file for the console version of linphone.

View file

@ -49,6 +49,8 @@ rm /lib/libgcc.a /lib/libmingw32.a /lib/libmingwex.a
#Remove libintl from gtk, we don't need it and it conflicts with the one supplied by mingw.
rm /lib/libintl.dll.a
rm /lib/libintl.la
rm /lib/libintl.a
rm /include/intl.h
* Download and install Inno Setup Compiler (required only if you run 'make setup.exe'). Add it to your windows Path environment variable.
@ -56,7 +58,8 @@ rm /include/intl.h
Get Linphone source code
************************
Install msys-git from (http://code.google.com/p/msysgit/)
Install msys-git from (http://code.google.com/p/msysgit/). During installation you are asked to make a choice about how line endings are treated by git.
Choose "Checkout line endings as they are, commit as they are". THIS CHOICE IS VERY IMPORTANT. OTHERS BREAK AUTOMAKE.
It is recommended that you create a directory somewhere with a path without any spaces or ~ characters, for example
c:\sources\

View file

@ -46,13 +46,14 @@ LOCAL_SRC_FILES = \
sal_eXosip2_sdp.c \
offeranswer.c \
callbacks.c \
linphonecall.c
linphonecall.c \
ec-calibrator.c
LOCAL_CFLAGS += \
-D_BYTE_ORDER=_LITTLE_ENDIAN \
-DORTP_INET6 \
-DENABLE_TRACE \
-DLINPHONE_VERSION=\"Linphone-3.3.x\" \
-DLINPHONE_VERSION=\"3.4.0\" \
-DLINPHONE_PLUGINS_DIR=\"\\tmp\" \
-DLOG_DOMAIN=\"Linphone\"

View file

@ -1,6 +1,6 @@
dnl Process this file with autoconf to produce a configure script.
AC_INIT([linphone],[3.3.99.10],[linphone-developers@nongnu.org])
AC_INIT([linphone],[3.4.1],[linphone-developers@nongnu.org])
AC_CANONICAL_SYSTEM
AC_CONFIG_SRCDIR([coreapi/linphonecore.c])
@ -298,7 +298,9 @@ AC_ARG_ENABLE(x11,
if test "$video" = "true"; then
if test "$enable_x11" = "true"; then
AC_CHECK_HEADERS(X11/Xlib.h)
AC_CHECK_HEADERS(X11/Xlib.h)
AC_CHECK_LIB(X11,XUnmapWindow, X11_LIBS="-lX11")
AC_SUBST(X11_LIBS)
fi
AC_DEFINE(VIDEO_ENABLED,1,[defined if video support is available])
fi

View file

@ -23,7 +23,8 @@ linphonec_LDADD = $(top_builddir)/coreapi/liblinphone.la $(READLINE_LIBS) \
$(MEDIASTREAMER_LIBS) \
$(ORTP_LIBS) \
$(SPEEX_LIBS) \
$(OSIP_LIBS)
$(OSIP_LIBS) \
$(X11_LIBS)
if BUILD_WIN32
#special build of linphonec to detach from the windows console
@ -33,17 +34,6 @@ linphoned_LDADD=$(linphonec_LDADD)
endif
sipomatic_SOURCES=\
sipomatic.c sipomatic.h
sipomatic_CFLAGS= $(COMMON_CFLAGS) $(CONSOLE_FLAGS)
sipomatic_LDADD= $(INTLLIBS) \
$(top_builddir)/coreapi/liblinphone.la \
$(MEDIASTREAMER_LIBS) \
$(ORTP_LIBS) \
$(SPEEX_LIBS) \
$(OSIP_LIBS)
linphonecsh_SOURCES = shell.c
linphonecsh_CFLAGS = $(CONSOLE_FLAGS)
linphonecsh_LDADD = $(ORTP_LIBS)

View file

@ -78,6 +78,7 @@ static int lpc_cmd_unregister(LinphoneCore *, char *);
static int lpc_cmd_duration(LinphoneCore *lc, char *args);
static int lpc_cmd_status(LinphoneCore *lc, char *args);
static int lpc_cmd_ports(LinphoneCore *lc, char *args);
static int lpc_cmd_param(LinphoneCore *lc, char *args);
static int lpc_cmd_speak(LinphoneCore *lc, char *args);
static int lpc_cmd_acodec(LinphoneCore *lc, char *args);
static int lpc_cmd_vcodec(LinphoneCore *lc, char *args);
@ -315,6 +316,10 @@ static LPC_COMMAND advanced_commands[] = {
{ "ports", lpc_cmd_ports, "Network ports configuration",
"'ports' \t: prints current used ports.\n"
"'ports sip <port number>'\t: Sets the sip port.\n" },
{ "param", lpc_cmd_param, "parameter set or read as normally given in .linphonerc",
"'param <section> <parameter> [<value>]' \t: reads [sets] given parameter.\n"
"NOTES: - changes may become effective after (re)establishing a sip connection.\n"
" - upon exit, .linphonerc will reflect the updated state.\n" },
{ "speak", lpc_cmd_speak, "Speak a sentence using espeak TTS engine",
"This feature is available only in file mode. (see 'help soundcard')\n"
"'speak <voice name> <sentence>' : speak a text using the specified espeak voice.\n"
@ -473,7 +478,8 @@ lpc_cmd_help(LinphoneCore *lc, char *arg)
}
linphonec_out("---------------------------\n");
linphonec_out("Type 'help <command>' for more details or 'help advanced' to list additional commands.\n");
linphonec_out("Type 'help <command>' for more details or\n");
linphonec_out(" 'help advanced' to list additional commands.\n");
return 1;
}
@ -2014,6 +2020,35 @@ static int lpc_cmd_ports(LinphoneCore *lc, char *args)
return 1;
}
static int lpc_cmd_param(LinphoneCore *lc, char *args)
{
char section[20], param[20], value[50];
const char *string;
if (args == NULL) {
return 0;
}
switch (sscanf(args,"%s %s %s",section,param,value)) {
// case 1 might show all current settings under a section
case 2:
string = lp_config_get_string(linphone_core_get_config(lc), section, param, "(undef)");
linphonec_out("current value: %s\n", string);
break;
case 3:
if (lp_config_get_string(linphone_core_get_config(lc), section, param, NULL) != NULL) {
lp_config_set_string(linphone_core_get_config(lc), section, param, value);
// no indication of existence
linphonec_out("updated value: %s\n", value);
} else {
linphonec_out("only update of existing variables are allowed\n");
}
break;
default:
return 0;
}
return 1;
}
static int lpc_cmd_speak(LinphoneCore *lc, char *args){
#ifndef WIN32
char voice[64];

View file

@ -80,7 +80,6 @@
#ifdef HAVE_X11_XLIB_H
#include <X11/Xlib.h>
#include <SDL/SDL_syswm.h>
#endif
/***************************************************************************

View file

@ -35,7 +35,8 @@ liblinphone_la_SOURCES=\
linphonecall.c \
sipsetup.c sipsetup.h \
siplogin.c \
lsd.c linphonecore_utils.h
lsd.c linphonecore_utils.h \
ec-calibrator.c
liblinphone_la_LDFLAGS= -version-info $(LIBLINPHONE_SO_VERSION) -no-undefined
@ -49,7 +50,7 @@ if BUILD_WIN32
liblinphone_la_LIBADD+=$(top_builddir)/oRTP/src/libortp.la
endif
noinst_PROGRAMS=test_lsd
noinst_PROGRAMS=test_lsd test_ecc
test_lsd_SOURCES=test_lsd.c
@ -57,6 +58,14 @@ test_lsd_LDADD=liblinphone.la \
$(MEDIASTREAMER_LIBS) \
$(ORTP_LIBS)
test_ecc_SOURCES=test_ecc.c
test_ecc_LDADD=liblinphone.la \
$(MEDIASTREAMER_LIBS) \
$(ORTP_LIBS)
AM_CFLAGS=$(STRICT_OPTIONS) -DIN_LINPHONE \
$(ORTP_CFLAGS) \
$(OSIP_CFLAGS) \

View file

@ -235,10 +235,12 @@ static void call_ringing(SalOp *h){
if (lc->ringstream!=NULL) return; /*already ringing !*/
if (lc->sound_conf.play_sndcard!=NULL){
MSSndCard *ringcard=lc->sound_conf.lsd_card ? lc->sound_conf.lsd_card : lc->sound_conf.play_sndcard;
ms_message("Remote ringing...");
lc->ringstream=ring_start(lc->sound_conf.remote_ring,2000,ringcard);
linphone_call_set_state(call,LinphoneCallOutgoingRinging,"Remote ringing");
}
ms_message("Remote ringing...");
if (lc->vtable.display_status)
lc->vtable.display_status(lc,_("Remote ringing..."));
linphone_call_set_state(call,LinphoneCallOutgoingRinging,"Remote ringing");
}else{
/*accept early media */
if (call->audiostream && call->audiostream->ticker!=NULL){
@ -303,18 +305,30 @@ static void call_accepted(SalOp *op){
ms_free(msg);
}
linphone_core_update_streams (lc,call,md);
linphone_call_set_state(call,LinphoneCallPaused,"Call paused");
linphone_call_set_state(call,LinphoneCallPausedByRemote,"Call paused by remote");
}else{
if (lc->vtable.display_status){
lc->vtable.display_status(lc,_("Call answered - connected."));
}
if (call->state==LinphoneCallStreamsRunning){
/*media was running before, the remote as acceted a call modification (that is
a reinvite made by us. We must notify the application this reinvite was accepted*/
linphone_call_set_state(call, LinphoneCallUpdated, "Call updated");
}else{
if (call->state==LinphoneCallResuming){
if (lc->vtable.display_status){
lc->vtable.display_status(lc,_("Call resumed."));
}
}else{
if (lc->vtable.display_status){
char *tmp=linphone_call_get_remote_address_as_string (call);
char *msg=ms_strdup_printf(_("Call answered by %s."),tmp);
lc->vtable.display_status(lc,msg);
ms_free(tmp);
ms_free(msg);
}
}
}
linphone_core_update_streams (lc,call,md);
linphone_call_set_state(call, LinphoneCallStreamsRunning, "Streams running");
lc->current_call=call;
}
}else{
/*send a bye*/
@ -349,6 +363,7 @@ static void call_ack(SalOp *op){
}
}
/* this callback is called when an incoming re-INVITE modifies the session*/
static void call_updating(SalOp *op){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
@ -360,32 +375,22 @@ static void call_updating(SalOp *op){
if (md && !sal_media_description_empty(md))
{
if ((call->state==LinphoneCallPausedByRemote || call->state==LinphoneCallPaused) &&
sal_media_description_has_dir(md,SalStreamSendRecv) && strcmp(md->addr,"0.0.0.0")!=0){
/*make sure we can be resumed */
if (lc->current_call!=NULL && lc->current_call!=call){
ms_warning("Attempt to be resumed but already in call with somebody else!");
/*we are actively running another call, reject with a busy*/
sal_call_decline (op,SalReasonBusy,NULL);
return;
if (sal_media_description_has_dir(call->localdesc,SalStreamSendRecv)){
ms_message("Our local status is SalStreamSendRecv");
if (sal_media_description_has_dir (md,SalStreamRecvOnly) || sal_media_description_has_dir(md,SalStreamInactive)){
/* we are being paused */
if(lc->vtable.display_status)
lc->vtable.display_status(lc,_("We are being paused..."));
linphone_call_set_state (call,LinphoneCallPausedByRemote,"Call paused by remote");
}else if (!sal_media_description_has_dir(call->resultdesc,SalStreamSendRecv) && sal_media_description_has_dir(md,SalStreamSendRecv)){
if(lc->vtable.display_status)
lc->vtable.display_status(lc,_("We have been resumed..."));
linphone_call_set_state (call,LinphoneCallStreamsRunning,"Connected (streams running)");
lc->current_call=call;
}else{
prevstate=call->state;
linphone_call_set_state(call, LinphoneCallUpdatedByRemote,"Call updated by remote");
}
if(lc->vtable.display_status)
lc->vtable.display_status(lc,_("We have been resumed..."));
linphone_call_set_state (call,LinphoneCallStreamsRunning,"Connected (streams running)");
}
else if(call->state==LinphoneCallStreamsRunning &&
( sal_media_description_has_dir(md,SalStreamRecvOnly)
|| sal_media_description_has_dir(md,SalStreamInactive)
|| strcmp(md->addr,"0.0.0.0")==0)){
if(lc->vtable.display_status)
lc->vtable.display_status(lc,_("We are being paused..."));
linphone_call_set_state (call,LinphoneCallPausedByRemote,"Call paused by remote");
if (lc->current_call!=call){
ms_error("Inconsitency detected: current call is %p but call %p is being paused !",lc->current_call,call);
}
}else{
prevstate=call->state;
linphone_call_set_state(call, LinphoneCallUpdatedByRemote,"Call updated by remote");
}
/*accept the modification (sends a 200Ok)*/
sal_call_accept(op);
@ -501,6 +506,13 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de
}
}
static void call_released(SalOp *op){
LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
if (call!=NULL){
linphone_call_set_state(call,LinphoneCallReleased,"Call released");
}else ms_error("call_released() for already destroyed call ?");
}
static void auth_requested(SalOp *h, const char *realm, const char *username){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h));
LinphoneAuthInfo *ai=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,realm,username);
@ -516,7 +528,7 @@ static void auth_requested(SalOp *h, const char *realm, const char *username){
ai->usecount++;
}else{
if (ai && ai->works==FALSE) {
register_failure(h, SalErrorFailure, SalReasonForbidden, _("Authentication failure"));
sal_op_cancel_authentication(h);
}
if (lc->vtable.auth_info_requested)
lc->vtable.auth_info_requested(lc,realm,username);
@ -676,6 +688,7 @@ SalCallbacks linphone_sal_callbacks={
call_updating,
call_terminated,
call_failure,
call_released,
auth_requested,
auth_success,
register_success,

179
coreapi/ec-calibrator.c Normal file
View file

@ -0,0 +1,179 @@
/*
linphone
Copyright (C) 2011 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 "private.h"
#include "mediastreamer2/mstonedetector.h"
#include "mediastreamer2/dtmfgen.h"
static void ecc_init_filters(EcCalibrator *ecc){
ecc->ticker=ms_ticker_new();
ecc->sndread=ms_snd_card_create_reader(ecc->play_card);
ecc->det=ms_filter_new(MS_TONE_DETECTOR_ID);
ecc->rec=ms_filter_new(MS_FILE_REC_ID);
ms_filter_link(ecc->sndread,0,ecc->det,0);
ms_filter_link(ecc->det,0,ecc->rec,0);
ecc->play=ms_filter_new(MS_FILE_PLAYER_ID);
ecc->gen=ms_filter_new(MS_DTMF_GEN_ID);
ecc->resampler=ms_filter_new(MS_RESAMPLE_ID);
ecc->sndwrite=ms_snd_card_create_writer(ecc->capt_card);
ms_filter_link(ecc->play,0,ecc->gen,0);
ms_filter_link(ecc->gen,0,ecc->resampler,0);
ms_filter_link(ecc->resampler,0,ecc->sndwrite,0);
unsigned int rate;
ms_filter_call_method(ecc->sndwrite,MS_FILTER_GET_SAMPLE_RATE,&rate);
ms_filter_call_method(ecc->resampler,MS_FILTER_SET_OUTPUT_SAMPLE_RATE,&rate);
ms_ticker_attach(ecc->ticker,ecc->play);
ms_ticker_attach(ecc->ticker,ecc->sndread);
}
static void ecc_deinit_filters(EcCalibrator *ecc){
ms_ticker_detach(ecc->ticker,ecc->play);
ms_ticker_detach(ecc->ticker,ecc->sndread);
ms_filter_unlink(ecc->play,0,ecc->gen,0);
ms_filter_unlink(ecc->gen,0,ecc->resampler,0);
ms_filter_unlink(ecc->resampler,0,ecc->sndwrite,0);
ms_filter_unlink(ecc->sndread,0,ecc->det,0);
ms_filter_unlink(ecc->det,0,ecc->rec,0);
ms_filter_destroy(ecc->sndread);
ms_filter_destroy(ecc->det);
ms_filter_destroy(ecc->rec);
ms_filter_destroy(ecc->play);
ms_filter_destroy(ecc->gen);
ms_filter_destroy(ecc->resampler);
ms_filter_destroy(ecc->sndwrite);
ms_ticker_destroy(ecc->ticker);
}
static void on_tone_sent(void *data, MSFilter *f, unsigned int event_id, void *arg){
MSDtmfGenEvent *ev=(MSDtmfGenEvent*)arg;
EcCalibrator *ecc=(EcCalibrator*)data;
ecc->sent_count++;
ecc->acc-=ev->tone_start_time;
ms_message("Sent tone at %u",(unsigned int)ev->tone_start_time);
}
static void on_tone_received(void *data, MSFilter *f, unsigned int event_id, void *arg){
MSToneDetectorEvent *ev=(MSToneDetectorEvent*)arg;
EcCalibrator *ecc=(EcCalibrator*)data;
ecc->recv_count++;
ecc->acc+=ev->tone_start_time;
ms_message("Received tone at %u",(unsigned int)ev->tone_start_time);
}
static void ecc_play_tones(EcCalibrator *ecc){
MSDtmfGenCustomTone tone;
MSToneDetectorDef expected_tone;
ms_filter_set_notify_callback(ecc->det,on_tone_received,ecc);
expected_tone.frequency=2000;
expected_tone.min_duration=40;
expected_tone.min_amplitude=0.02;
ms_filter_call_method (ecc->det,MS_TONE_DETECTOR_ADD_SCAN,&expected_tone);
tone.frequency=1000;
tone.duration=1000;
tone.amplitude=1.0;
/*play an initial tone to startup the audio playback/capture*/
ms_filter_call_method(ecc->gen,MS_DTMF_GEN_PLAY_CUSTOM,&tone);
ms_sleep(2);
ms_filter_set_notify_callback(ecc->gen,on_tone_sent,ecc);
tone.frequency=2000;
tone.duration=100;
ms_filter_call_method(ecc->gen,MS_DTMF_GEN_PLAY_CUSTOM,&tone);
ms_sleep(1);
ms_filter_call_method(ecc->gen,MS_DTMF_GEN_PLAY_CUSTOM,&tone);
ms_sleep(1);
ms_filter_call_method(ecc->gen,MS_DTMF_GEN_PLAY_CUSTOM,&tone);
ms_sleep(1);
if (ecc->sent_count==3 && ecc->recv_count==3){
int delay=ecc->acc/3;
if (delay<0){
ms_error("Quite surprising calibration result, delay=%i",delay);
ecc->status=LinphoneEcCalibratorFailed;
}else{ms_message("Echo calibration estimated delay to be %i ms",delay);
ecc->delay=delay;
ecc->status=LinphoneEcCalibratorDone;
}
}else{
ms_error("Echo calibration failed, tones received = %i",ecc->recv_count);
ecc->status=LinphoneEcCalibratorFailed;
}
}
static void * ecc_thread(void *p){
EcCalibrator *ecc=(EcCalibrator*)p;
ecc_init_filters(ecc);
ecc_play_tones(ecc);
ecc_deinit_filters(ecc);
ms_thread_exit(NULL);
return NULL;
}
EcCalibrator * ec_calibrator_new(MSSndCard *play_card, MSSndCard *capt_card, LinphoneEcCalibrationCallback cb, void *cb_data ){
EcCalibrator *ecc=ms_new0(EcCalibrator,1);
ecc->cb=cb;
ecc->cb_data=cb_data;
ecc->capt_card=capt_card;
ecc->play_card=play_card;
ms_thread_create(&ecc->thread,NULL,ecc_thread,ecc);
return ecc;
}
LinphoneEcCalibratorStatus ec_calibrator_get_status(EcCalibrator *ecc){
return ecc->status;
}
void ec_calibrator_destroy(EcCalibrator *ecc){
ms_thread_join(ecc->thread,NULL);
ms_free(ecc);
}
int linphone_core_start_echo_calibration(LinphoneCore *lc, LinphoneEcCalibrationCallback cb, void *cb_data){
if (lc->ecc!=NULL){
ms_error("Echo calibration is still on going !");
return -1;
}
lc->ecc=ec_calibrator_new(lc->sound_conf.play_sndcard,lc->sound_conf.capt_sndcard,cb,cb_data);
return 0;
}

View file

@ -277,7 +277,9 @@ SalPresenceStatus linphone_online_status_to_sal(LinphoneOnlineStatus os){
}
void linphone_friend_notify(LinphoneFriend *lf, LinphoneOnlineStatus os){
//printf("Wish to notify %p, lf->nid=%i\n",lf,lf->nid);
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,linphone_online_status_to_sal(os),NULL);
}
@ -286,8 +288,6 @@ void linphone_friend_notify(LinphoneFriend *lf, LinphoneOnlineStatus os){
static void linphone_friend_unsubscribe(LinphoneFriend *lf){
if (lf->outsub!=NULL) {
sal_unsubscribe(lf->outsub);
sal_op_release(lf->outsub);
lf->outsub=NULL;
lf->subscribe_active=FALSE;
}
}
@ -296,13 +296,19 @@ void linphone_friend_close_subscriptions(LinphoneFriend *lf){
linphone_friend_unsubscribe(lf);
if (lf->insub){
sal_notify_close(lf->insub);
sal_op_release(lf->insub);
lf->insub=NULL;
}
}
void linphone_friend_destroy(LinphoneFriend *lf){
if (lf->insub) {
sal_op_release(lf->insub);
lf->insub=NULL;
}
if (lf->outsub){
sal_op_release(lf->outsub);
lf->outsub=NULL;
}
if (lf->uri!=NULL) linphone_address_destroy(lf->uri);
if (lf->info!=NULL) buddy_info_free(lf->info);
ms_free(lf);

View file

@ -34,6 +34,13 @@
/**
* @defgroup call_control Placing and receiving calls
*
* The #LinphoneCall object represents an incoming or outgoing call managed by the #LinphoneCore.
* Outgoing calls can be created using linphone_core_invite() or linphone_core_invite_address(), while incoming calls are notified to the application
* through the LinphoneCoreVTable::call_state_changed callback.
*
* See the basic call \ref basic_call_tutorials "tutorial".
*
**/
/**

View file

@ -22,6 +22,7 @@ import org.linphone.core.LinphoneAddress;
import org.linphone.core.LinphoneCall;
import org.linphone.core.LinphoneChatRoom;
import org.linphone.core.LinphoneCore;
import org.linphone.core.LinphoneCore.EcCalibratorStatus;
import org.linphone.core.LinphoneCoreException;
import org.linphone.core.LinphoneCoreFactory;
import org.linphone.core.LinphoneCoreListener;
@ -95,7 +96,7 @@ public class TutorialBuddyStatus implements LinphoneCoreListener {
public void globalState(LinphoneCore lc, GlobalState state, String message) {}
public void textReceived(LinphoneCore lc, LinphoneChatRoom cr,LinphoneAddress from, String message) {}
public void callState(LinphoneCore lc, LinphoneCall call, State cstate, String msg) {}
public void ecCalibrationStatus(LinphoneCore lc, EcCalibratorStatus status,int delay_ms, Object data) {}
@ -229,4 +230,6 @@ public class TutorialBuddyStatus implements LinphoneCoreListener {
TutorialNotifier.notify(s);
}
}

View file

@ -22,6 +22,7 @@ import org.linphone.core.LinphoneAddress;
import org.linphone.core.LinphoneCall;
import org.linphone.core.LinphoneChatRoom;
import org.linphone.core.LinphoneCore;
import org.linphone.core.LinphoneCore.EcCalibratorStatus;
import org.linphone.core.LinphoneCoreException;
import org.linphone.core.LinphoneCoreFactory;
import org.linphone.core.LinphoneCoreListener;
@ -73,7 +74,7 @@ public class TutorialChatRoom implements LinphoneCoreListener {
public void newSubscriptionRequest(LinphoneCore lc, LinphoneFriend lf,String url) {}
public void notifyPresenceReceived(LinphoneCore lc, LinphoneFriend lf) {}
public void callState(LinphoneCore lc, LinphoneCall call, State cstate, String msg){}
public void ecCalibrationStatus(LinphoneCore lc, EcCalibratorStatus status,int delay_ms, Object data) {}
public void textReceived(LinphoneCore lc, LinphoneChatRoom cr,LinphoneAddress from, String message) {
@ -144,4 +145,5 @@ public class TutorialChatRoom implements LinphoneCoreListener {
TutorialNotifier.notify(s);
}
}

View file

@ -22,6 +22,7 @@ import org.linphone.core.LinphoneAddress;
import org.linphone.core.LinphoneCall;
import org.linphone.core.LinphoneChatRoom;
import org.linphone.core.LinphoneCore;
import org.linphone.core.LinphoneCore.EcCalibratorStatus;
import org.linphone.core.LinphoneCoreException;
import org.linphone.core.LinphoneCoreFactory;
import org.linphone.core.LinphoneCoreListener;
@ -67,7 +68,7 @@ public class TutorialHelloWorld implements LinphoneCoreListener {
public void newSubscriptionRequest(LinphoneCore lc, LinphoneFriend lf,String url) {}
public void notifyPresenceReceived(LinphoneCore lc, LinphoneFriend lf) {}
public void textReceived(LinphoneCore lc, LinphoneChatRoom cr,LinphoneAddress from, String message) {}
public void ecCalibrationStatus(LinphoneCore lc, EcCalibratorStatus status,int delay_ms, Object data) {}
/*
* Call state notification listener
*/
@ -153,4 +154,5 @@ public class TutorialHelloWorld implements LinphoneCoreListener {
TutorialNotifier.notify(s);
}
}

View file

@ -22,6 +22,7 @@ import org.linphone.core.LinphoneAddress;
import org.linphone.core.LinphoneCall;
import org.linphone.core.LinphoneChatRoom;
import org.linphone.core.LinphoneCore;
import org.linphone.core.LinphoneCore.EcCalibratorStatus;
import org.linphone.core.LinphoneCoreException;
import org.linphone.core.LinphoneCoreFactory;
import org.linphone.core.LinphoneCoreListener;
@ -78,7 +79,7 @@ public class TutorialRegistration implements LinphoneCoreListener {
public void notifyPresenceReceived(LinphoneCore lc, LinphoneFriend lf) {}
public void textReceived(LinphoneCore lc, LinphoneChatRoom cr,LinphoneAddress from, String message) {}
public void callState(LinphoneCore lc, LinphoneCall call, State cstate, String msg) {}
public void ecCalibrationStatus(LinphoneCore lc, EcCalibratorStatus status,int delay_ms, Object data) {}
public static void main(String[] args) {
// Check tutorial was called with the right number of arguments
@ -184,4 +185,6 @@ public class TutorialRegistration implements LinphoneCoreListener {
TutorialNotifier.notify(s);
}
}

View file

@ -32,6 +32,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "mediastreamer2/msequalizer.h"
#include "mediastreamer2/msfileplayer.h"
#include "mediastreamer2/msjpegwriter.h"
#include "mediastreamer2/mseventqueue.h"
#ifdef VIDEO_ENABLED
static MSWebCam *get_nowebcam_device(){
@ -58,7 +59,7 @@ static MSList *make_codec_list(LinphoneCore *lc, const MSList *codecs, int bandw
return l;
}
SalMediaDescription *create_local_media_description(LinphoneCore *lc, LinphoneCall *call){
static SalMediaDescription *_create_local_media_description(LinphoneCore *lc, LinphoneCall *call, unsigned int session_id, unsigned int session_ver){
MSList *l;
PayloadType *pt;
const char *me=linphone_core_get_identity(lc);
@ -66,6 +67,8 @@ SalMediaDescription *create_local_media_description(LinphoneCore *lc, LinphoneCa
const char *username=linphone_address_get_username (addr);
SalMediaDescription *md=sal_media_description_new();
md->session_id=session_id;
md->session_ver=session_ver;
md->nstreams=1;
strncpy(md->addr,call->localip,sizeof(md->addr));
strncpy(md->username,username,sizeof(md->username));
@ -95,6 +98,22 @@ SalMediaDescription *create_local_media_description(LinphoneCore *lc, LinphoneCa
return md;
}
void update_local_media_description(LinphoneCore *lc, LinphoneCall *call, SalMediaDescription **md){
if (*md == NULL) {
*md = _create_local_media_description(lc,call,0,0);
} else {
unsigned int id = (*md)->session_id;
unsigned int ver = (*md)->session_ver+1;
sal_media_description_unref(*md);
*md = _create_local_media_description(lc,call,id,ver);
}
}
SalMediaDescription *create_local_media_description(LinphoneCore *lc, LinphoneCall *call){
unsigned int id=rand();
return _create_local_media_description(lc,call,id,id);
}
static int find_port_offset(LinphoneCore *lc){
int offset;
MSList *elem;
@ -126,6 +145,7 @@ static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from,
call->start_time=time(NULL);
call->media_start_time=0;
call->log=linphone_call_log_new(call, from, to);
call->owns_call_log=TRUE;
linphone_core_notify_all_friends(call->core,LinphoneStatusOnThePhone);
port_offset=find_port_offset (call->core);
if (port_offset==-1) return;
@ -222,8 +242,10 @@ static void linphone_call_set_terminated(LinphoneCall *call){
else status=LinphoneCallSuccess;
}
call->owns_call_log=FALSE;
linphone_call_log_completed(call->log,call, status);
if (call == lc->current_call){
ms_message("Resetting the current call");
lc->current_call=NULL;
@ -236,13 +258,6 @@ static void linphone_call_set_terminated(LinphoneCall *call){
if (ms_list_size(lc->calls)==0)
linphone_core_notify_all_friends(lc,lc->presence_mode);
if (call->op!=NULL) {
/* so that we cannot have anymore upcalls for SAL
concerning this call*/
sal_op_release(call->op);
call->op=NULL;
}
linphone_call_unref(call);
}
const char *linphone_call_state_to_string(LinphoneCallState cs){
@ -283,14 +298,23 @@ const char *linphone_call_state_to_string(LinphoneCallState cs){
return "LinphoneCallIncomingEarlyMedia";
case LinphoneCallUpdated:
return "LinphoneCallUpdated";
case LinphoneCallReleased:
return "LinphoneCallReleased";
}
return "undefined state";
}
void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const char *message){
LinphoneCore *lc=call->core;
bool_t finalize_call=FALSE;
if (call->state!=cstate){
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),
linphone_call_state_to_string(cstate));
return;
}
}
ms_message("Call %p: moving from state %s to %s",call,linphone_call_state_to_string(call->state),
linphone_call_state_to_string(cstate));
if (cstate!=LinphoneCallRefered){
@ -299,14 +323,20 @@ void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const
call->state=cstate;
}
if (cstate==LinphoneCallEnd || cstate==LinphoneCallError){
finalize_call=TRUE;
linphone_call_ref(call);
linphone_call_set_terminated (call);
}
if (lc->vtable.call_state_changed)
lc->vtable.call_state_changed(lc,call,cstate,message);
if (finalize_call)
if (cstate==LinphoneCallReleased){
if (call->op!=NULL) {
/* so that we cannot have anymore upcalls for SAL
concerning this call*/
sal_op_release(call->op);
call->op=NULL;
}
linphone_call_unref(call);
}
}
}
@ -330,6 +360,8 @@ static void linphone_call_destroy(LinphoneCall *obj)
if (obj->refer_to){
ms_free(obj->refer_to);
}
if (obj->owns_call_log)
linphone_call_log_destroy(obj->log);
ms_free(obj);
}
@ -473,6 +505,20 @@ int linphone_call_get_duration(const LinphoneCall *call){
return time(NULL)-call->media_start_time;
}
/**
* Returns the call object this call is replacing, if any.
* Call replacement can occur during call transfers.
* By default, the core automatically terminates the replaced call and accept the new one.
* This function allows the application to know whether a new incoming call is a one that replaces another one.
**/
LinphoneCall *linphone_call_get_replaced_call(LinphoneCall *call){
SalOp *op=sal_call_get_replaces(call->op);
if (op){
return (LinphoneCall*)sal_op_get_user_pointer(op);
}
return NULL;
}
/**
* Indicate whether camera input should be sent to remote end.
**/
@ -505,21 +551,21 @@ int linphone_call_take_video_snapshot(LinphoneCall *call, const char *file){
}
/**
*
* Returns TRUE if camera pictures are sent to the remote party.
**/
bool_t linphone_call_camera_enabled (const LinphoneCall *call){
return call->camera_active;
}
/**
*
* Enable video stream.
**/
void linphone_call_params_enable_video(LinphoneCallParams *cp, bool_t enabled){
cp->has_video=enabled;
}
/**
*
* Returns whether video is enabled.
**/
bool_t linphone_call_params_video_enabled(const LinphoneCallParams *cp){
return cp->has_video;
@ -969,6 +1015,7 @@ void linphone_call_stop_media_streams(LinphoneCall *call){
video_stream_stop(call->videostream);
call->videostream=NULL;
}
ms_event_queue_skip(call->core->msevq);
#endif
if (call->audio_profile){

View file

@ -49,6 +49,8 @@ static void toggle_video_preview(LinphoneCore *lc, bool_t val);
#define LOCAL_RING "rings/oldphone.wav"
/* same for remote ring (ringback)*/
#define REMOTE_RING "ringback.wav"
#define HOLD_MUSIC "rings/toy-mono.wav"
extern SalCallbacks linphone_sal_callbacks;
@ -452,6 +454,8 @@ static void sound_config_read(LinphoneCore *lc)
tmpbuf=PACKAGE_SOUND_DIR "/" REMOTE_RING;
}
linphone_core_set_ringback(lc,tmpbuf);
linphone_core_set_play_file(lc,lp_config_get_string(lc->config,"sound","hold_music",PACKAGE_SOUND_DIR "/" HOLD_MUSIC));
check_sound_device(lc);
lc->sound_conf.latency=0;
@ -571,6 +575,7 @@ static void sip_config_read(LinphoneCore *lc)
lc->sip_conf.keepalive_period=lp_config_get_int(lc->config,"sip","keepalive_period",10000);
sal_set_keepalive_period(lc->sal,lc->sip_conf.keepalive_period);
sal_use_one_matching_codec_policy(lc->sal,lp_config_get_int(lc->config,"sip","only_one_codec",0));
sal_use_double_registrations(lc->sal,lp_config_get_int(lc->config,"sip","use_double_registrations",1));
}
static void rtp_config_read(LinphoneCore *lc)
@ -590,6 +595,8 @@ static void rtp_config_read(LinphoneCore *lc)
jitt_comp=lp_config_get_int(lc->config,"rtp","audio_jitt_comp",60);
linphone_core_set_audio_jittcomp(lc,jitt_comp);
jitt_comp=lp_config_get_int(lc->config,"rtp","video_jitt_comp",60);
if (jitt_comp==0) jitt_comp=60;
lc->rtp_conf.video_jitt_comp=jitt_comp;
nortp_timeout=lp_config_get_int(lc->config,"rtp","nortp_timeout",30);
linphone_core_set_nortp_timeout(lc,nortp_timeout);
rtp_no_xmit_on_audio_mute=lp_config_get_int(lc->config,"rtp","rtp_no_xmit_on_audio_mute",FALSE);
@ -910,7 +917,8 @@ static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vta
{
memset (lc, 0, sizeof (LinphoneCore));
lc->data=userdata;
lc->ringstream_autorelease=TRUE;
memcpy(&lc->vtable,vtable,sizeof(LinphoneCoreVTable));
linphone_core_set_state(lc,LinphoneGlobalStartup,"Starting up");
@ -1635,6 +1643,19 @@ void linphone_core_iterate(LinphoneCore *lc){
one_second_elapsed=TRUE;
}
if (lc->ecc!=NULL){
LinphoneEcCalibratorStatus ecs=ec_calibrator_get_status(lc->ecc);
if (ecs!=LinphoneEcCalibratorInProgress){
if (lc->ecc->cb)
lc->ecc->cb(lc,ecs,lc->ecc->delay,lc->ecc->cb_data);
if (ecs==LinphoneEcCalibratorDone){
lp_config_set_int(lc->config, "sound", "ec_delay",MAX(lc->ecc->delay-10,0));
}
ec_calibrator_destroy(lc->ecc);
lc->ecc=NULL;
}
}
if (lc->preview_finished){
lc->preview_finished=0;
ring_stop(lc->ringstream);
@ -1642,7 +1663,7 @@ void linphone_core_iterate(LinphoneCore *lc){
lc_callback_obj_invoke(&lc->preview_finished_cb,lc);
}
if (lc->ringstream && lc->dmfs_playing_start_time!=0
if (lc->ringstream && lc->ringstream_autorelease && lc->dmfs_playing_start_time!=0
&& (curtime-lc->dmfs_playing_start_time)>5){
ring_stop(lc->ringstream);
lc->ringstream=NULL;
@ -2176,15 +2197,13 @@ bool_t linphone_core_inc_invite_pending(LinphoneCore*lc){
int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params){
int err=0;
if (params!=NULL){
if (call->localdesc)
sal_media_description_unref(call->localdesc);
call->params=*params;
call->localdesc=create_local_media_description (lc,call);
update_local_media_description(lc,call,&call->localdesc);
call->camera_active=params->has_video;
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);
err=sal_call_update(call->op,"Media parameters update");
}else{
#ifdef VIDEO_ENABLED
if (call->videostream!=NULL){
@ -2411,13 +2430,23 @@ LinphoneCall *linphone_core_get_current_call(const LinphoneCore *lc)
int linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *the_call)
{
LinphoneCall *call = the_call;
const char *subject=NULL;
if (call->state!=LinphoneCallStreamsRunning && call->state!=LinphoneCallPausedByRemote){
ms_warning("Cannot pause this call, it is not active.");
return -1;
}
if (sal_call_hold(call->op,TRUE) != 0)
if (sal_media_description_has_dir(call->resultdesc,SalStreamSendRecv)){
sal_media_description_set_dir(call->localdesc,SalStreamSendOnly);
subject="Call on hold";
}else if (sal_media_description_has_dir(call->resultdesc,SalStreamRecvOnly)){
sal_media_description_set_dir(call->localdesc,SalStreamSendOnly);
subject="Call on hold for me too";
}else{
ms_error("No reason to pause this call, it is already paused or inactive.");
return -1;
}
if (sal_call_update(call->op,subject) != 0)
{
if (lc->vtable.display_warning)
lc->vtable.display_warning(lc,_("Could not pause the call"));
@ -2467,14 +2496,14 @@ int linphone_core_resume_call(LinphoneCore *lc, LinphoneCall *the_call)
return -1;
}
ms_message("Resuming call %p",call);
if(sal_call_hold(call->op,FALSE) != 0){
sal_media_description_set_dir(call->localdesc,SalStreamSendRecv);
if(sal_call_update(call->op,"Call resuming") != 0){
return -1;
}
linphone_call_set_state (call,LinphoneCallResuming,"Resuming");
snprintf(temp,sizeof(temp)-1,"Resuming the call with %s",linphone_call_get_remote_address_as_string(call));
if (lc->vtable.display_status)
lc->vtable.display_status(lc,temp);
lc->current_call=call;
return 0;
}
@ -2687,6 +2716,7 @@ static MSSndCard *get_card_from_string_id(const char *devid, unsigned int cap){
* Returns true if the specified sound device can capture sound.
*
* @ingroup media_parameters
* @param lc The LinphoneCore object
* @param devid the device name as returned by linphone_core_get_sound_devices()
**/
bool_t linphone_core_sound_device_can_capture(LinphoneCore *lc, const char *devid){
@ -2700,6 +2730,7 @@ bool_t linphone_core_sound_device_can_capture(LinphoneCore *lc, const char *devi
* Returns true if the specified sound device can play sound.
*
* @ingroup media_parameters
* @param lc The LinphoneCore object
* @param devid the device name as returned by linphone_core_get_sound_devices()
**/
bool_t linphone_core_sound_device_can_playback(LinphoneCore *lc, const char *devid){
@ -2713,6 +2744,7 @@ bool_t linphone_core_sound_device_can_playback(LinphoneCore *lc, const char *dev
* Sets the sound device used for ringing.
*
* @ingroup media_parameters
* @param lc The LinphoneCore object
* @param devid the device name as returned by linphone_core_get_sound_devices()
**/
int linphone_core_set_ringer_device(LinphoneCore *lc, const char * devid){
@ -2727,6 +2759,7 @@ int linphone_core_set_ringer_device(LinphoneCore *lc, const char * devid){
* Sets the sound device used for playback.
*
* @ingroup media_parameters
* @param lc The LinphoneCore object
* @param devid the device name as returned by linphone_core_get_sound_devices()
**/
int linphone_core_set_playback_device(LinphoneCore *lc, const char * devid){
@ -2741,6 +2774,7 @@ int linphone_core_set_playback_device(LinphoneCore *lc, const char * devid){
* Sets the sound device used for capture.
*
* @ingroup media_parameters
* @param lc The LinphoneCore object
* @param devid the device name as returned by linphone_core_get_sound_devices()
**/
int linphone_core_set_capture_device(LinphoneCore *lc, const char * devid){
@ -2755,6 +2789,7 @@ int linphone_core_set_capture_device(LinphoneCore *lc, const char * devid){
* Returns the name of the currently assigned sound device for ringing.
*
* @ingroup media_parameters
* @param lc The LinphoneCore object
**/
const char * linphone_core_get_ringer_device(LinphoneCore *lc)
{
@ -2766,6 +2801,7 @@ const char * linphone_core_get_ringer_device(LinphoneCore *lc)
* Returns the name of the currently assigned sound device for playback.
*
* @ingroup media_parameters
* @param lc The LinphoneCore object
**/
const char * linphone_core_get_playback_device(LinphoneCore *lc)
{
@ -2776,6 +2812,7 @@ const char * linphone_core_get_playback_device(LinphoneCore *lc)
* Returns the name of the currently assigned sound device for capture.
*
* @ingroup media_parameters
* @param lc The LinphoneCore object
**/
const char * linphone_core_get_capture_device(LinphoneCore *lc)
{
@ -2785,8 +2822,10 @@ const char * linphone_core_get_capture_device(LinphoneCore *lc)
/**
* Returns an unmodifiable array of available sound devices.
*
* @ingroup media_parameters
* The array is NULL terminated.
*
* @ingroup media_parameters
* @param lc The LinphoneCore object
**/
const char** linphone_core_get_sound_devices(LinphoneCore *lc){
build_sound_devices_table(lc);
@ -2829,14 +2868,17 @@ void linphone_core_set_sound_source(LinphoneCore *lc, char source)
* Sets the path to a wav file used for ringing.
*
* @param path The file must be a wav 16bit linear. Local ring is disabled if null
* @param lc The LinphoneCore object
*
* @ingroup media_parameters
**/
void linphone_core_set_ring(LinphoneCore *lc,const char *path){
if (lc->sound_conf.local_ring!=0){
ms_free(lc->sound_conf.local_ring);
lc->sound_conf.local_ring=NULL;
}
lc->sound_conf.local_ring=ms_strdup(path);
if (path)
lc->sound_conf.local_ring=ms_strdup(path);
if ( linphone_core_ready(lc) && lc->sound_conf.local_ring)
lp_config_set_string(lc->config,"sound","local_ring",lc->sound_conf.local_ring);
}
@ -2844,6 +2886,7 @@ void linphone_core_set_ring(LinphoneCore *lc,const char *path){
/**
* Returns the path to the wav file used for ringing.
*
* @param lc The LinphoneCore object
* @ingroup media_parameters
**/
const char *linphone_core_get_ring(const LinphoneCore *lc){
@ -3112,6 +3155,7 @@ static void toggle_video_preview(LinphoneCore *lc, bool_t val){
* initiate future calls with video or not. The two boolean parameters indicate in which
* direction video is enabled. Setting both to false disables video entirely.
*
* @param lc The LinphoneCore object
* @param vcap_enabled indicates whether video capture is enabled
* @param display_enabled indicates whether video display should be shown
*
@ -3191,6 +3235,7 @@ bool_t linphone_core_self_view_enabled(const LinphoneCore *lc){
* Sets the active video device.
*
* @ingroup media_parameters
* @param lc The LinphoneCore object
* @param id the name of the video device as returned by linphone_core_get_video_devices()
**/
int linphone_core_set_video_device(LinphoneCore *lc, const char *id){
@ -3220,6 +3265,7 @@ int linphone_core_set_video_device(LinphoneCore *lc, const char *id){
/**
* Returns the name of the currently active video device.
*
* @param lc The LinphoneCore object
* @ingroup media_parameters
**/
const char *linphone_core_get_video_device(const LinphoneCore *lc){
@ -3371,6 +3417,10 @@ void linphone_core_use_preview_window(LinphoneCore *lc, bool_t yesno){
}
static MSVideoSizeDef supported_resolutions[]={
#ifdef ENABLE_HD
{ {MS_VIDEO_SIZE_1080P_W,MS_VIDEO_SIZE_1080P_H} , "1080p" },
{ {MS_VIDEO_SIZE_720P_W,MS_VIDEO_SIZE_720P_H} , "1080p" },
#endif
{ {MS_VIDEO_SIZE_SVGA_W,MS_VIDEO_SIZE_SVGA_H} , "svga" },
{ {MS_VIDEO_SIZE_4CIF_W,MS_VIDEO_SIZE_4CIF_H} , "4cif" },
{ {MS_VIDEO_SIZE_VGA_W,MS_VIDEO_SIZE_VGA_H} , "vga" },
@ -3519,8 +3569,10 @@ static MSFilter *get_dtmf_gen(LinphoneCore *lc){
}
}
if (lc->ringstream==NULL){
float amp=0.1;
MSSndCard *ringcard=lc->sound_conf.lsd_card ?lc->sound_conf.lsd_card : lc->sound_conf.ring_sndcard;
lc->ringstream=ring_start(NULL,0,ringcard);
ms_filter_call_method(lc->ringstream->gendtmf,MS_DTMF_GEN_SET_DEFAULT_AMPLITUDE,&amp);
lc->dmfs_playing_start_time=time(NULL);
}else{
if (lc->dmfs_playing_start_time!=0)
@ -3688,7 +3740,7 @@ void sip_config_uninit(LinphoneCore *lc)
linphone_proxy_config_write_to_config_file(lc->config,NULL,i);
for (i=0;i<20;i++){
linphone_core_iterate(lc);
sal_iterate(lc->sal);
#ifndef WIN32
usleep(100000);
#else
@ -3825,7 +3877,6 @@ static void linphone_core_uninit(LinphoneCore *lc)
usleep(50000);
#endif
}
if (lc->friends)
ms_list_for_each(lc->friends,(void (*)(void *))linphone_friend_close_subscriptions);
linphone_core_set_state(lc,LinphoneGlobalShutdown,"Shutting down");
@ -3839,12 +3890,13 @@ static void linphone_core_uninit(LinphoneCore *lc)
lc->msevq=NULL;
/* save all config */
net_config_uninit(lc);
sip_config_uninit(lc);
rtp_config_uninit(lc);
if (lc->ringstream) ring_stop(lc->ringstream);
sound_config_uninit(lc);
video_config_uninit(lc);
codecs_config_uninit(lc);
ui_config_uninit(lc);
sip_config_uninit(lc);
if (lp_config_needs_commit(lc->config)) lp_config_sync(lc->config);
lp_config_destroy(lc->config);
lc->config = NULL; /* Mark the config as NULL to block further calls */
@ -3854,7 +3906,6 @@ static void linphone_core_uninit(LinphoneCore *lc)
lc->call_logs=ms_list_free(lc->call_logs);
linphone_core_free_payload_types();
ortp_exit();
linphone_core_set_state(lc,LinphoneGlobalOff,"Off");
}
@ -3875,8 +3926,24 @@ static void set_network_reachable(LinphoneCore* lc,bool_t isReachable, time_t cu
}
lc->netup_time=curtime;
lc->network_reachable=isReachable;
}
if(!isReachable) {
sal_unlisten_ports (lc->sal);
} else {
apply_transports(lc);
}
}
void linphone_core_refresh_registers(LinphoneCore* lc) {
const MSList *elem=linphone_core_get_proxy_config_list(lc);
for(;elem!=NULL;elem=elem->next){
LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data;
if (linphone_proxy_config_register_enabled(cfg) ) {
cfg->registered=0;
cfg->commit=TRUE;
}
}
}
void linphone_core_set_network_reachable(LinphoneCore* lc,bool_t isReachable) {
//first disable automatic mode
if (lc->auto_net_state_mon) {
@ -4044,4 +4111,31 @@ const char *linphone_error_to_string(LinphoneReason err){
}
return "unknown error";
}
/**
* enable signaling keep alive
*/
void linphone_core_enable_keep_alive(LinphoneCore* lc,bool_t enable) {
if (enable > 0) {
sal_set_keepalive_period(lc->sal,lc->sip_conf.keepalive_period);
} else {
sal_set_keepalive_period(lc->sal,0);
}
}
/**
* Is signaling keep alive
*/
bool_t linphone_core_keep_alive_enabled(LinphoneCore* lc) {
return sal_get_keepalive_period(lc->sal) > 0;
}
void linphone_core_start_dtmf_stream(LinphoneCore* lc) {
get_dtmf_gen(lc); /*make sure ring stream is started*/
lc->ringstream_autorelease=FALSE; /*disable autorelease mode*/
}
void linphone_core_stop_dtmf_stream(LinphoneCore* lc) {
if (lc->ringstream) ring_stop(lc->ringstream);
lc->ringstream=NULL;
}

View file

@ -185,6 +185,7 @@ void linphone_call_params_destroy(LinphoneCallParams *cp);
/**
* Enum describing failure reasons.
* @ingroup initializing
**/
enum _LinphoneReason{
LinphoneReasonNone,
@ -203,8 +204,13 @@ const char *linphone_reason_to_string(LinphoneReason err);
struct _LinphoneCall;
typedef struct _LinphoneCall LinphoneCall;
/**
* LinphoneCallState enum represents the different state a call can reach into.
* The application is notified of state changes through the LinphoneCoreVTable::call_state_changed callback.
* @ingroup call_control
**/
typedef enum _LinphoneCallState{
LinphoneCallIdle,
LinphoneCallIdle, /**<Initial call state */
LinphoneCallIncomingReceived, /**<This is a new incoming call */
LinphoneCallOutgoingInit, /**<An outgoing call is started */
LinphoneCallOutgoingProgress, /**<An outgoing call is in progress */
@ -221,7 +227,8 @@ typedef enum _LinphoneCallState{
LinphoneCallPausedByRemote, /**<The call is paused by remote end*/
LinphoneCallUpdatedByRemote, /**<The call's parameters are updated, used for example when video is asked by remote */
LinphoneCallIncomingEarlyMedia, /**<We are proposing early media to an incoming call */
LinphoneCallUpdated /**<The remote accepted the call update initiated by us */
LinphoneCallUpdated, /**<The remote accepted the call update initiated by us */
LinphoneCallReleased /**< The call object is no more retained by the core */
} LinphoneCallState;
const char *linphone_call_state_to_string(LinphoneCallState cs);
@ -238,6 +245,7 @@ void linphone_call_unref(LinphoneCall *call);
LinphoneCallLog *linphone_call_get_call_log(const LinphoneCall *call);
const char *linphone_call_get_refer_to(const LinphoneCall *call);
bool_t linphone_call_has_transfer_pending(const LinphoneCall *call);
LinphoneCall *linphone_call_get_replaced_call(LinphoneCall *call);
int linphone_call_get_duration(const LinphoneCall *call);
const LinphoneCallParams * linphone_call_get_current_params(const LinphoneCall *call);
void linphone_call_enable_camera(LinphoneCall *lc, bool_t enabled);
@ -301,11 +309,11 @@ typedef struct _LinphoneProxyConfig LinphoneProxyConfig;
* LinphoneRegistrationState describes proxy registration states.
**/
typedef enum _LinphoneRegistrationState{
LinphoneRegistrationNone,
LinphoneRegistrationProgress,
LinphoneRegistrationOk,
LinphoneRegistrationCleared,
LinphoneRegistrationFailed
LinphoneRegistrationNone, /**<Initial state for registrations */
LinphoneRegistrationProgress, /**<Registration is in progress */
LinphoneRegistrationOk, /**< Registration is successful */
LinphoneRegistrationCleared, /**< Unregistration succeeded */
LinphoneRegistrationFailed /**<Registration failed */
}LinphoneRegistrationState;
/**
@ -484,6 +492,17 @@ void * linphone_chat_room_get_user_data(LinphoneChatRoom *cr);
/**
* @}
*/
/**
* @addtogroup initializing
* @{
**/
/**
* LinphoneGlobalState describes the global state of the LinphoneCore object.
* It is notified via the LinphoneCoreVTable::global_state_changed
**/
typedef enum _LinphoneGlobalState{
LinphoneGlobalOff,
LinphoneGlobalStartup,
@ -493,11 +512,6 @@ typedef enum _LinphoneGlobalState{
const char *linphone_global_state_to_string(LinphoneGlobalState gs);
/**
* @addtogroup initializing
* @{
**/
/**Call state notification callback prototype*/
typedef void (*LinphoneGlobalStateCb)(struct _LinphoneCore *lc, LinphoneGlobalState gstate, const char *message);
@ -919,6 +933,14 @@ void linphone_core_set_network_reachable(LinphoneCore* lc,bool_t value);
*/
bool_t linphone_core_is_network_reachabled(LinphoneCore* lc);
/**
* enable signaling keep alive. small udp packet sent periodically to keep udp NAT association
*/
void linphone_core_enable_keep_alive(LinphoneCore* lc,bool_t enable);
/**
* Is signaling keep alive
*/
bool_t linphone_core_keep_alive_enabled(LinphoneCore* lc);
void *linphone_core_get_user_data(LinphoneCore *lc);
@ -950,7 +972,11 @@ int linphone_core_get_current_call_stats(LinphoneCore *lc, rtp_stats_t *local, r
const MSList *linphone_core_get_calls(LinphoneCore *lc);
LinphoneGlobalState linphone_core_get_global_state(const LinphoneCore *lc);
/**
* force registration refresh to be initiated upon next iterate
* @ingroup proxies
*/
void linphone_core_refresh_registers(LinphoneCore* lc);
#ifdef __cplusplus
}
#endif

View file

@ -17,7 +17,8 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <jni.h>
#include "linphonecore.h"
#include "linphonecore_utils.h"
#include "mediastreamer2/msjava.h"
#ifdef ANDROID
@ -100,7 +101,10 @@ public:
callStateId = env->GetMethodID(listernerClass,"callState","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCall;Lorg/linphone/core/LinphoneCall$State;Ljava/lang/String;)V");
callStateClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneCall$State"));
callStateFromIntId = env->GetStaticMethodID(callStateClass,"fromInt","(I)Lorg/linphone/core/LinphoneCall$State;");
/*void ecCalibrationStatus(LinphoneCore.EcCalibratorStatus status, int delay_ms, Object data);*/
ecCalibrationStatusId = env->GetMethodID(listernerClass,"ecCalibrationStatus","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCore$EcCalibratorStatus;ILjava/lang/Object;)V");
ecCalibratorStatusClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneCore$EcCalibratorStatus"));
ecCalibratorStatusFromIntId = env->GetStaticMethodID(ecCalibratorStatusClass,"fromInt","(I)Lorg/linphone/core/LinphoneCore$EcCalibratorStatus;");
/*void newSubscriptionRequest(LinphoneCore lc, LinphoneFriend lf, String url)*/
newSubscriptionRequestId = env->GetMethodID(listernerClass,"newSubscriptionRequest","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneFriend;Ljava/lang/String;)V");
@ -165,6 +169,10 @@ public:
jmethodID callStateId;
jmethodID callStateFromIntId;
jclass ecCalibratorStatusClass;
jmethodID ecCalibrationStatusId;
jmethodID ecCalibratorStatusFromIntId;
jclass proxyClass;
jmethodID proxyCtrId;
@ -290,6 +298,26 @@ public:
,env->NewObject(lcData->addressClass,lcData->addressCtrId,(jlong)from)
,message ? env->NewStringUTF(message) : NULL);
}
static void ecCalibrationStatus(LinphoneCore *lc, LinphoneEcCalibratorStatus status, int delay_ms, void *data) {
JNIEnv *env = 0;
jint result = jvm->AttachCurrentThread(&env,NULL);
if (result != 0) {
ms_error("cannot attach VM\n");
return;
}
LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc);
env->CallVoidMethod(lcData->listener
,lcData->ecCalibrationStatusId
,lcData->core
,env->CallStaticObjectMethod(lcData->ecCalibratorStatusClass,lcData->ecCalibratorStatusFromIntId,(jint)status)
,delay_ms
,data ? data : NULL);
if (data != NULL &&status !=LinphoneEcCalibratorInProgress ) {
//final state, releasing global ref
env->DeleteGlobalRef((jobject)data);
}
}
};
@ -615,6 +643,29 @@ extern "C" jstring Java_org_linphone_core_LinphoneCoreImpl_getRing(JNIEnv* env
return NULL;
}
}
extern "C" void Java_org_linphone_core_LinphoneCoreImpl_enableKeepAlive(JNIEnv* env
,jobject thiz
,jlong lc
,jboolean enable) {
linphone_core_enable_keep_alive((LinphoneCore*)lc,enable);
}
extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_isKeepAliveEnabled(JNIEnv* env
,jobject thiz
,jlong lc) {
return linphone_core_keep_alive_enabled((LinphoneCore*)lc);
}
extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_startEchoCalibration(JNIEnv* env
,jobject thiz
,jlong lc
,jobject data) {
return linphone_core_start_echo_calibration((LinphoneCore*)lc
, LinphoneCoreData::ecCalibrationStatus
, data?env->NewGlobalRef(data):NULL);
}
//ProxyConfig
@ -939,6 +990,12 @@ extern "C" jboolean Java_org_linphone_core_LinphoneCallImpl_isEchoLimiterEnabled
return linphone_call_echo_limiter_enabled((LinphoneCall*)ptr);
}
extern "C" jlong Java_org_linphone_core_LinphoneCallImpl_getReplacedCall( JNIEnv* env
,jobject thiz
,jlong ptr) {
return (jlong)linphone_call_get_replaced_call((LinphoneCall*)ptr);
}
//LinphoneFriend
extern "C" long Java_org_linphone_core_LinphoneFriendImpl_newLinphoneFriend(JNIEnv* env

View file

@ -25,6 +25,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#else
#include "linphone/linphonecore.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
typedef struct _LsdPlayer LsdPlayer;
typedef struct _LinphoneSoundDaemon LinphoneSoundDaemon;
@ -49,4 +52,35 @@ void linphone_sound_daemon_release_all_players(LinphoneSoundDaemon *obj);
void linphone_core_use_sound_daemon(LinphoneCore *lc, LinphoneSoundDaemon *lsd);
void linphone_sound_daemon_destroy(LinphoneSoundDaemon *obj);
/**
* Enum describing the result of the echo canceller calibration process.
**/
typedef enum {
LinphoneEcCalibratorInProgress,
LinphoneEcCalibratorDone,
LinphoneEcCalibratorFailed
}LinphoneEcCalibratorStatus;
typedef void (*LinphoneEcCalibrationCallback)(LinphoneCore *lc, LinphoneEcCalibratorStatus status, int delay_ms, void *data);
/**
* Start an echo calibration of the sound devices, in order to find adequate settings for the echo canceller automatically.
**/
int linphone_core_start_echo_calibration(LinphoneCore *lc, LinphoneEcCalibrationCallback cb, void *cb_data);
#if TARGET_OS_IPHONE
/**
* IOS special function to warm up dtmf feeback stream. #linphone_core_stop_dtmf_stream must be called before entering BG mode
*/
void linphone_core_start_dtmf_stream(const LinphoneCore* lc);
/**
* IOS special function to stop dtmf feed back function. Must be called before entering BG mode
*/
void linphone_core_stop_dtmf_stream(const LinphoneCore* lc);
#endif
#ifdef __cplusplus
}
#endif
#endif

View file

@ -109,7 +109,7 @@ static MSList *match_payloads(const MSList *local, const MSList *remote, bool_t
static SalStreamDir compute_dir(SalStreamDir local, SalStreamDir answered){
static SalStreamDir compute_dir_outgoing(SalStreamDir local, SalStreamDir answered){
SalStreamDir res=local;
if (local==SalStreamSendRecv){
if (answered==SalStreamRecvOnly){
@ -124,6 +124,30 @@ static SalStreamDir compute_dir(SalStreamDir local, SalStreamDir answered){
return res;
}
static SalStreamDir compute_dir_incoming(SalStreamDir local, SalStreamDir offered){
SalStreamDir res=SalStreamSendRecv;
if (local==SalStreamSendRecv){
if (offered==SalStreamSendOnly)
res=SalStreamRecvOnly;
else if (offered==SalStreamRecvOnly)
res=SalStreamSendOnly;
else if (offered==SalStreamInactive)
res=SalStreamInactive;
else
res=SalStreamSendRecv;
}else if (local==SalStreamSendOnly){
if (offered==SalStreamRecvOnly || offered==SalStreamSendRecv)
res=SalStreamSendOnly;
else res=SalStreamInactive;
}else if (local==SalStreamRecvOnly){
if (offered==SalStreamSendOnly || offered==SalStreamSendRecv)
res=SalStreamRecvOnly;
else
res=SalStreamInactive;
}else res=SalStreamInactive;
return res;
}
static void initiate_outgoing(const SalStreamDescription *local_offer,
const SalStreamDescription *remote_answer,
SalStreamDescription *result){
@ -131,7 +155,7 @@ static void initiate_outgoing(const SalStreamDescription *local_offer,
result->payloads=match_payloads(local_offer->payloads,remote_answer->payloads,TRUE,FALSE);
result->proto=local_offer->proto;
result->type=local_offer->type;
result->dir=compute_dir(local_offer->dir,remote_answer->dir);
result->dir=compute_dir_outgoing(local_offer->dir,remote_answer->dir);
if (result->payloads && !only_telephone_event(result->payloads)){
strcpy(result->addr,remote_answer->addr);
@ -150,13 +174,7 @@ static void initiate_incoming(const SalStreamDescription *local_cap,
result->payloads=match_payloads(local_cap->payloads,remote_offer->payloads, FALSE, one_matching_codec);
result->proto=local_cap->proto;
result->type=local_cap->type;
if (remote_offer->dir==SalStreamSendOnly)
result->dir=SalStreamRecvOnly;
else if (remote_offer->dir==SalStreamRecvOnly){
result->dir=SalStreamSendOnly;
}else if (remote_offer->dir==SalStreamInactive){
result->dir=SalStreamInactive;
}else result->dir=SalStreamSendRecv;
result->dir=compute_dir_incoming(local_cap->dir,remote_offer->dir);
if (result->payloads && !only_telephone_event(result->payloads)){
strcpy(result->addr,local_cap->addr);
result->port=local_cap->port;
@ -200,22 +218,30 @@ int offer_answer_initiate_outgoing(const SalMediaDescription *local_offer,
int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities,
const SalMediaDescription *remote_offer,
SalMediaDescription *result, bool_t one_matching_codec){
int i,j;
int i;
const SalStreamDescription *ls,*rs;
for(i=0,j=0;i<remote_offer->nstreams;++i){
for(i=0;i<remote_offer->nstreams;++i){
rs=&remote_offer->streams[i];
ms_message("Processing for stream %i",i);
ls=sal_media_description_find_stream((SalMediaDescription*)local_capabilities,rs->proto,rs->type);
if (ls){
initiate_incoming(ls,rs,&result->streams[j],one_matching_codec);
++j;
initiate_incoming(ls,rs,&result->streams[i],one_matching_codec);
} else {
/* create an inactive stream for the answer, as there where no matching stream a local capability */
result->streams[i].dir=SalStreamInactive;
result->streams[i].port=0;
result->streams[i].type=rs->type;
if (rs->type==SalOther){
strncpy(result->streams[i].typeother,rs->typeother,sizeof(rs->typeother)-1);
}
}
}
result->nstreams=j;
result->nstreams=i;
strcpy(result->username, local_capabilities->username);
strcpy(result->addr,local_capabilities->addr);
result->bandwidth=local_capabilities->bandwidth;
result->session_ver=local_capabilities->session_ver;
result->session_id=local_capabilities->session_id;
return 0;
}

View file

@ -26,6 +26,7 @@
#define _PRIVATE_H
#include "linphonecore.h"
#include "linphonecore_utils.h"
#include "sal.h"
#ifdef HAVE_CONFIG_H
@ -97,6 +98,7 @@ struct _LinphoneCall
bool_t camera_active;
bool_t all_muted; /*this flag is set during early medias*/
bool_t playing_ringbacktone;
bool_t owns_call_log;
};
@ -424,6 +426,7 @@ struct _LinphoneCore
unsigned long video_window_id;
unsigned long preview_window_id;
time_t netup_time; /*time when network went reachable */
struct _EcCalibrator *ecc;
bool_t use_files;
bool_t apply_nat_settings;
bool_t initial_subscribes_sent;
@ -432,6 +435,7 @@ struct _LinphoneCore
bool_t auto_net_state_mon;
bool_t network_reachable;
bool_t use_preview_window;
bool_t ringstream_autorelease;
};
bool_t linphone_core_can_we_add_call(LinphoneCore *lc);
@ -443,6 +447,7 @@ 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);
void update_local_media_description(LinphoneCore *lc, LinphoneCall *call, SalMediaDescription **md);
void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMediaDescription *new_md);
@ -451,6 +456,27 @@ bool_t linphone_core_is_payload_type_usable_for_bandwidth(LinphoneCore *lc, Payl
#define linphone_core_ready(lc) ((lc)->state!=LinphoneGlobalStartup)
void _linphone_core_configure_resolver();
struct _EcCalibrator{
ms_thread_t thread;
MSSndCard *play_card,*capt_card;
MSFilter *sndread,*det,*rec;
MSFilter *play, *gen, *sndwrite,*resampler;
MSTicker *ticker;
LinphoneEcCalibrationCallback cb;
void *cb_data;
int recv_count;
int sent_count;
int64_t acc;
int delay;
LinphoneEcCalibratorStatus status;
};
typedef struct _EcCalibrator EcCalibrator;
LinphoneEcCalibratorStatus ec_calibrator_get_status(EcCalibrator *ecc);
void ec_calibrator_destroy(EcCalibrator *ecc);
#define HOLD_OFF (0)
#define HOLD_ON (1)

View file

@ -249,13 +249,14 @@ static char *guess_contact_for_register(LinphoneProxyConfig *obj){
if (host!=NULL){
LinphoneAddress *contact;
char localip[LINPHONE_IPADDR_SIZE];
LCSipTransports tr;
linphone_core_get_local_ip(obj->lc,host,localip);
contact=linphone_address_new(obj->reg_identity);
linphone_address_set_domain (contact,localip);
linphone_address_set_port_int(contact,linphone_core_get_sip_port(obj->lc));
linphone_address_set_display_name(contact,NULL);
LCSipTransports tr;
linphone_core_get_sip_transports(obj->lc,&tr);
if (tr.udp_port <= 0 && tr.tcp_port>0) {
sal_address_add_param(contact,"transport","tcp");

View file

@ -79,19 +79,41 @@ void sal_media_description_set_dir(SalMediaDescription *md, SalStreamDir stream_
}
}
bool_t sal_media_description_has_dir(const SalMediaDescription *md, SalStreamDir stream_dir){
static bool_t is_null_address(const char *addr){
return strcmp(addr,"0.0.0.0")==0 || strcmp(addr,"::0")==0;
}
/*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;
bool_t found=FALSE;
/* we are looking for at least one stream with requested direction, inactive streams are ignored*/
for(i=0;i<md->nstreams;++i){
const SalStreamDescription *ss=&md->streams[i];
if (ss->dir==stream_dir) found=TRUE;
else{
if (ss->dir!=SalStreamInactive) return FALSE;
}
if (ss->dir==stream_dir) return TRUE;
if (stream_dir==SalStreamSendOnly && (is_null_address(md->addr) || is_null_address(ss->addr)))
return TRUE;
}
return found;
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;
}else if (stream_dir==SalStreamSendOnly){
if (has_dir(md,SalStreamRecvOnly) || has_dir(md,SalStreamSendRecv)) return FALSE;
else return TRUE;
}else if (stream_dir==SalStreamSendRecv){
return has_dir(md,SalStreamSendRecv);
}else{
/*SalStreamInactive*/
if (has_dir(md,SalStreamSendOnly) || has_dir(md,SalStreamSendRecv) || has_dir(md,SalStreamRecvOnly))
return FALSE;
else return TRUE;
}
return FALSE;
}
/*
@ -128,7 +150,6 @@ static bool_t payload_list_equals(const MSList *l1, const MSList *l2){
}
if (e1!=NULL || e2!=NULL){
/*means one list is longer than the other*/
abort();
return FALSE;
}
return TRUE;

View file

@ -103,6 +103,7 @@ typedef struct SalEndpointCandidate{
typedef struct SalStreamDescription{
SalMediaProto proto;
SalStreamType type;
char typeother[32];
char addr[64];
int port;
MSList *payloads; //<list of PayloadType
@ -120,6 +121,8 @@ typedef struct SalMediaDescription{
char username[64];
int nstreams;
int bandwidth;
unsigned int session_ver;
unsigned int session_id;
SalStreamDescription streams[SAL_MEDIA_DESCRIPTION_MAX_STREAMS];
} SalMediaDescription;
@ -192,6 +195,7 @@ typedef void (*SalOnCallAck)(SalOp *op);
typedef void (*SalOnCallUpdating)(SalOp *op);/*< Called when a reINVITE is received*/
typedef void (*SalOnCallTerminated)(SalOp *op, const char *from);
typedef void (*SalOnCallFailure)(SalOp *op, SalError error, SalReason reason, const char *details, int code);
typedef void (*SalOnCallReleased)(SalOp *salop);
typedef void (*SalOnAuthRequested)(SalOp *op, const char *realm, const char *username);
typedef void (*SalOnAuthSuccess)(SalOp *op, const char *realm, const char *username);
typedef void (*SalOnRegisterSuccess)(SalOp *op, bool_t registered);
@ -215,6 +219,7 @@ typedef struct SalCallbacks{
SalOnCallUpdating call_updating;
SalOnCallTerminated call_terminated;
SalOnCallFailure call_failure;
SalOnCallReleased call_released;
SalOnAuthRequested auth_requested;
SalOnAuthSuccess auth_success;
SalOnRegisterSuccess register_success;
@ -249,7 +254,13 @@ ortp_socket_t sal_get_socket(Sal *ctx);
void sal_set_user_agent(Sal *ctx, const char *user_agent);
/*keepalive period in ms*/
void sal_set_keepalive_period(Sal *ctx,unsigned int value);
/**
* returns keepalive period in ms
* 0 desactiaved
* */
unsigned int sal_get_keepalive_period(Sal *ctx);
void sal_use_session_timers(Sal *ctx, int expires);
void sal_use_double_registrations(Sal *ctx, bool_t enabled);
void sal_use_one_matching_codec_policy(Sal *ctx, bool_t one_matching_codec);
int sal_iterate(Sal *sal);
MSList * sal_get_pending_auths(Sal *sal);
@ -265,6 +276,7 @@ void sal_op_set_from(SalOp *op, const char *from);
void sal_op_set_to(SalOp *op, const char *to);
void sal_op_release(SalOp *h);
void sal_op_authenticate(SalOp *h, const SalAuthInfo *info);
void sal_op_cancel_authentication(SalOp *h);
void sal_op_set_user_pointer(SalOp *h, void *up);
int sal_op_get_auth_requested(SalOp *h, const char **realm, const char **username);
const char *sal_op_get_from(const SalOp *op);
@ -285,8 +297,7 @@ 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);
int sal_call_update(SalOp *h, const char *subject);
SalMediaDescription * sal_call_get_final_media_description(SalOp *h);
int sal_call_refer(SalOp *h, const char *refer_to);
int sal_call_refer_with_replaces(SalOp *h, SalOp *other_call_h);

View file

@ -21,9 +21,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#endif
#include "sal_eXosip2.h"
#include "private.h"
#include "offeranswer.h"
static bool_t call_failure(Sal *sal, eXosip_event_t *ev);
static void text_received(Sal *sal, eXosip_event_t *ev);
void _osip_list_set_empty(osip_list_t *l, void (*freefunc)(void*)){
@ -264,6 +266,7 @@ Sal * sal_init(){
eXosip_init();
sal=ms_new0(Sal,1);
sal->keepalive_period=30;
sal->double_reg=TRUE;
return sal;
}
@ -296,6 +299,8 @@ void sal_set_callbacks(Sal *ctx, const SalCallbacks *cbs){
ctx->callbacks.call_failure=(SalOnCallFailure)unimplemented_stub;
if (ctx->callbacks.call_terminated==NULL)
ctx->callbacks.call_terminated=(SalOnCallTerminated)unimplemented_stub;
if (ctx->callbacks.call_released==NULL)
ctx->callbacks.call_released=(SalOnCallReleased)unimplemented_stub;
if (ctx->callbacks.call_updating==NULL)
ctx->callbacks.call_updating=(SalOnCallUpdating)unimplemented_stub;
if (ctx->callbacks.auth_requested==NULL)
@ -326,6 +331,7 @@ int sal_unlisten_ports(Sal *ctx){
if (ctx->running){
eXosip_quit();
eXosip_init();
ctx->running=FALSE;
}
return 0;
}
@ -334,13 +340,17 @@ int sal_listen_port(Sal *ctx, const char *addr, int port, SalTransport tr, int i
int err;
bool_t ipv6;
int proto=IPPROTO_UDP;
int keepalive = ctx->keepalive_period;
switch (tr) {
case SalTransportDatagram:
proto=IPPROTO_UDP;
eXosip_set_option (EXOSIP_OPT_UDP_KEEP_ALIVE, &keepalive);
break;
case SalTransportStream:
proto= IPPROTO_TCP;
keepalive=-1;
eXosip_set_option (EXOSIP_OPT_UDP_KEEP_ALIVE,&keepalive);
break;
default:
ms_warning("unexpected proto, using datagram");
@ -361,7 +371,7 @@ int sal_listen_port(Sal *ctx, const char *addr, int port, SalTransport tr, int i
#ifdef HAVE_EXOSIP_GET_SOCKET
ms_message("Exosip has socket number %i",eXosip_get_socket(proto));
#endif
eXosip_set_option (EXOSIP_OPT_UDP_KEEP_ALIVE, &ctx->keepalive_period);
ctx->running=TRUE;
return err;
}
@ -391,6 +401,10 @@ MSList *sal_get_pending_auths(Sal *sal){
return ms_list_copy(sal->pending_auths);
}
void sal_use_double_registrations(Sal *ctx, bool_t enabled){
ctx->double_reg=enabled;
}
static int extract_received_rport(osip_message_t *msg, const char **received, int *rportval){
osip_via_t *via=NULL;
osip_generic_param_t *param=NULL;
@ -764,8 +778,6 @@ int sal_call_terminate(SalOp *h){
if (err!=0){
ms_warning("Exosip could not terminate the call: cid=%i did=%i", h->cid,h->did);
}
sal_remove_call(h->base.root,h);
h->cid=-1;
return 0;
}
@ -784,7 +796,16 @@ void sal_op_authenticate(SalOp *h, const SalAuthInfo *info){
h->auth_info=sal_auth_info_clone(info); /*store auth info for subsequent request*/
}
}
void sal_op_cancel_authentication(SalOp *h) {
if (h->rid >0) {
sal_op_get_sal(h)->callbacks.register_failure(h,SalErrorFailure, SalReasonForbidden,_("Authentication failure"));
} else if (h->cid >0) {
sal_op_get_sal(h)->callbacks.call_failure(h,SalErrorFailure, SalReasonForbidden,_("Authentication failure"),0);
} else {
ms_warning("Auth failure not handled");
}
}
static void set_network_origin(SalOp *op, osip_message_t *req){
const char *received=NULL;
int rport=5060;
@ -836,6 +857,9 @@ static SalOp *find_op(Sal *sal, eXosip_event_t *ev){
if (ev->sid>0){
return sal_find_out_subscribe(sal,ev->sid);
}
if (ev->nid>0){
return sal_find_in_subscribe(sal,ev->nid);
}
if (ev->response) return sal_find_other(sal,ev->response);
return NULL;
}
@ -1054,8 +1078,6 @@ static void call_terminated(Sal *sal, eXosip_event_t *ev){
if (ev->request){
osip_from_to_str(ev->request->from,&from);
}
sal_remove_call(sal,op);
op->cid=-1;
sal->callbacks.call_terminated(op,from!=NULL ? from : sal_op_get_from(op));
if (from) osip_free(from);
}
@ -1066,9 +1088,11 @@ static void call_released(Sal *sal, eXosip_event_t *ev){
ms_warning("No op associated to this call_released()");
return;
}
op->cid=-1;
if (op->did==-1)
sal->callbacks.call_failure(op,SalErrorNoResponse,SalReasonUnknown,NULL, 487);
if (ev->response==NULL){
/* no response received so far */
call_failure(sal,ev);
}
sal->callbacks.call_released(op);
}
static int get_auth_data_from_response(osip_message_t *resp, const char **realm, const char **username){
@ -1323,9 +1347,11 @@ static void process_dtmf_relay(Sal *sal, eXosip_event_t *ev){
sal->callbacks.dtmf_received(op, tmp[0]);
}
}
eXosip_lock();
eXosip_call_build_answer(ev->tid,200,&ans);
if (ans)
eXosip_call_send_answer(ev->tid,200,ans);
eXosip_unlock();
}
}
@ -1553,6 +1579,9 @@ static bool_t register_again_with_updated_contact(SalOp *op, osip_message_t *ori
char *tmp;
char port[20];
SalAddress *addr;
Sal *sal=op->base.root;
if (sal->double_reg==FALSE) return FALSE;
if (extract_received_rport(last_answer,&received,&rport)==-1) return FALSE;
osip_message_get_contact(orig_request,0,&ctt);
@ -1784,6 +1813,7 @@ static bool_t process_event(Sal *sal, eXosip_event_t *ev){
other_request_reply(sal,ev);
break;
case EXOSIP_MESSAGE_REQUESTFAILURE:
case EXOSIP_NOTIFICATION_REQUESTFAILURE:
if (ev->response) {
switch (ev->response->status_code) {
case 407:
@ -1982,6 +2012,9 @@ void sal_set_keepalive_period(Sal *ctx,unsigned int value) {
ctx->keepalive_period=value;
eXosip_set_option (EXOSIP_OPT_UDP_KEEP_ALIVE, &value);
}
unsigned int sal_get_keepalive_period(Sal *ctx) {
return ctx->keepalive_period;
}
const char * sal_address_get_port(const SalAddress *addr) {
const osip_from_t *u=(const osip_from_t*)addr;
@ -1997,47 +2030,18 @@ int sal_address_get_port_int(const SalAddress *uri) {
}
}
/*
* Send a re-Invite used to hold the current call
*/
int sal_call_hold(SalOp *h, bool_t holdon)
{
int err=0;
osip_message_t *reinvite=NULL;
if(eXosip_call_build_request(h->did,"INVITE",&reinvite) != OSIP_SUCCESS || reinvite==NULL)
return -1;
osip_message_set_subject(reinvite,holdon ? "Phone call hold" : "Phone call resume" );
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");
}
//add something to say that the distant sip phone will be in sendonly/sendrecv mode
if (h->base.local_media){
h->sdp_offering=TRUE;
sal_media_description_set_dir(h->base.local_media, holdon ? SalStreamSendOnly : SalStreamSendRecv);
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;
}
/* sends a reinvite. Local media description may have changed by application since call establishment*/
int sal_call_update(SalOp *h){
int sal_call_update(SalOp *h, const char *subject){
int err=0;
osip_message_t *reinvite=NULL;
eXosip_lock();
if(eXosip_call_build_request(h->did,"INVITE",&reinvite) != OSIP_SUCCESS || reinvite==NULL){
if(eXosip_call_build_request(h->did,"INVITE",&reinvite) != 0 || reinvite==NULL){
eXosip_unlock();
return -1;
}
eXosip_unlock();
osip_message_set_subject(reinvite,osip_strdup("Phone call parameters updated"));
osip_message_set_subject(reinvite,subject);
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");

View file

@ -41,6 +41,7 @@ struct Sal{
int keepalive_period;
void *up;
bool_t one_matching_codec;
bool_t double_reg;
};
struct SalOp{
@ -78,6 +79,7 @@ void sal_exosip_subscription_closed(Sal *sal,eXosip_event_t *ev);
void sal_exosip_in_subscription_closed(Sal *sal, eXosip_event_t *ev);
SalOp * sal_find_out_subscribe(Sal *sal, int sid);
SalOp * sal_find_in_subscribe(Sal *sal, int nid);
void sal_exosip_fix_route(SalOp *op);
void _osip_list_set_empty(osip_list_t *l, void (*freefunc)(void*));

View file

@ -39,6 +39,7 @@ SalOp * sal_find_out_subscribe(Sal *sal, int sid){
op=(SalOp*)elem->data;
if (op->sid==sid) return op;
}
ms_message("No op for sid %i",sid);
return NULL;
}
@ -50,7 +51,7 @@ void sal_remove_out_subscribe(Sal *sal, SalOp *op){
sal->out_subscribes=ms_list_remove(sal->out_subscribes,op);
}
static SalOp * sal_find_in_subscribe(Sal *sal, int nid){
SalOp * sal_find_in_subscribe(Sal *sal, int nid){
const MSList *elem;
SalOp *op;
for(elem=sal->in_subscribes;elem!=NULL;elem=elem->next){
@ -569,6 +570,7 @@ int sal_notify_presence(SalOp *op, SalPresenceStatus status, const char *status_
if (msg!=NULL){
const char *identity=sal_op_get_contact(op);
if (identity==NULL) identity=sal_op_get_to(op);
_osip_list_set_empty(&msg->contacts,(void (*)(void*))osip_contact_free);
osip_message_set_contact(msg,identity);
add_presence_body(msg,status);
eXosip_insubscription_send_request(op->did,msg);

View file

@ -127,14 +127,18 @@ static sdp_message_t *create_generic_sdp(const SalMediaDescription *desc)
{
sdp_message_t *local;
int inet6;
char sessid[16];
char sessver[16];
snprintf(sessid,16,"%i",desc->session_id);
snprintf(sessver,16,"%i",desc->session_ver);
sdp_message_init (&local);
if (strchr(desc->addr,':')!=NULL){
inet6=1;
}else inet6=0;
sdp_message_v_version_set (local, osip_strdup ("0"));
sdp_message_o_origin_set (local, osip_strdup (desc->username),
osip_strdup ("123456"), osip_strdup ("654321"),
osip_strdup (sessid), osip_strdup (sessver),
osip_strdup ("IN"), inet6 ? osip_strdup("IP6") : osip_strdup ("IP4"),
osip_strdup (desc->addr));
sdp_message_s_name_set (local, osip_strdup ("A conversation"));
@ -181,11 +185,23 @@ static void add_payload(sdp_message_t *msg, int line, const PayloadType *pt)
static void add_line(sdp_message_t *msg, int lineno, const SalStreamDescription *desc){
const char *mt=desc->type==SalAudio ? "audio" : "video";
const char *mt=NULL;
const MSList *elem;
const char *addr;
const char *dir="sendrecv";
int port;
switch (desc->type) {
case SalAudio:
mt="audio";
break;
case SalVideo:
mt="video";
break;
case SalOther:
mt=desc->typeother;
break;
}
if (desc->candidates[0].addr[0]!='\0'){
addr=desc->candidates[0].addr;
port=desc->candidates[0].port;
@ -310,7 +326,10 @@ int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc){
stream->type=SalAudio;
}else if (strcasecmp("video", mtype) == 0){
stream->type=SalVideo;
}else stream->type=SalOther;
}else {
stream->type=SalOther;
strncpy(stream->typeother,mtype,sizeof(stream->typeother)-1);
}
for(j=0;(sbw=sdp_message_bandwidth_get(msg,i,j))!=NULL;++j){
if (strcasecmp(sbw->b_bwtype,"AS")==0) stream->bandwidth=atoi(sbw->b_bandwidth);
}

46
coreapi/test_ecc.c Normal file
View file

@ -0,0 +1,46 @@
/*
linphone
Copyright (C) 2011 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"
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);
}
int main(int argc, char *argv[]){
int count=0;
LinphoneCoreVTable vtable={0};
LinphoneCore *lc=linphone_core_new(&vtable,NULL,NULL,NULL);
linphone_core_enable_logs(NULL);
linphone_core_start_echo_calibration(lc,calibration_finished,NULL);
while(count++<1000){
linphone_core_iterate(lc);
ms_usleep(10000);
}
linphone_core_destroy(lc);
return 0;
}

2
gtk/.gitignore vendored
View file

@ -1,4 +1,4 @@
linphone-3
linphone
.libs
.deps
linphone.res

View file

@ -27,9 +27,9 @@ if BUILD_GTK_UI
BUILT_SOURCES=version_date.h
bin_PROGRAMS=linphone-3
bin_PROGRAMS=linphone
linphone_3_SOURCES= \
linphone_SOURCES= \
main.c \
propertybox.c \
friendlist.c \
@ -45,7 +45,7 @@ linphone_3_SOURCES= \
loginframe.c \
linphone.h
linphone_3_LDADD=$(ORTP_LIBS) \
linphone_LDADD=$(ORTP_LIBS) \
$(MEDIASTREAMER_LIBS) \
$(top_builddir)/coreapi/liblinphone.la \
$(LIBGTK_LIBS) $(INTLLIBS)
@ -56,10 +56,10 @@ if BUILD_WIN32
linphone.res: $(LINPHONE_ICO_RC_FILE) $(LINPHONE_ICO_FILE)
windres $(LINPHONE_ICO_RC_FILE) -O coff -o linphone.res
linphone_3_LDADD+=linphone.res -lwininet
linphone_3_LDFLAGS=-Wl,--export-all-symbols -mwindows
linphone_LDADD+=linphone.res -lwininet
linphone_LDFLAGS=-Wl,--export-all-symbols -mwindows
else
linphone_3_LDFLAGS=-export-dynamic
linphone_LDFLAGS=-export-dynamic
endif
uidir=$(datadir)/linphone

View file

@ -201,6 +201,7 @@ void linphone_gtk_in_call_view_set_incoming(LinphoneCall *call, bool_t with_paus
GtkWidget *animation=linphone_gtk_get_widget(callview,"in_call_animation");
GdkPixbufAnimation *pbuf=create_pixbuf_animation("calling_anim.gif");
GtkWidget *answer_button;
GtkWidget *image;
gtk_label_set_markup(GTK_LABEL(status),_("<b>Incoming call</b>"));
gtk_widget_show_all(linphone_gtk_get_widget(callview,"answer_decline_panel"));
@ -209,14 +210,17 @@ void linphone_gtk_in_call_view_set_incoming(LinphoneCall *call, bool_t with_paus
display_peer_name_in_label(callee,linphone_call_get_remote_address (call));
answer_button=linphone_gtk_get_widget(callview,"accept_call");
gtk_button_set_image(GTK_BUTTON(answer_button),
create_pixmap (linphone_gtk_get_ui_config("start_call_icon","startcall-green.png")));
image=create_pixmap (linphone_gtk_get_ui_config("start_call_icon","startcall-green.png"));
if (with_pause){
gtk_button_set_label(GTK_BUTTON(answer_button),
_("Pause all calls\nand answer"));
}else gtk_button_set_label(GTK_BUTTON(answer_button),_("Answer"));
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_button_set_image(GTK_BUTTON(answer_button),image);
gtk_widget_show(image);
image=create_pixmap (linphone_gtk_get_ui_config("stop_call_icon","stopcall-red.png"));
gtk_button_set_image(GTK_BUTTON(linphone_gtk_get_widget(callview,"decline_call")),image);
gtk_widget_show(image);
if (pbuf!=NULL){
gtk_image_set_from_animation(GTK_IMAGE(animation),pbuf);

View file

@ -1,147 +0,0 @@
<?xml version="1.0"?>
<interface>
<!-- interface-requires gtk+ 2.16 -->
<!-- interface-naming-policy toplevel-contextual -->
<object class="GtkDialog" id="incoming_call">
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="border_width">5</property>
<property name="type">popup</property>
<property name="title" translatable="yes">Linphone - Incoming call</property>
<property name="window_position">center-on-parent</property>
<property name="icon">linphone2.png</property>
<property name="type_hint">notification</property>
<property name="urgency_hint">True</property>
<property name="deletable">False</property>
<child internal-child="vbox">
<object class="GtkVBox" id="dialog-vbox8">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="spacing">2</property>
<child>
<object class="GtkFrame" id="frame16">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label_xalign">0</property>
<child>
<object class="GtkAlignment" id="alignment16">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="left_padding">12</property>
<child>
<object class="GtkLabel" id="message">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">Incoming call from</property>
</object>
</child>
</object>
</child>
<child type="label">
<object class="GtkLabel" id="label43">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">Incoming call</property>
<property name="use_markup">True</property>
</object>
</child>
</object>
<packing>
<property name="position">1</property>
</packing>
</child>
<child internal-child="action_area">
<object class="GtkHButtonBox" id="dialog-action_area7">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="layout_style">spread</property>
<child>
<object class="GtkButton" id="accept_call">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<signal handler="linphone_gtk_accept_call" name="clicked"/>
<child>
<object class="GtkHBox" id="hbox17">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<child>
<object class="GtkImage" id="image12">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="stock">gtk-yes</property>
</object>
<packing>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label44">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">Accept</property>
</object>
<packing>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="decline_cal">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<signal handler="linphone_gtk_decline_call" name="clicked"/>
<child>
<object class="GtkHBox" id="hbox20">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<child>
<object class="GtkImage" id="image13">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="stock">gtk-no</property>
</object>
<packing>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="decline_call">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">Decline</property>
</object>
<packing>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="pack_type">end</property>
<property name="position">0</property>
</packing>
</child>
</object>
</child>
</object>
</interface>

View file

@ -1446,6 +1446,7 @@ int main(int argc, char *argv[]){
settings=gtk_settings_get_default();
g_type_class_unref (g_type_class_ref (GTK_TYPE_IMAGE_MENU_ITEM));
g_type_class_unref (g_type_class_ref (GTK_TYPE_BUTTON));
g_object_set(settings, "gtk-menu-images", TRUE, NULL);
g_object_set(settings, "gtk-button-images", TRUE, NULL);
#ifdef WIN32

View file

@ -24,7 +24,7 @@ import java.util.Vector;
* Object representing a Call. calls are created using {@link LinphoneCore#invite(LinphoneAddress)} or passed to the application by listener {@link LinphoneCoreListener#callState(LinphoneCore, LinphoneCall, State, String)}
*
*/
@SuppressWarnings("unchecked")
public interface LinphoneCall {
/**
* Linphone call states
@ -110,7 +110,11 @@ public interface LinphoneCall {
* The remote accepted the call update initiated by us
*/
public static final State CallUpdated = new State(17, "CallUpdated");
/**
* The call object is now released.
*/
public static final State CallReleased = new State(18,"CallReleased");
private State(int value,String stringValue) {
mValue = value;
@ -174,5 +178,9 @@ public interface LinphoneCall {
* @return true if echo limiter is enabled.
*/
public boolean isEchoLimiterEnabled();
/**
* Returns the object associated to a call this one is replacing.
* Call replacement can occur during transfer scenarios.
*/
public LinphoneCall getReplacedCall();
}

View file

@ -24,7 +24,7 @@ package org.linphone.core;
import java.util.Vector;
@SuppressWarnings("unchecked")
public interface LinphoneCallLog {
/**
* Represents call status

View file

@ -25,7 +25,7 @@ import java.util.Vector;
* Linphone core main object created by method {@link LinphoneCoreFactory#createLinphoneCore(LinphoneCoreListener, String, String, Object)}.
*
*/
@SuppressWarnings("unchecked")
public interface LinphoneCore {
/**
* linphone core states
@ -179,6 +179,50 @@ public interface LinphoneCore {
return mStringValue;
}
}
/**
* EC Calibrator Status
.
*
*/
static public class EcCalibratorStatus {
static private Vector values = new Vector();
/**
* Calibration in progress
*/
static public EcCalibratorStatus InProgress = new EcCalibratorStatus(0,"InProgress");
/**
* Calibration done
*/
static public EcCalibratorStatus Done = new EcCalibratorStatus(1,"Done");
/**
* Calibration in progress
*/
static public EcCalibratorStatus Failed = new EcCalibratorStatus(2,"Failed");
private final int mValue;
private final String mStringValue;
private EcCalibratorStatus(int value,String stringValue) {
mValue = value;
values.addElement(this);
mStringValue=stringValue;
}
public static EcCalibratorStatus fromInt(int value) {
for (int i=0; i<values.size();i++) {
EcCalibratorStatus status = (EcCalibratorStatus) values.elementAt(i);
if (status.mValue == value) return status;
}
throw new RuntimeException("status not found ["+value+"]");
}
public String toString() {
return mStringValue;
}
public int value(){
return mValue;
}
}
/**
* clear all added proxy configs
*/
@ -386,10 +430,17 @@ public interface LinphoneCore {
*/
public boolean isEchoCancellationEnabled();
/**
* not implemented yet
* set transport used for signaling (TCP or UDP)
*
* @param aTransport
*/
public void setSignalingTransport(Transport aTransport);
/**
* get transport used for signaling (TCP or UDP)
*
* @return Transport;
*/
public Transport getSignalingTransport();
/**
* not implemented
* @param value
@ -489,5 +540,20 @@ public interface LinphoneCore {
public VideoSize getPreferredVideoSize();
public PayloadType[] listVideoCodecs();
/**
* enable signaling keep alive. small udp packet sent periodically to keep udp NAT association
*/
void enableKeepAlive(boolean enable);
/**
* get keep elive mode
* @return true if enable
*/
boolean isKeepAliveEnabled();
/**
* Start an echo calibration of the sound devices, in order to find adequate settings for the echo canceler automatically.
* status is notified to {@link LinphoneCoreListener#ecCalibrationStatus(EcCalibratorStatus, int, Object)}
* @param User object
* @throws LinphoneCoreException if operation is still in progress;
**/
void startEchoCalibration(Object data) throws LinphoneCoreException;
}

View file

@ -21,7 +21,7 @@ package org.linphone.core;
@SuppressWarnings("unchecked")
abstract public class LinphoneCoreFactory {
private static String factoryName = "org.linphone.core.LinphoneCoreFactoryImpl";

View file

@ -78,5 +78,14 @@ public interface LinphoneCoreListener {
* @param message incoming message
*/
public void textReceived(LinphoneCore lc, LinphoneChatRoom cr,LinphoneAddress from,String message);
/**
* Invoked when echo cancalation calibration is completed
* @param lc LinphoneCore
* @param status
* @param delay_ms echo delay
* @param data
*/
void ecCalibrationStatus(LinphoneCore lc,LinphoneCore.EcCalibratorStatus status, int delay_ms, Object data);
}

View file

@ -27,7 +27,7 @@ import java.util.Vector;
*
*
*/
@SuppressWarnings("unchecked")
public interface LinphoneFriend {
/**
* Enum controlling behavior for incoming subscription request.

View file

@ -25,7 +25,7 @@ import java.util.Vector;
* Enum describing remote friend status
*
*/
@SuppressWarnings("unchecked")
public class OnlineStatus {
static private Vector values = new Vector();

View file

@ -78,7 +78,7 @@ public final class VideoSize {
return true;
}
@Override
public String toString() {
return "width = "+width + " height = " + height;
}

View file

@ -1,10 +1,10 @@
./bin/avcodec-52.dll
./bin/avutil-50.dll
./bin/libeXosip2-4.dll
./bin/libeXosip2-6.dll
./bin/libogg.dll
./bin/libtheora.dll
./bin/libxml2-2.dll
./bin/libosip2-4.dll
./bin/libosipparser2-4.dll
./bin/libosip2-6.dll
./bin/libosipparser2-6.dll
./bin/swscale-0.dll

View file

@ -30,19 +30,19 @@ Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{
#include "linphone-win32.filelist"
[Icons]
Name: "{group}\Linphone"; Filename: "{app}\bin\linphone-3.exe" ; WorkingDir: "{app}"
Name: "{userdesktop}\Linphone"; Filename: "{app}\bin\linphone-3.exe"; WorkingDir: "{app}" ; Tasks: desktopicon
Name: "{group}\Linphone"; Filename: "{app}\bin\linphone.exe" ; WorkingDir: "{app}"
Name: "{userdesktop}\Linphone"; Filename: "{app}\bin\linphone.exe"; WorkingDir: "{app}" ; Tasks: desktopicon
[Registry]
Root: HKCR; Subkey: "sip";
Root: HKCR; Subkey: "sip"; ValueData: "URL: SIP protocol" ; ValueType:string
Root: HKCR; Subkey: "sip"; ValueName: "EditFlags"; ValueData: "02 00 00 00" ; ValueType:binary
Root: HKCR; Subkey: "sip"; ValueName: "URL Protocol" ; ValueType:string
Root: HKCR; Subkey: "sip\DefaultIcon"; ValueData: "{app}\bin\linphone-3.exe"; ValueType:string ; Flags:uninsdeletekey
Root: HKCR; Subkey: "sip\DefaultIcon"; ValueData: "{app}\bin\linphone.exe"; ValueType:string ; Flags:uninsdeletekey
Root: HKCR; Subkey: "sip\shell"
Root: HKCR; Subkey: "sip\shell\open"
Root: HKCR; Subkey: "sip\shell\open\command"; ValueType:string ; ValueData: "{app}\bin\linphone-3.exe --workdir {app} --call %1"; Flags:uninsdeletekey
Root: HKCR; Subkey: "sip\shell\open\command"; ValueType:string ; ValueData: "{app}\bin\linphone.exe --workdir {app} --call %1"; Flags:uninsdeletekey
[Run]
Filename: "{app}\bin\linphone-3.exe"; Description: "{cm:LaunchProgram,Linphone}"; WorkingDir: "{app}" ; Flags: nowait postinstall skipifsilent
Filename: "{app}\bin\linphone.exe"; Description: "{cm:LaunchProgram,Linphone}"; WorkingDir: "{app}" ; Flags: nowait postinstall skipifsilent

View file

@ -16,7 +16,7 @@
<kdevcustomproject>
<run>
<directoryradio>executable</directoryradio>
<mainprogram>gtk-glade/linphone-3</mainprogram>
<mainprogram>gtk-glade/linphone</mainprogram>
<programargs/>
<globaldebugarguments/>
<globalcwd/>

View file

@ -29,6 +29,7 @@ coreapi/presence.c
coreapi/friend.c
coreapi/proxy.c
coreapi/callbacks.c
coreapi/sal_eXosip2.c
mediastreamer2/src/alaw.c
mediastreamer2/src/alsa.c
mediastreamer2/src/aqsnd.c

View file

@ -1 +1,2 @@
gtk/p2pwizard.ui

1524
po/cs.po

File diff suppressed because it is too large Load diff

1459
po/de.po

File diff suppressed because it is too large Load diff

1417
po/es.po

File diff suppressed because it is too large Load diff

1465
po/fr.po

File diff suppressed because it is too large Load diff

1460
po/hu.po

File diff suppressed because it is too large Load diff

1578
po/it.po

File diff suppressed because it is too large Load diff

1412
po/ja.po

File diff suppressed because it is too large Load diff

1466
po/nl.po

File diff suppressed because it is too large Load diff

1411
po/pl.po

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

1647
po/ru.po

File diff suppressed because it is too large Load diff

1542
po/sv.po

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -11,7 +11,7 @@ MSX264_ZIP=$(WORKDIR)/msx264.zip
INSTALL_ROOT=$(WORKDIR)/root
FILELIST=$(WORKDIR)/linphone-bundle.filelist
LINPHONE_VERSION=strings $(INSTALL_ROOT)/bin/linphone-3.exe |grep linphone_ident | sed 's/linphone_ident_string=//'
LINPHONE_VERSION=strings $(INSTALL_ROOT)/bin/linphone.exe |grep linphone_ident | sed 's/linphone_ident_string=//'
$(WORKDIR):
mkdir -p $(WORKDIR)

View file

@ -8,7 +8,7 @@ LINPHONE_RINGS=rings/orig.wav \
rings/oldphone-mono-30s.caf \
rings/rock.wav \
rings/bigben.wav \
rings/toy.wav \
rings/toy-mono.wav \
rings/sweet.wav \
rings/synth.wav \
rings/tapping.wav

View file

@ -4,7 +4,7 @@ Comment=Linphone is a web-phone
Comment[fr]=Linphone est un web-phone.
Comment[de]=Linphone ist ein web-phone.
Type=Application
Exec=linphone-3
Exec=linphone
Icon=@prefix@/share/pixmaps/linphone/linphone.png
Terminal=false
Categories=Network;Telephony;
Categories=Network;Telephony;

BIN
share/rings/toy-mono.wav Normal file

Binary file not shown.

Binary file not shown.