Merge branch 'master' of git.linphone.org:linphone

This commit is contained in:
Yann Diorcet 2012-04-05 12:44:58 +02:00
commit cdba86af35
17 changed files with 301 additions and 85 deletions

View file

@ -17,7 +17,7 @@ if test "$LINPHONE_EXTRA_VERSION" != "" ;then
LINPHONE_VERSION=$LINPHONE_VERSION.${LINPHONE_EXTRA_VERSION}
fi
LIBLINPHONE_SO_CURRENT=4 dnl increment this number when you add/change/remove an interface
LIBLINPHONE_SO_CURRENT=5 dnl increment this number when you add/change/remove an interface
LIBLINPHONE_SO_REVISION=0 dnl increment this number when you change source code, without changing interfaces; set to 0 when incrementing CURRENT
LIBLINPHONE_SO_AGE=0 dnl increment this number when you add an interface, set to 0 if you remove an interface
@ -102,9 +102,13 @@ AC_SUBST(ALL_LINGUAS)
AC_DEFINE_UNQUOTED(LINPHONE_ALL_LANGS, "$ALL_LINGUAS", [All supported languages])
if test "$mingw_found" != "yes" ; then
dnl gettext macro does not work properly under mingw. And we want to use the one provided by GTK.
AM_GNU_GETTEXT([external])
LIBS="$LIBS $LIBINTL"
dnl gettext macro does not work properly under mingw. And we want to use the one provided by GTK.
dnl AM_GNU_GETTEXT pollutes CPPFLAGS: workaround this.
CPPFLAGS_save=$CPPFLAGS
AM_GNU_GETTEXT([external])
CPPFLAGS=$CPPFLAGS_save
LIBS="$LIBS $LIBINTL"
else
AC_DEFINE(ENABLE_NLS,1,[Tells whether localisation is possible])
AC_DEFINE(HAVE_GETTEXT,1,[Tells wheter localisation is possible])

View file

@ -276,6 +276,7 @@ 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;
if (call->localdesc->streams[0].max_rate>0) ms_snd_card_set_preferred_sample_rate(ringcard, call->localdesc->streams[0].max_rate);
lc->ringstream=ring_start(lc->sound_conf.remote_ring,2000,ringcard);
}
ms_message("Remote ringing...");
@ -323,6 +324,7 @@ static void call_accepted(SalOp *op){
call->state==LinphoneCallOutgoingRinging ||
call->state==LinphoneCallOutgoingEarlyMedia){
linphone_call_set_state(call,LinphoneCallConnected,"Connected");
if (call->referer) linphone_core_notify_refer_state(lc,call->referer,call);
}
if (md && !sal_media_description_empty(md)){
if (sal_media_description_has_dir(md,SalStreamSendOnly) ||
@ -368,9 +370,9 @@ static void call_accepted(SalOp *op){
}
}
linphone_core_update_streams (lc,call,md);
linphone_call_set_state(call, LinphoneCallStreamsRunning, "Streams running");
if (!call->current_params.in_conference)
lc->current_call=call;
linphone_call_set_state(call, LinphoneCallStreamsRunning, "Streams running");
}
}else{
/*send a bye*/
@ -418,6 +420,7 @@ static void call_resumed(LinphoneCore *lc, LinphoneCall *call){
if(lc->vtable.display_status)
lc->vtable.display_status(lc,_("We have been resumed."));
linphone_call_set_state(call,LinphoneCallStreamsRunning,"Connected (streams running)");
linphone_call_set_transfer_state(call, LinphoneCallIdle);
}
static void call_paused_by_remote(LinphoneCore *lc, LinphoneCall *call){
@ -558,16 +561,18 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de
int i;
ms_message("Outgoing call failed with SRTP (SAVP) enabled - retrying with AVP");
linphone_call_stop_media_streams(call);
/* clear SRTP local params */
call->params.media_encryption = LinphoneMediaEncryptionNone;
for(i=0; i<call->localdesc->nstreams; i++) {
call->localdesc->streams[i].proto = SalProtoRtpAvp;
memset(call->localdesc->streams[i].crypto, 0, sizeof(call->localdesc->streams[i].crypto));
if (call->state==LinphoneCallOutgoingInit || call->state==LinphoneCallOutgoingProgress){
/* clear SRTP local params */
call->params.media_encryption = LinphoneMediaEncryptionNone;
for(i=0; i<call->localdesc->nstreams; i++) {
call->localdesc->streams[i].proto = SalProtoRtpAvp;
memset(call->localdesc->streams[i].crypto, 0, sizeof(call->localdesc->streams[i].crypto));
}
linphone_core_start_invite(lc, call, NULL);
}
linphone_core_start_invite(lc, call, NULL);
return;
}
msg=_("No common codecs");
msg=_("Incompatible media parameters.");
if (lc->vtable.display_status)
lc->vtable.display_status(lc,msg);
break;
@ -582,6 +587,10 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de
lc->ringstream=NULL;
}
linphone_call_stop_media_streams (call);
if (call->referer && linphone_call_get_state(call->referer)==LinphoneCallPaused && call->referer->was_automatically_paused){
/*resume to the call that send us the refer automatically*/
linphone_core_resume_call(lc,call->referer);
}
if (sr == SalReasonDeclined) {
call->reason=LinphoneReasonDeclined;
linphone_call_set_state(call,LinphoneCallEnd,"Call declined.");
@ -744,12 +753,11 @@ static void refer_received(Sal *sal, SalOp *op, const char *referto){
if (call->state!=LinphoneCallPaused){
ms_message("Automatically pausing current call to accept transfer.");
linphone_core_pause_call(lc,call);
call->was_automatically_paused=TRUE;
}
linphone_core_start_refered_call(lc,call);
sal_call_accept_refer(op);
}else if (lc->vtable.refer_received){
lc->vtable.refer_received(lc,referto);
sal_call_accept_refer(op);
}
}
@ -766,7 +774,7 @@ static void notify(SalOp *op, const char *from, const char *msg){
lc->vtable.notify_recv(lc,call,from,msg);
}
static void notify_presence(SalOp *op, SalSubscribeState ss, SalPresenceStatus status, const char *msg){
static void notify_presence(SalOp *op, SalSubscribeStatus ss, SalPresenceStatus status, const char *msg){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
linphone_notify_recv(lc,op,ss,status);
}
@ -795,6 +803,34 @@ static void ping_reply(SalOp *op){
}
}
static void notify_refer(SalOp *op, SalReferStatus status){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
LinphoneCall *call=(LinphoneCall*) sal_op_get_user_pointer(op);
LinphoneCallState cstate;
if (call==NULL) {
ms_warning("Receiving notify_refer for unknown call.");
return ;
}
switch(status){
case SalReferTrying:
cstate=LinphoneCallOutgoingProgress;
break;
case SalReferSuccess:
cstate=LinphoneCallConnected;
break;
case SalReferFailed:
cstate=LinphoneCallError;
break;
default:
cstate=LinphoneCallError;
}
linphone_call_set_transfer_state(call, cstate);
if (cstate==LinphoneCallConnected){
/*automatically terminate the call as the transfer is complete.*/
linphone_core_terminate_call(lc,call);
}
}
SalCallbacks linphone_sal_callbacks={
call_received,
call_ringing,
@ -814,6 +850,7 @@ SalCallbacks linphone_sal_callbacks={
text_received,
notify,
notify_presence,
notify_refer,
subscribe_received,
subscribe_closed,
ping_reply

View file

@ -52,15 +52,20 @@
void linphone_chat_room_send_message(LinphoneChatRoom *cr, const char *msg){
const char *route=NULL;
const char *identity=linphone_core_find_best_identity(cr->lc,cr->peer_url,&route);
SalOp *op;
SalOp *op=NULL;
LinphoneCall *call;
if((call = linphone_core_get_call_by_remote_address(cr->lc,cr->peer))!=NULL)
{
ms_message("send SIP message into the call\n");
op = call->op;
if((call = linphone_core_get_call_by_remote_address(cr->lc,cr->peer))!=NULL){
if (call->state==LinphoneCallConnected ||
call->state==LinphoneCallStreamsRunning ||
call->state==LinphoneCallPaused ||
call->state==LinphoneCallPausing ||
call->state==LinphoneCallPausedByRemote){
ms_message("send SIP message through the existing call.");
op = call->op;
}
}
else
{
if (op==NULL){
/*sending out of calls*/
op = sal_op_new(cr->lc->sal);
sal_op_set_route(op,route);
if (cr->op!=NULL){

View file

@ -35,6 +35,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "mediastreamer2/msfileplayer.h"
#include "mediastreamer2/msjpegwriter.h"
#include "mediastreamer2/mseventqueue.h"
#include "mediastreamer2/mssndcard.h"
#ifdef VIDEO_ENABLED
static MSWebCam *get_nowebcam_device(){
@ -172,9 +173,10 @@ void linphone_call_set_authentication_token_verified(LinphoneCall *call, bool_t
propagate_encryption_changed(call);
}
static MSList *make_codec_list(LinphoneCore *lc, const MSList *codecs, int bandwidth_limit){
static MSList *make_codec_list(LinphoneCore *lc, const MSList *codecs, int bandwidth_limit,int* max_sample_rate){
MSList *l=NULL;
const MSList *it;
if (max_sample_rate) *max_sample_rate=0;
for(it=codecs;it!=NULL;it=it->next){
PayloadType *pt=(PayloadType*)it->data;
if (pt->flags & PAYLOAD_TYPE_ENABLED){
@ -184,6 +186,7 @@ static MSList *make_codec_list(LinphoneCore *lc, const MSList *codecs, int bandw
}
if (linphone_core_check_payload_type_usability(lc,pt)){
l=ms_list_append(l,payload_type_clone(pt));
if (max_sample_rate && payload_type_get_rate(pt)>*max_sample_rate) *max_sample_rate=payload_type_get_rate(pt);
}
}
}
@ -199,6 +202,7 @@ static SalMediaDescription *_create_local_media_description(LinphoneCore *lc, Li
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;
@ -213,10 +217,11 @@ static SalMediaDescription *_create_local_media_description(LinphoneCore *lc, Li
SalProtoRtpSavp : SalProtoRtpAvp;
md->streams[0].type=SalAudio;
md->streams[0].ptime=lc->net_conf.down_ptime;
l=make_codec_list(lc,lc->codecs_conf.audio_codecs,call->params.audio_bw);
l=make_codec_list(lc,lc->codecs_conf.audio_codecs,call->params.audio_bw,&md->streams[0].max_rate);
pt=payload_type_clone(rtp_profile_get_payload_from_mime(&av_profile,"telephone-event"));
l=ms_list_append(l,pt);
md->streams[0].payloads=l;
if (call->params.has_video){
@ -224,7 +229,7 @@ static SalMediaDescription *_create_local_media_description(LinphoneCore *lc, Li
md->streams[1].port=call->video_port;
md->streams[1].proto=md->streams[0].proto;
md->streams[1].type=SalVideo;
l=make_codec_list(lc,lc->codecs_conf.video_codecs,0);
l=make_codec_list(lc,lc->codecs_conf.video_codecs,0,NULL);
md->streams[1].payloads=l;
}
@ -290,6 +295,7 @@ static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from,
call->magic=linphone_call_magic;
call->refcnt=1;
call->state=LinphoneCallIdle;
call->transfer_state = LinphoneCallIdle;
call->start_time=time(NULL);
call->media_start_time=0;
call->log=linphone_call_log_new(call, from, to);
@ -332,6 +338,7 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr
discover_mtu(lc,linphone_address_get_domain (to));
if (params->referer){
sal_call_set_referer(call->op,params->referer->op);
call->referer=linphone_call_ref(params->referer);
}
return call;
}
@ -401,6 +408,10 @@ static void linphone_call_set_terminated(LinphoneCall *call){
linphone_core_stop_dtmf(lc);
call->ringing_beep=FALSE;
}
if (call->referer){
linphone_call_unref(call->referer);
call->referer=NULL;
}
}
void linphone_call_fix_call_parameters(LinphoneCall *call){
@ -842,12 +853,18 @@ static void rendercb(void *data, const MSPicture *local, const MSPicture *remote
#ifdef VIDEO_ENABLED
static void video_stream_event_cb(void *user_pointer, const MSFilter *f, const unsigned int event_id, const void *args){
LinphoneCall* call = (LinphoneCall*) user_pointer;
ms_warning("In linphonecall.c: video_stream_event_cb");
switch (event_id) {
case MS_VIDEO_DECODER_DECODING_ERRORS:
ms_warning("Case is MS_VIDEO_DECODER_DECODING_ERRORS");
linphone_call_send_vfu_request((LinphoneCall*) user_pointer);
linphone_call_send_vfu_request(call);
break;
case MS_VIDEO_DECODER_FIRST_IMAGE_DECODED:
ms_message("First video frame decoded successfully");
if (call->nextVideoFrameDecoded._func != NULL)
call->nextVideoFrameDecoded._func(call, call->nextVideoFrameDecoded._user_data);
break;
default:
ms_warning("Unhandled event %i", event_id);
break;
@ -855,6 +872,14 @@ static void video_stream_event_cb(void *user_pointer, const MSFilter *f, const u
}
#endif
void linphone_call_set_next_video_frame_decoded_callback(LinphoneCall *call, LinphoneCallCbFunc cb, void* user_data) {
call->nextVideoFrameDecoded._func = cb;
call->nextVideoFrameDecoded._user_data = user_data;
#ifdef VIDEO_ENABLED
ms_filter_call_method_noarg(call->videostream->decoder, MS_VIDEO_DECODER_RESET_FIRST_IMAGE_NOTIFICATION);
#endif
}
void linphone_call_init_media_streams(LinphoneCall *call){
LinphoneCore *lc=call->core;
SalMediaDescription *md=call->localdesc;
@ -1157,7 +1182,8 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cna
captcard=playcard=NULL;
}
use_ec=captcard==NULL ? FALSE : linphone_core_echo_cancellation_enabled(lc);
if (playcard && stream->max_rate>0) ms_snd_card_set_preferred_sample_rate(playcard, stream->max_rate);
if (captcard && stream->max_rate>0) ms_snd_card_set_preferred_sample_rate(captcard, stream->max_rate);
audio_stream_enable_adaptive_bitrate_control(call->audiostream,use_arc);
audio_stream_start_full(
call->audiostream,
@ -1273,6 +1299,7 @@ static void linphone_call_start_video_stream(LinphoneCall *call, const char *cna
cam=get_nowebcam_device();
}
if (!is_inactive){
call->log->video_enabled = TRUE;
video_stream_set_direction (call->videostream, dir);
ms_message("%s lc rotation:%d\n", __FUNCTION__, lc->device_rotation);
video_stream_set_device_rotation(call->videostream, lc->device_rotation);
@ -1649,4 +1676,16 @@ void linphone_call_log_completed(LinphoneCall *call){
call_logs_write_to_config_file(lc);
}
LinphoneCallState linphone_call_get_transfer_state(LinphoneCall *call) {
return call->transfer_state;
}
void linphone_call_set_transfer_state(LinphoneCall* call, LinphoneCallState state) {
if (state != call->transfer_state) {
LinphoneCore* lc = call->core;
call->transfer_state = state;
if (lc->vtable.transfer_state_changed)
lc->vtable.transfer_state_changed(lc, call, state);
}
}

View file

@ -132,6 +132,7 @@ void call_logs_write_to_config_file(LinphoneCore *lc){
lp_config_set_int(cfg,logsection,"duration",cl->duration);
if (cl->refkey) lp_config_set_string(cfg,logsection,"refkey",cl->refkey);
lp_config_set_float(cfg,logsection,"quality",cl->quality);
lp_config_set_int(cfg,logsection,"video_enabled", cl->video_enabled);
}
for(;i<lc->max_call_logs;++i){
snprintf(logsection,sizeof(logsection),"call_log_%i",i);
@ -160,6 +161,7 @@ static void call_logs_read_from_config_file(LinphoneCore *lc){
tmp=lp_config_get_string(cfg,logsection,"refkey",NULL);
if (tmp) cl->refkey=ms_strdup(tmp);
cl->quality=lp_config_get_float(cfg,logsection,"quality",-1);
cl->video_enabled=lp_config_get_int(cfg,logsection,"video_enabled",0);
lc->call_logs=ms_list_append(lc->call_logs,cl);
}else break;
}
@ -1798,7 +1800,7 @@ void linphone_core_iterate(LinphoneCore *lc){
/*start the call even if the OPTIONS reply did not arrive*/
linphone_core_start_invite(lc,call,NULL);
}
if (call->dir==LinphoneCallIncoming && call->state==LinphoneCallOutgoingRinging){
if (call->state==LinphoneCallIncomingReceived){
elapsed=curtime-call->start_time;
ms_message("incoming call ringing for %i seconds",elapsed);
if (elapsed>lc->sip_conf.inc_timeout){
@ -1941,12 +1943,20 @@ const char * linphone_core_get_route(LinphoneCore *lc){
void linphone_core_start_refered_call(LinphoneCore *lc, LinphoneCall *call){
if (call->refer_pending){
LinphoneCallParams *cp=linphone_core_create_default_call_parameters(lc);
LinphoneCall *newcall;
cp->has_video &= !!lc->video_policy.automatically_initiate;
cp->referer=call;
ms_message("Starting new call to refered address %s",call->refer_to);
call->refer_pending=FALSE;
linphone_core_invite_with_params(lc,call->refer_to,cp);
newcall=linphone_core_invite_with_params(lc,call->refer_to,cp);
linphone_call_params_destroy(cp);
if (newcall) linphone_core_notify_refer_state(lc,call,newcall);
}
}
void linphone_core_notify_refer_state(LinphoneCore *lc, LinphoneCall *referer, LinphoneCall *newcall){
if (referer->op!=NULL){
sal_call_notify_refer_state(referer->op,newcall ? newcall->op : NULL);
}
}
@ -2252,6 +2262,7 @@ int linphone_core_transfer_call(LinphoneCore *lc, LinphoneCall *call, const char
sal_call_refer(call->op,real_url);
ms_free(real_url);
linphone_address_destroy(real_parsed_url);
linphone_call_set_transfer_state(call, LinphoneCallOutgoingInit);
return 0;
}
@ -2268,7 +2279,9 @@ int linphone_core_transfer_call(LinphoneCore *lc, LinphoneCall *call, const char
* close the call with us (the 'dest' call).
**/
int linphone_core_transfer_call_to_another(LinphoneCore *lc, LinphoneCall *call, LinphoneCall *dest){
return sal_call_refer_with_replaces (call->op,dest->op);
int result = sal_call_refer_with_replaces (call->op,dest->op);
linphone_call_set_transfer_state(call, LinphoneCallOutgoingInit);
return result;
}
bool_t linphone_core_inc_invite_pending(LinphoneCore*lc){
@ -4573,8 +4586,10 @@ void linphone_core_start_dtmf_stream(LinphoneCore* lc) {
}
void linphone_core_stop_dtmf_stream(LinphoneCore* lc) {
if (lc->ringstream) ring_stop(lc->ringstream);
lc->ringstream=NULL;
if (lc->ringstream && lc->dmfs_playing_start_time!=0) {
ring_stop(lc->ringstream);
lc->ringstream=NULL;
}
}
int linphone_core_get_max_calls(LinphoneCore *lc) {

View file

@ -153,6 +153,7 @@ typedef struct _LinphoneCallLog{
rtp_stats_t local_stats;
rtp_stats_t remote_stats;
float quality;
int video_enabled;
struct _LinphoneCore *lc;
} LinphoneCallLog;
@ -225,6 +226,9 @@ typedef struct _LinphoneVideoPolicy LinphoneVideoPolicy;
**/
struct _LinphoneCall;
typedef struct _LinphoneCall LinphoneCall;
/** Callback prototype */
typedef void (*LinphoneCallCbFunc)(struct _LinphoneCall *call,void * user_data);
/**
* LinphoneCallState enum represents the different state a call can reach into.
@ -286,6 +290,9 @@ void linphone_call_set_authentication_token_verified(LinphoneCall *call, bool_t
void linphone_call_send_vfu_request(LinphoneCall *call);
void *linphone_call_get_user_pointer(LinphoneCall *call);
void linphone_call_set_user_pointer(LinphoneCall *call, void *user_pointer);
void linphone_call_set_next_video_frame_decoded_callback(LinphoneCall *call, LinphoneCallCbFunc cb, void* user_data);
LinphoneCallState linphone_call_get_transfer_state(LinphoneCall *call);
/**
* Enables or disable echo cancellation for this call
* @param call
@ -613,6 +620,8 @@ typedef void (*DtmfReceived)(struct _LinphoneCore* lc, LinphoneCall *call, int d
typedef void (*ReferReceived)(struct _LinphoneCore *lc, const char *refer_to);
/** Callback prototype */
typedef void (*BuddyInfoUpdated)(struct _LinphoneCore *lc, LinphoneFriend *lf);
/** Callback prototype for in progress transfers. The new_call_state is the state of the call resulting of the transfer, at the other party. */
typedef void (*LinphoneTransferStateChanged)(struct _LinphoneCore *lc, LinphoneCall *transfered, LinphoneCallState new_call_state);
/**
* This structure holds all callbacks that the application should implement.
@ -629,6 +638,8 @@ typedef struct _LinphoneVTable{
TextMessageReceived text_received; /**< A text message has been received */
DtmfReceived dtmf_received; /**< A dtmf has been received received */
ReferReceived refer_received; /**< An out of call refer was received */
CallEncryptionChangedCb call_encryption_changed; /**<Notifies on change in the encryption of call streams */
LinphoneTransferStateChanged transfer_state_changed; /**<Notifies when a transfer is in progress */
BuddyInfoUpdated buddy_info_updated; /**< a LinphoneFriend's BuddyInfo has changed*/
NotifyReceivedCb notify_recv; /**< Other notifications*/
DisplayStatusCb display_status; /**< Callback that notifies various events with human readable text.*/
@ -636,7 +647,6 @@ typedef struct _LinphoneVTable{
DisplayMessageCb display_warning;/** Callback to display a warning to the user */
DisplayUrlCb display_url;
ShowInterfaceCb show; /**< Notifies the application that it should show up*/
CallEncryptionChangedCb call_encryption_changed; /**<Notifies on change in the encryption of call streams */
} LinphoneCoreVTable;
/**
@ -782,6 +792,8 @@ int linphone_core_enable_payload_type(LinphoneCore *lc, PayloadType *pt, bool_t
PayloadType* linphone_core_find_payload_type(LinphoneCore* lc, const char* type, int rate) ;
int linphone_core_get_payload_type_number(LinphoneCore *lc, PayloadType *pt);
const char *linphone_core_get_payload_type_description(LinphoneCore *lc, PayloadType *pt);
bool_t linphone_core_check_payload_type_usability(LinphoneCore *lc, PayloadType *pt);

View file

@ -202,6 +202,10 @@ int linphone_core_enable_payload_type(LinphoneCore *lc, PayloadType *pt, bool_t
return -1;
}
int linphone_core_get_payload_type_number(LinphoneCore *lc, PayloadType *pt){
return payload_type_get_number(pt);
}
const char *linphone_core_get_payload_type_description(LinphoneCore *lc, PayloadType *pt){
if (ms_filter_codec_supported(pt->mime_type)){
MSFilterDesc *desc=ms_filter_get_encoder(pt->mime_type);

View file

@ -101,7 +101,7 @@ void linphone_subscription_new(LinphoneCore *lc, SalOp *op, const char *from){
ms_free(tmp);
}
void linphone_notify_recv(LinphoneCore *lc, SalOp *op, SalSubscribeState ss, SalPresenceStatus sal_status){
void linphone_notify_recv(LinphoneCore *lc, SalOp *op, SalSubscribeStatus ss, SalPresenceStatus sal_status){
char *tmp;
LinphoneFriend *lf;
LinphoneAddress *friend=NULL;

View file

@ -74,6 +74,12 @@ struct _LinphoneCallParams{
bool_t pad;
};
typedef struct _CallCallbackObj
{
LinphoneCallCbFunc _func;
void * _user_data;
}CallCallbackObj;
static const int linphone_call_magic=0x3343;
@ -84,6 +90,7 @@ struct _LinphoneCall
SalMediaDescription *localdesc;
SalMediaDescription *resultdesc;
LinphoneCallDir dir;
LinphoneCall *referer; /*when this call is the result of a transfer, referer is set to the original call that caused the transfer*/
struct _RtpProfile *audio_profile;
struct _RtpProfile *video_profile;
struct _LinphoneCallLog *log;
@ -93,6 +100,7 @@ struct _LinphoneCall
time_t start_time; /*time at which the call was initiated*/
time_t media_start_time; /*time at which it was accepted, media streams established*/
LinphoneCallState state;
LinphoneCallState transfer_state; /*idle if no transfer*/
LinphoneReason reason;
int refcnt;
void * user_pointer;
@ -122,6 +130,8 @@ struct _LinphoneCall
bool_t audiostream_encrypted;
bool_t auth_token_verified;
bool_t defer_update;
bool_t was_automatically_paused;
CallCallbackObj nextVideoFrameDecoded;
};
@ -133,6 +143,7 @@ void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const
LinphoneCallLog * linphone_call_log_new(LinphoneCall *call, LinphoneAddress *local, LinphoneAddress * remote);
void linphone_call_log_completed(LinphoneCall *call);
void linphone_call_log_destroy(LinphoneCallLog *cl);
void linphone_call_set_transfer_state(LinphoneCall* call, LinphoneCallState state);
void linphone_auth_info_write_config(struct _LpConfig *config, LinphoneAuthInfo *obj, int pos);
@ -193,7 +204,7 @@ SalPresenceStatus linphone_online_status_to_sal(LinphoneOnlineStatus os);
void linphone_process_authentication(LinphoneCore* lc, SalOp *op);
void linphone_authentication_ok(LinphoneCore *lc, SalOp *op);
void linphone_subscription_new(LinphoneCore *lc, SalOp *op, const char *from);
void linphone_notify_recv(LinphoneCore *lc, SalOp *op, SalSubscribeState ss, SalPresenceStatus status);
void linphone_notify_recv(LinphoneCore *lc, SalOp *op, SalSubscribeStatus ss, SalPresenceStatus status);
void linphone_proxy_config_process_authentication_failure(LinphoneCore *lc, SalOp *op);
void linphone_subscription_answered(LinphoneCore *lc, SalOp *op);
@ -549,6 +560,7 @@ void linphone_call_add_to_conf(LinphoneCall *call, bool_t muted);
void linphone_call_remove_from_conf(LinphoneCall *call);
void linphone_core_conference_check_uninit(LinphoneCore *lc);
bool_t linphone_core_sound_resources_available(LinphoneCore *lc);
void linphone_core_notify_refer_state(LinphoneCore *lc, LinphoneCall *referer, LinphoneCall *newcall);
void __linphone_core_invalidate_registers(LinphoneCore* lc);

View file

@ -134,6 +134,7 @@ typedef struct SalStreamDescription{
SalStreamDir dir;
SalSrtpCryptoAlgo crypto[SAL_CRYPTO_ALGO_MAX];
unsigned int crypto_local_tag;
int max_rate;
} SalStreamDescription;
#define SAL_MEDIA_DESCRIPTION_MAX_STREAMS 4
@ -206,10 +207,16 @@ typedef enum SalPresenceStatus{
SalPresenceAltService,
}SalPresenceStatus;
typedef enum SalSubscribeState{
typedef enum SalReferStatus{
SalReferTrying,
SalReferSuccess,
SalReferFailed
}SalReferStatus;
typedef enum SalSubscribeStatus{
SalSubscribeActive,
SalSubscribeTerminated
}SalSubscribeState;
}SalSubscribeStatus;
typedef void (*SalOnCallReceived)(SalOp *op);
typedef void (*SalOnCallRinging)(SalOp *op);
@ -227,8 +234,9 @@ typedef void (*SalOnVfuRequest)(SalOp *op);
typedef void (*SalOnDtmfReceived)(SalOp *op, char dtmf);
typedef void (*SalOnRefer)(Sal *sal, SalOp *op, const char *referto);
typedef void (*SalOnTextReceived)(Sal *sal, const char *from, const char *msg);
typedef void (*SalOnNotify)(SalOp *op, const char *from, const char *value);
typedef void (*SalOnNotifyPresence)(SalOp *op, SalSubscribeState ss, SalPresenceStatus status, const char *msg);
typedef void (*SalOnNotify)(SalOp *op, const char *from, const char *event);
typedef void (*SalOnNotifyRefer)(SalOp *op, SalReferStatus state);
typedef void (*SalOnNotifyPresence)(SalOp *op, SalSubscribeStatus ss, SalPresenceStatus status, const char *msg);
typedef void (*SalOnSubscribeReceived)(SalOp *salop, const char *from);
typedef void (*SalOnSubscribeClosed)(SalOp *salop, const char *from);
typedef void (*SalOnPingReply)(SalOp *salop);
@ -252,6 +260,7 @@ typedef struct SalCallbacks{
SalOnTextReceived text_received;
SalOnNotify notify;
SalOnNotifyPresence notify_presence;
SalOnNotifyRefer notify_refer;
SalOnSubscribeReceived subscribe_received;
SalOnSubscribeClosed subscribe_closed;
SalOnPingReply ping_reply;
@ -339,6 +348,7 @@ int sal_call_terminate(SalOp *h);
bool_t sal_call_autoanswer_asked(SalOp *op);
void sal_call_send_vfu_request(SalOp *h);
int sal_call_is_offerer(const SalOp *h);
int sal_call_notify_refer_state(SalOp *h, SalOp *newcall);
/*Registration*/
int sal_register(SalOp *op, const char *proxy, const char *from, int expires);

View file

@ -728,6 +728,45 @@ int sal_call_set_referer(SalOp *h, SalOp *refered_call){
return 0;
}
static int send_notify_for_refer(int did, const char *sipfrag){
osip_message_t *msg;
eXosip_lock();
eXosip_call_build_notify(did,EXOSIP_SUBCRSTATE_ACTIVE,&msg);
if (msg==NULL){
eXosip_unlock();
ms_error("Could not build NOTIFY for refer.");
return -1;
}
osip_message_set_content_type(msg,"message/sipfrag");
osip_message_set_header(msg,"Event","refer");
osip_message_set_body(msg,sipfrag,strlen(sipfrag));
eXosip_call_send_request(did,msg);
eXosip_unlock();
return 0;
}
/* currently only support to notify trying and 200Ok*/
int sal_call_notify_refer_state(SalOp *h, SalOp *newcall){
if (newcall==NULL){
/* in progress*/
send_notify_for_refer(h->did,"SIP/2.0 100 Trying\r\n");
}
else if (newcall->cid!=-1){
if (newcall->did==-1){
/* not yet established*/
if (!newcall->terminated){
/* in progress*/
send_notify_for_refer(h->did,"SIP/2.0 100 Trying\r\n");
}
}else{
if (!newcall->terminated){
send_notify_for_refer(h->did,"SIP/2.0 200 Ok\r\n");
}
}
}
return 0;
}
int sal_ping(SalOp *op, const char *from, const char *to){
osip_message_t *options=NULL;
@ -748,26 +787,6 @@ int sal_ping(SalOp *op, const char *from, const char *to){
return -1;
}
int sal_call_accept_refer(SalOp *op){
osip_message_t *msg=NULL;
int err=0;
eXosip_lock();
err = eXosip_call_build_notify(op->did,EXOSIP_SUBCRSTATE_ACTIVE,&msg);
if(msg != NULL)
{
osip_message_set_header(msg,(const char *)"event","refer");
osip_message_set_content_type(msg,"message/sipfrag");
osip_message_set_body(msg,"SIP/2.0 100 Trying",sizeof("SIP/2.0 100 Trying"));
eXosip_call_send_request(op->did,msg);
}
else
{
ms_error("could not get a notify built\n");
}
eXosip_unlock();
return err;
}
int sal_call_refer(SalOp *h, const char *refer_to){
osip_message_t *msg=NULL;
int err=0;
@ -1517,6 +1536,51 @@ static void process_refer(Sal *sal, SalOp *op, eXosip_event_t *ev){
}
}
void process_notify(Sal *sal, eXosip_event_t *ev){
osip_header_t *h=NULL;
char *from=NULL;
SalOp *op=find_op(sal,ev);
osip_message_t *ans=NULL;
ms_message("Receiving NOTIFY request !");
osip_from_to_str(ev->request->from,&from);
osip_message_header_get_byname(ev->request,"Event",0,&h);
if(h){
osip_body_t *body=NULL;
//osip_content_type_t *ct=NULL;
osip_message_get_body(ev->request,0,&body);
//ct=osip_message_get_content_type(ev->request);
if (h->hvalue && strcasecmp(h->hvalue,"refer")==0){
/*special handling of refer events*/
if (body && body->body){
osip_message_t *msg;
osip_message_init(&msg);
if (osip_message_parse_sipfrag(msg,body->body,strlen(body->body))==0){
int code=osip_message_get_status_code(msg);
if (code==100){
sal->callbacks.notify_refer(op,SalReferTrying);
}else if (code==200){
sal->callbacks.notify_refer(op,SalReferSuccess);
}else if (code>=400){
sal->callbacks.notify_refer(op,SalReferFailed);
}
}
osip_message_free(msg);
}
}else{
/*generic handling*/
sal->callbacks.notify(op,from,h->hvalue);
}
}
/*answer that we received the notify*/
eXosip_lock();
eXosip_call_build_answer(ev->tid,200,&ans);
if (ans)
eXosip_call_send_answer(ev->tid,200,ans);
eXosip_unlock();
osip_free(from);
}
static void call_message_new(Sal *sal, eXosip_event_t *ev){
osip_message_t *ans=NULL;
if (ev->request){
@ -1559,22 +1623,7 @@ static void call_message_new(Sal *sal, eXosip_event_t *ev){
ms_message("Receiving REFER request !");
process_refer(sal,op,ev);
}else if(MSG_IS_NOTIFY(ev->request)){
osip_header_t *h=NULL;
char *from=NULL;
SalOp *op=find_op(sal,ev);
ms_message("Receiving NOTIFY request !");
osip_from_to_str(ev->request->from,&from);
osip_message_header_get_byname(ev->request,"Event",0,&h);
if(h)
sal->callbacks.notify(op,from,h->hvalue);
/*answer that we received the notify*/
eXosip_lock();
eXosip_call_build_answer(ev->tid,200,&ans);
if (ans)
eXosip_call_send_answer(ev->tid,200,ans);
eXosip_unlock();
osip_free(from);
process_notify(sal,ev);
}else if (MSG_IS_OPTIONS(ev->request)){
eXosip_lock();
eXosip_call_build_answer(ev->tid,200,&ans);

View file

@ -579,6 +579,28 @@ void linphone_gtk_in_call_view_terminate(LinphoneCall *call, const char *error_m
linphone_gtk_terminate_conference_participant(call);
}
void linphone_gtk_in_call_view_set_transfer_status(LinphoneCall *call,LinphoneCallState cstate){
GtkWidget *callview=(GtkWidget*)linphone_call_get_user_pointer(call);
if (callview){
GtkWidget *duration=linphone_gtk_get_widget(callview,"in_call_duration");
const char *transfer_status="unknown";
switch(cstate){
case LinphoneCallOutgoingProgress:
transfer_status=_("Transfer in progress");
break;
case LinphoneCallConnected:
transfer_status=_("Transfer done.");
break;
case LinphoneCallError:
transfer_status=_("Transfer failed.");
break;
default:
break;
}
gtk_label_set_text(GTK_LABEL(duration),transfer_status);
}
}
void linphone_gtk_draw_mute_button(GtkButton *button, gboolean active){
g_object_set_data(G_OBJECT(button),"active",GINT_TO_POINTER(active));
if (active){

View file

@ -107,6 +107,7 @@ void linphone_gtk_in_call_view_update_duration(LinphoneCall *call);
void linphone_gtk_in_call_view_terminate(LinphoneCall *call, const char *error_msg);
void linphone_gtk_in_call_view_set_incoming(LinphoneCall *call);
void linphone_gtk_in_call_view_set_paused(LinphoneCall *call);
void linphone_gtk_in_call_view_set_transfer_status(LinphoneCall *call,LinphoneCallState cstate);
void linphone_gtk_mute_clicked(GtkButton *button);
void linphone_gtk_enable_mute_button(GtkButton *button, gboolean sensitive);
void linphone_gtk_enable_hold_button(LinphoneCall *call, gboolean sensitive, gboolean holdon);

View file

@ -63,6 +63,7 @@ static void linphone_gtk_display_url(LinphoneCore *lc, const char *msg, const ch
static void linphone_gtk_call_log_updated(LinphoneCore *lc, LinphoneCallLog *cl);
static void linphone_gtk_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cs, const char *msg);
static void linphone_gtk_call_encryption_changed(LinphoneCore *lc, LinphoneCall *call, bool_t enabled, const char *token);
static void linphone_gtk_transfer_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate);
static gboolean linphone_gtk_auto_answer(LinphoneCall *call);
static void linphone_gtk_status_icon_set_blinking(gboolean val);
@ -225,6 +226,7 @@ static void linphone_gtk_init_liblinphone(const char *config_file,
vtable.refer_received=linphone_gtk_refer_received;
vtable.buddy_info_updated=linphone_gtk_buddy_info_updated;
vtable.call_encryption_changed=linphone_gtk_call_encryption_changed;
vtable.transfer_state_changed=linphone_gtk_transfer_state_changed;
linphone_core_set_user_agent("Linphone", LINPHONE_VERSION);
the_core=linphone_core_new(&vtable,config_file,factory_config_file,NULL);
@ -1133,6 +1135,10 @@ static void linphone_gtk_call_encryption_changed(LinphoneCore *lc, LinphoneCall
linphone_gtk_in_call_view_show_encryption(call);
}
static void linphone_gtk_transfer_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate){
linphone_gtk_in_call_view_set_transfer_status(call,cstate);
}
static void update_registration_status(LinphoneProxyConfig *cfg, LinphoneRegistrationState rs){
GtkComboBox *box=GTK_COMBO_BOX(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"identities"));
GtkTreeModel *model=gtk_combo_box_get_model(box);

View file

@ -11,7 +11,7 @@
Name: linphone
Version: @VERSION@
Release: %(git describe --tags | sed 's/.*-\([0-9]*\)-g.*/\1/' || echo '1')%{?dist}
Release: %(git describe --tags --abbrev=40 | sed -rn 's/^.*-([0-9]+)-g[a-z0-9]{40}$/\1/p' || echo '1')%{?dist}
Summary: Phone anywhere in the whole world by using the Internet
Group: Applications/Communications
@ -27,7 +27,7 @@ BuildRequires: gtk2-devel
BuildRequires: libeXosip2-devel speex-devel gettext
BuildRequires: intltool gettext-devel
%if %{video}
BuildRequires: ffmpeg-devel SDL-devel
BuildRequires: ffmpeg-devel SDL-devel
%endif
%description
@ -35,12 +35,12 @@ Linphone is a SIP compliant audio & video phone. It can be used to run calls
over the internet. It has a gtk+ and console interface.
%package devel
Summary: Development libraries for linphone
Group: Development/Libraries
Requires: %{name} = %{version}-%{release}
Requires: ortp-devel = @ORTP_VERSION@
Requires: mediastreamer2-devel = @MS2_VERSION@
Requires: glib2-devel
Summary: Development libraries for linphone
Group: Development/Libraries
Requires: %{name} = %{version}-%{release}
Requires: ortp-devel = @ORTP_VERSION@
Requires: mediastreamer-devel = @MS2_VERSION@
Requires: glib2-devel
%description devel
Libraries and headers required to develop software with linphone.

@ -1 +1 @@
Subproject commit 33599a544a23878604cd42a769c1044d599c1347
Subproject commit 3870493e9a59ddf7858cf4628dd86ec7a8b469d8

2
oRTP

@ -1 +1 @@
Subproject commit 3fb614e2ed15803f2c96c223cceb5545a60f2431
Subproject commit 04570bd7a02f9baa682c4667fbba16e8c951b62b