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

This commit is contained in:
Ghislain MARY 2012-09-17 15:13:50 +02:00
commit 0c146ef59d
55 changed files with 1337 additions and 1245 deletions

View file

@ -16,6 +16,7 @@ You need:
$ port install libeXosip2 #WARNING: currently outdated in macport
$ port install ffmpeg-devel
$ port install libvpx
$ port install readline
- Install srtp (optional) for call encryption
$ port install srtp

View file

@ -26,11 +26,13 @@ include $(CLEAR_VARS)
include $(linphone-root-dir)/submodules/linphone/build/android/common.mk
ifeq ($(LINPHONE_VIDEO),1)
LOCAL_SHARED_LIBRARIES += \
libavcodecnoneon \
libswscale \
libavcore \
libavutil
endif
LOCAL_MODULE := liblinphonenoneon
ifeq ($(TARGET_ARCH_ABI),armeabi)

View file

@ -26,11 +26,13 @@ include $(CLEAR_VARS)
include $(linphone-root-dir)/submodules/linphone/build/android/common.mk
ifeq ($(LINPHONE_VIDEO),1)
LOCAL_SHARED_LIBRARIES += \
libavcodec \
libswscale \
libavcore \
libavutil
endif
LOCAL_MODULE := liblinphone

View file

@ -59,6 +59,7 @@ LOCAL_CFLAGS += \
-DORTP_INET6 \
-DINET6 \
-DOSIP_MT \
-DHAVE_EXOSIP_RESET_TRANSPORTS \
-DENABLE_TRACE \
-DLINPHONE_VERSION=\"$(LINPHONE_VERSION)\" \
-DLINPHONE_PLUGINS_DIR=\"\\tmp\" \

View file

@ -502,7 +502,7 @@ AS_CASE($enable_external_mediastreamer,
AC_CONFIG_SUBDIRS( mediastreamer2 )
MEDIASTREAMER_DIR=${top_srcdir}/mediastreamer2
MEDIASTREAMER_CFLAGS="-I\$(top_srcdir)/mediastreamer2/include"
MEDIASTREAMER_LIBS="\$(top_builddir)/mediastreamer2/src/libmediastreamer.la"
MEDIASTREAMER_LIBS="\$(top_builddir)/mediastreamer2/src/libmediastreamer_base.la \$(top_builddir)/mediastreamer2/src/libmediastreamer_voip.la"
dnl need to temporary change quotes to allow square brackets
changequote(<<, >>)
MS2_VERSION=`grep -e '^.C_INIT(' $MEDIASTREAMER_DIR/configure.ac | sed -e 's:\([^(]\+\)(\[mediastreamer\],\[\(.*\)\]):\2:g'`

View file

@ -732,9 +732,12 @@ static void refer_received(Sal *sal, SalOp *op, const char *referto){
static void text_received(Sal *sal, const char *from, const char *msg){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal);
linphone_core_text_received(lc,from,msg);
linphone_core_message_received(lc,from,msg,NULL);
}
void message_external_body_received(Sal *sal, const char *from, const char *url) {
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal);
linphone_core_message_received(lc,from,NULL,url);
}
static void notify(SalOp *op, const char *from, const char *msg){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer (op);
@ -801,6 +804,28 @@ static void notify_refer(SalOp *op, SalReferStatus status){
}
}
static LinphoneChatMessageState chatStatusSal2Linphone(SalTextDeliveryStatus status){
switch(status){
case SalTextDeliveryInProgress:
return LinphoneChatMessageStateInProgress;
case SalTextDeliveryDone:
return LinphoneChatMessageStateDelivered;
case SalTextDeliveryFailed:
return LinphoneChatMessageStateNotDelivered;
}
return LinphoneChatMessageStateIdle;
}
static void text_delivery_update(SalOp *op, SalTextDeliveryStatus status){
LinphoneChatMessage *chat_msg=(LinphoneChatMessage* )sal_op_get_user_pointer(op);
if (chat_msg && chat_msg->cb) {
chat_msg->cb(chat_msg
,chatStatusSal2Linphone(status)
,chat_msg->cb_ud);
}
linphone_chat_message_destroy(chat_msg);
}
SalCallbacks linphone_sal_callbacks={
call_received,
call_ringing,
@ -818,12 +843,14 @@ SalCallbacks linphone_sal_callbacks={
dtmf_received,
refer_received,
text_received,
message_external_body_received,
text_delivery_update,
notify,
notify_presence,
notify_refer,
subscribe_received,
subscribe_closed,
ping_reply
ping_reply,
};

View file

@ -55,6 +55,7 @@ static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatM
const char *identity=linphone_core_find_best_identity(cr->lc,cr->peer_url,&route);
SalOp *op=NULL;
LinphoneCall *call;
char* content_type;
if((call = linphone_core_get_call_by_remote_address(cr->lc,cr->peer))!=NULL){
if (call->state==LinphoneCallConnected ||
call->state==LinphoneCallStreamsRunning ||
@ -77,7 +78,15 @@ static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatM
cr->op=op;
sal_op_set_user_pointer(op, msg); /*if out of call, directly store msg*/
}
sal_text_send(op,identity,cr->peer,msg->message);
if (msg->external_body_url) {
content_type=ms_strdup_printf("message/external-body; access-type=URL; URL=\"%s\"",msg->external_body_url);
sal_message_send(op,identity,cr->peer,content_type,NULL);
ms_free(content_type);
} else {
sal_text_send(op, identity, cr->peer, msg->message);
}
}
void linphone_chat_room_send_message(LinphoneChatRoom *cr, const char *msg) {
@ -89,16 +98,20 @@ bool_t linphone_chat_room_matches(LinphoneChatRoom *cr, const LinphoneAddress *f
return FALSE;
}
void linphone_chat_room_text_received(LinphoneChatRoom *cr, LinphoneCore *lc, const LinphoneAddress *from, const char *msg){
if (lc->vtable.text_received!=NULL) lc->vtable.text_received(lc, cr, from, msg);
void linphone_chat_room_message_received(LinphoneChatRoom *cr, LinphoneCore *lc, LinphoneChatMessage *msg){
if (msg->message)
//legacy API
if (lc->vtable.text_received!=NULL) lc->vtable.text_received(lc, cr, msg->from, msg->message);
if (lc->vtable.message_received!=NULL) lc->vtable.message_received(lc, cr,msg);
}
void linphone_core_text_received(LinphoneCore *lc, const char *from, const char *msg){
void linphone_core_message_received(LinphoneCore *lc, const char *from, const char *raw_msg,const char* external_url){
MSList *elem;
LinphoneChatRoom *cr=NULL;
LinphoneAddress *addr;
char *cleanfrom;
LinphoneChatMessage* msg;
addr=linphone_address_new(from);
linphone_address_clean(addr);
for(elem=lc->chatrooms;elem!=NULL;elem=ms_list_next(elem)){
@ -113,12 +126,23 @@ void linphone_core_text_received(LinphoneCore *lc, const char *from, const char
/* create a new chat room */
cr=linphone_core_create_chat_room(lc,cleanfrom);
}
msg = linphone_chat_room_create_message(cr, raw_msg);
linphone_chat_message_set_from(msg, cr->peer_url);
if (external_url) {
linphone_chat_message_set_external_body_url(msg, external_url);
}
linphone_address_destroy(addr);
linphone_chat_room_text_received(cr,lc,cr->peer_url,msg);
linphone_chat_room_message_received(cr,lc,msg);
ms_free(cleanfrom);
}
LinphoneCore* linphone_chat_room_get_lc(LinphoneChatRoom *cr){
return cr->lc;
}
LinphoneChatRoom* linphone_chat_message_get_chat_room(LinphoneChatMessage *msg){
return msg->chat_room;
}
void linphone_chat_room_set_user_data(LinphoneChatRoom *cr, void * ud){
cr->user_data=ud;
@ -133,13 +157,17 @@ const LinphoneAddress* linphone_chat_room_get_peer_address(LinphoneChatRoom *cr)
LinphoneChatMessage* linphone_chat_room_create_message(const LinphoneChatRoom *cr,const char* message) {
LinphoneChatMessage* msg = ms_new0(LinphoneChatMessage,1);
msg->chat_room=(LinphoneChatRoom*)cr;
msg->message=ms_strdup(message);
msg->message=message?ms_strdup(message):NULL;
return msg;
}
void linphone_chat_message_destroy(LinphoneChatMessage* msg) {
if (msg->message) ms_free((void*)msg->message);
ms_free((void*)msg);
if (msg->message) ms_free(msg->message);
if (msg->external_body_url) ms_free(msg->external_body_url);
if (msg->from) linphone_address_destroy(msg->from);
ms_free(msg);
}
void linphone_chat_room_send_message2(LinphoneChatRoom *cr, LinphoneChatMessage* msg,LinphoneChatMessageStateChangeCb status_cb,void* ud) {
msg->cb=status_cb;
msg->cb_ud=ud;
@ -156,6 +184,15 @@ const char* linphone_chat_message_state_to_string(const LinphoneChatMessageState
}
}
char* linphone_chat_message_get_message(LinphoneChatMessage* msg) {
return msg->message;
}
const LinphoneAddress* linphone_chat_message_get_peer_address(LinphoneChatMessage *msg) {
return linphone_chat_room_get_peer_address(msg->chat_room);
}
/**
* user pointer set function
*/
@ -167,4 +204,45 @@ void linphone_chat_message_set_user_data(LinphoneChatMessage* message,void* ud)
*/
void* linphone_chat_message_get_user_data(const LinphoneChatMessage* message) {
return message->message_userdata;
}
const char* linphone_chat_message_get_external_body_url(const LinphoneChatMessage* message) {
return message->external_body_url;
}
void linphone_chat_message_set_external_body_url(LinphoneChatMessage* message,const char* url) {
if (message->external_body_url) {
ms_free(message->external_body_url);
}
message->external_body_url=url?ms_strdup(url):NULL;
}
void linphone_chat_message_set_from(LinphoneChatMessage* message, const LinphoneAddress* from) {
if(message->from) linphone_address_destroy(message->from);
message->from=linphone_address_clone(from);
}
LinphoneAddress* linphone_chat_message_get_from(const LinphoneChatMessage* message) {
return message->from;
}
const char * linphone_chat_message_get_text(const LinphoneChatMessage* message) {
return message->message;
}
LinphoneChatMessage* linphone_chat_message_clone(const LinphoneChatMessage* msg) {
/*struct _LinphoneChatMessage {
char* message;
LinphoneChatRoom* chat_room;
LinphoneChatMessageStateChangeCb cb;
void* cb_ud;
void* message_userdata;
char* external_body_url;
LinphoneAddress* from;
};*/
LinphoneChatMessage* new_message = linphone_chat_room_create_message(msg->chat_room,msg->message);
if (msg->external_body_url) new_message->external_body_url=ms_strdup(msg->external_body_url);
new_message->cb=msg->cb;
new_message->cb_ud=msg->cb_ud;
new_message->message_userdata=msg->message_userdata;
new_message->cb=msg->cb;
if (msg->from) new_message->from=linphone_address_clone(msg->from);
return new_message;
}

View file

@ -207,7 +207,10 @@ static SalMediaDescription *_create_local_media_description(LinphoneCore *lc, Li
md->nstreams=1;
strncpy(md->addr,call->localip,sizeof(md->addr));
strncpy(md->username,username,sizeof(md->username));
md->bandwidth=linphone_core_get_download_bandwidth(lc);
if (call->params.down_bw)
md->bandwidth=call->params.down_bw;
else md->bandwidth=linphone_core_get_download_bandwidth(lc);
/*set audio capabilities */
strncpy(md->streams[0].rtp_addr,call->localip,sizeof(md->streams[0].rtp_addr));
@ -217,7 +220,10 @@ static SalMediaDescription *_create_local_media_description(LinphoneCore *lc, Li
md->streams[0].proto=(call->params.media_encryption == LinphoneMediaEncryptionSRTP) ?
SalProtoRtpSavp : SalProtoRtpAvp;
md->streams[0].type=SalAudio;
md->streams[0].ptime=lc->net_conf.down_ptime;
if (call->params.down_ptime)
md->streams[0].ptime=call->params.down_ptime;
else
md->streams[0].ptime=linphone_core_get_download_ptime(lc);
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);
@ -318,6 +324,22 @@ void linphone_call_init_stats(LinphoneCallStats *stats, int type) {
stats->type = type;
stats->received_rtcp = NULL;
stats->sent_rtcp = NULL;
stats->ice_state = LinphoneIceStateNotActivated;
}
static void update_media_description_from_stun(SalMediaDescription *md, const StunCandidate *ac, const StunCandidate *vc){
if (ac->port!=0){
strcpy(md->streams[0].rtp_addr,ac->addr);
md->streams[0].rtp_port=ac->port;
if ((ac->addr[0]!='\0' && vc->addr[0]!='\0' && strcmp(ac->addr,vc->addr)==0) || md->nstreams==1){
strcpy(md->addr,ac->addr);
}
}
if (vc->port!=0){
strcpy(md->streams[1].rtp_addr,vc->addr);
md->streams[1].rtp_port=vc->port;
}
}
static void discover_mtu(LinphoneCore *lc, const char *remote){
@ -333,9 +355,13 @@ static void discover_mtu(LinphoneCore *lc, const char *remote){
}
}
#define STUN_CANDIDATE_INIT {{0},0}
LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, const LinphoneCallParams *params)
{
LinphoneCall *call=ms_new0(LinphoneCall,1);
StunCandidate ac=STUN_CANDIDATE_INIT,vc=STUN_CANDIDATE_INIT;
int ping_time=-1;
call->dir=LinphoneCallOutgoing;
call->op=sal_op_new(lc->sal);
sal_op_set_user_pointer(call->op,call);
@ -347,11 +373,16 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr
call->ice_session = ice_session_new();
ice_session_set_role(call->ice_session, IR_Controlling);
}
call->localdesc=create_local_media_description (lc,call);
call->camera_active=params->has_video;
if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseStun) {
linphone_core_run_stun_tests(call->core,call);
ping_time=linphone_core_run_stun_tests(call->core,call,&ac, &vc);
}
if (ping_time>=0) {
linphone_core_adapt_to_network(lc,ping_time,&call->params);
}
call->localdesc=create_local_media_description(lc,call);
update_media_description_from_stun(call->localdesc,&ac,&vc);
call->camera_active=params->has_video;
discover_mtu(lc,linphone_address_get_domain (to));
if (params->referer){
sal_call_set_referer(call->op,params->referer->op);
@ -363,6 +394,8 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr
LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, SalOp *op){
LinphoneCall *call=ms_new0(LinphoneCall,1);
char *from_str;
int ping_time=-1;
StunCandidate ac=STUN_CANDIDATE_INIT,vc=STUN_CANDIDATE_INIT;
call->dir=LinphoneCallIncoming;
sal_op_set_user_pointer(op,call);
@ -385,8 +418,6 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro
linphone_call_init_common(call, from, to);
linphone_core_init_default_params(lc, &call->params);
call->params.has_video &= !!lc->video_policy.automatically_accept;
call->localdesc=create_local_media_description (lc,call);
call->camera_active=call->params.has_video;
switch (linphone_core_get_firewall_policy(call->core)) {
case LinphonePolicyUseIce:
call->ice_session = ice_session_new();
@ -403,11 +434,18 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro
}
break;
case LinphonePolicyUseStun:
linphone_core_run_stun_tests(call->core,call);
ping_time=linphone_core_run_stun_tests(call->core,call,&ac, &vc);
/* No break to also destroy ice session in this case. */
default:
break;
}
if (ping_time>=0) {
linphone_core_adapt_to_network(lc,ping_time,&call->params);
};
call->localdesc=create_local_media_description(lc,call);
update_media_description_from_stun(call->localdesc,&ac,&vc);
call->camera_active=call->params.has_video;
discover_mtu(lc,linphone_address_get_domain(from));
return call;
}
@ -521,7 +559,7 @@ void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const
switch(call->reason){
case LinphoneReasonDeclined:
call->log->status=LinphoneCallDeclined;
break;
break;
case LinphoneReasonNotAnswered:
call->log->status=LinphoneCallMissed;
break;
@ -936,11 +974,10 @@ void linphone_call_set_next_video_frame_decoded_callback(LinphoneCall *call, Lin
void linphone_call_init_audio_stream(LinphoneCall *call){
LinphoneCore *lc=call->core;
SalMediaDescription *md=call->localdesc;
AudioStream *audiostream;
int dscp=lp_config_get_int(lc->config,"rtp","audio_dscp",-1);
int dscp=linphone_core_get_audio_dscp(lc);
call->audiostream=audiostream=audio_stream_new(md->streams[0].rtp_port,md->streams[0].rtcp_port,linphone_core_ipv6_enabled(lc));
call->audiostream=audiostream=audio_stream_new(call->audio_port,call->audio_port+1,linphone_core_ipv6_enabled(lc));
if (dscp!=-1)
audio_stream_set_dscp(audiostream,dscp);
if (linphone_core_echo_limiter_enabled(lc)){
@ -989,13 +1026,12 @@ void linphone_call_init_audio_stream(LinphoneCall *call){
void linphone_call_init_video_stream(LinphoneCall *call){
#ifdef VIDEO_ENABLED
LinphoneCore *lc=call->core;
SalMediaDescription *md=call->localdesc;
if ((lc->video_conf.display || lc->video_conf.capture) && md->streams[1].rtp_port>0){
if ((lc->video_conf.display || lc->video_conf.capture) && call->params.has_video){
int video_recv_buf_size=lp_config_get_int(lc->config,"video","recv_buf_size",0);
int dscp=lp_config_get_int(lc->config,"rtp","video_dscp",-1);
int dscp=linphone_core_get_video_dscp(lc);
call->videostream=video_stream_new(md->streams[1].rtp_port,md->streams[1].rtcp_port,linphone_core_ipv6_enabled(lc));
call->videostream=video_stream_new(call->video_port,call->video_port+1,linphone_core_ipv6_enabled(lc));
if (dscp!=-1)
video_stream_set_dscp(call->videostream,dscp);
video_stream_enable_display_filter_auto_rotate(call->videostream, lp_config_get_int(lc->config,"video","display_filter_auto_rotate",0));
@ -1137,6 +1173,7 @@ static RtpProfile *make_profile(LinphoneCall *call, const SalMediaDescription *m
int remote_bw=0;
LinphoneCore *lc=call->core;
int up_ptime=0;
const LinphoneCallParams *params=&call->params;
*used_pt=-1;
for(elem=desc->payloads;elem!=NULL;elem=elem->next){
@ -1146,7 +1183,9 @@ static RtpProfile *make_profile(LinphoneCall *call, const SalMediaDescription *m
if ((pt->flags & PAYLOAD_TYPE_FLAG_CAN_SEND) && first) {
if (desc->type==SalAudio){
linphone_core_update_allocated_audio_bandwidth_in_call(call,pt);
up_ptime=linphone_core_get_upload_ptime(lc);
if (params->up_ptime)
up_ptime=params->up_ptime;
else up_ptime=linphone_core_get_upload_ptime(lc);
}
*used_pt=payload_type_get_number(pt);
first=FALSE;
@ -1161,7 +1200,12 @@ static RtpProfile *make_profile(LinphoneCall *call, const SalMediaDescription *m
}
if (desc->type==SalAudio){
bw=get_min_bandwidth(call->audio_bw,remote_bw);
int audio_bw=call->audio_bw;
if (params->up_bw){
if (params->up_bw< audio_bw)
audio_bw=params->up_bw;
}
bw=get_min_bandwidth(audio_bw,remote_bw);
}else bw=get_min_bandwidth(get_video_bandwidth(linphone_core_get_upload_bandwidth (lc),call->audio_bw),remote_bw);
if (bw>0) pt->normal_bitrate=bw*1000;
else if (desc->type==SalAudio){
@ -1498,6 +1542,8 @@ void linphone_call_delete_ice_session(LinphoneCall *call){
call->ice_session = NULL;
if (call->audiostream != NULL) call->audiostream->ice_check_list = NULL;
if (call->videostream != NULL) call->videostream->ice_check_list = NULL;
call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateNotActivated;
call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateNotActivated;
}
}
@ -1723,6 +1769,7 @@ static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){
if (ice_session_role(call->ice_session) == IR_Controlling) {
ice_session_select_candidates(call->ice_session);
linphone_core_update_call(call->core, call, &call->current_params);
linphone_core_update_ice_state_in_call_stats(call);
}
break;
case IS_Failed:
@ -1731,6 +1778,7 @@ static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){
/* At least one ICE session has succeeded, so perform a call update. */
ice_session_select_candidates(call->ice_session);
linphone_core_update_call(call->core, call, &call->current_params);
linphone_core_update_ice_state_in_call_stats(call);
}
}
break;
@ -1738,11 +1786,17 @@ static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){
break;
}
} else if (evt == ORTP_EVENT_ICE_GATHERING_FINISHED) {
int ping_time = -1;
if (evd->info.ice_processing_successful==TRUE) {
ice_session_compute_candidates_foundations(call->ice_session);
ice_session_eliminate_redundant_candidates(call->ice_session);
ice_session_choose_default_candidates(call->ice_session);
ping_time = ice_session_gathering_duration(call->ice_session);
if (ping_time >=0) {
ping_time /= ice_session_nb_check_lists(call->ice_session);
}
} else {
ms_warning("No STUN answer from [%s], disabling ICE",linphone_core_get_stun_server(call->core));
linphone_call_delete_ice_session(call);
}
switch (call->state) {
@ -1753,10 +1807,16 @@ static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){
linphone_core_start_accept_call_update(call->core, call);
break;
case LinphoneCallOutgoingInit:
if (ping_time >= 0) {
linphone_core_adapt_to_network(call->core, ping_time, &call->params);
}
linphone_call_stop_media_streams(call);
linphone_core_proceed_with_invite_if_ready(call->core, call, NULL);
break;
default:
if (ping_time >= 0) {
linphone_core_adapt_to_network(call->core, ping_time, &call->params);
}
linphone_call_stop_media_streams(call);
linphone_core_notify_incoming_call(call->core, call);
break;

View file

@ -615,6 +615,7 @@ static void sip_config_read(LinphoneCore *lc)
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));
sal_set_dscp(lc->sal,linphone_core_get_sip_dscp(lc));
}
static void rtp_config_read(LinphoneCore *lc)
@ -967,14 +968,14 @@ int linphone_core_get_upload_bandwidth(const LinphoneCore *lc){
* Set audio packetization time linphone expects to receive from peer
*/
void linphone_core_set_download_ptime(LinphoneCore *lc, int ptime) {
lc->net_conf.down_ptime=ptime;
lp_config_set_int(lc->config,"rtp","download_ptime",ptime);
}
/**
* Get audio packetization time linphone expects to receive from peer
*/
int linphone_core_get_download_ptime(LinphoneCore *lc) {
return lc->net_conf.down_ptime;
return lp_config_get_int(lc->config,"rtp","download_ptime",0);
}
/**
@ -1903,7 +1904,8 @@ void linphone_core_iterate(LinphoneCore *lc){
if (call->state==LinphoneCallOutgoingInit && (curtime-call->start_time>=2)){
/*start the call even if the OPTIONS reply did not arrive*/
if (call->ice_session != NULL) {
/* ICE candidates gathering has not finished yet, proceed with the call without ICE anyway. */
ms_warning("ICE candidates gathering from [%s] has not finished yet, proceed with the call without ICE anyway."
,linphone_core_get_stun_server(lc));
linphone_call_delete_ice_session(call);
linphone_call_stop_media_streams(call);
}
@ -3650,6 +3652,8 @@ void linphone_core_set_stun_server(LinphoneCore *lc, const char *server){
if (server)
lc->net_conf.stun_server=ms_strdup(server);
else lc->net_conf.stun_server=NULL;
if (linphone_core_ready(lc))
lp_config_set_string(lc->config,"net","stun_server",lc->net_conf.stun_server);
}
const char * linphone_core_get_stun_server(const LinphoneCore *lc){
@ -3714,6 +3718,8 @@ const char *linphone_core_get_nat_address_resolved(LinphoneCore *lc)
void linphone_core_set_firewall_policy(LinphoneCore *lc, LinphoneFirewallPolicy pol){
lc->net_conf.firewall_policy=pol;
if (lc->sip_conf.contact) update_primary_contact(lc);
if (linphone_core_ready(lc))
lp_config_set_int(lc->config,"net","firewall_policy",pol);
}
LinphoneFirewallPolicy linphone_core_get_firewall_policy(const LinphoneCore *lc){
@ -3866,6 +3872,8 @@ const LinphoneVideoPolicy *linphone_core_get_video_policy(LinphoneCore *lc){
**/
void linphone_core_enable_video_preview(LinphoneCore *lc, bool_t val){
lc->video_conf.show_local=val;
if (linphone_core_ready(lc))
lp_config_set_int(lc->config,"video","show_local",val);
}
/**
@ -3891,6 +3899,9 @@ void linphone_core_enable_self_view(LinphoneCore *lc, bool_t val){
if (call && call->videostream){
video_stream_enable_self_view(call->videostream,val);
}
if (linphone_core_ready(lc)){
lp_config_set_int(lc->config,"video","self_view",val);
}
#endif
}
@ -4447,7 +4458,6 @@ void net_config_uninit(LinphoneCore *lc)
net_config_t *config=&lc->net_conf;
if (config->stun_server!=NULL){
lp_config_set_string(lc->config,"net","stun_server",config->stun_server);
ms_free(lc->net_conf.stun_server);
}
if (config->nat_address!=NULL){
@ -4457,7 +4467,6 @@ void net_config_uninit(LinphoneCore *lc)
if (lc->net_conf.nat_address_ip !=NULL){
ms_free(lc->net_conf.nat_address_ip);
}
lp_config_set_int(lc->config,"net","firewall_policy",config->firewall_policy);
lp_config_set_int(lc->config,"net","mtu",config->mtu);
}
@ -4525,7 +4534,7 @@ void rtp_config_uninit(LinphoneCore *lc)
lp_config_set_int(lc->config,"rtp","video_jitt_comp_enabled",config->video_adaptive_jitt_comp_enabled);
}
void sound_config_uninit(LinphoneCore *lc)
static void sound_config_uninit(LinphoneCore *lc)
{
sound_config_t *config=&lc->sound_conf;
ms_free(config->cards);
@ -4537,13 +4546,11 @@ void sound_config_uninit(LinphoneCore *lc)
ms_snd_card_manager_destroy();
}
void video_config_uninit(LinphoneCore *lc)
static void video_config_uninit(LinphoneCore *lc)
{
lp_config_set_string(lc->config,"video","size",video_size_get_name(linphone_core_get_preferred_video_size(lc)));
lp_config_set_int(lc->config,"video","display",lc->video_conf.display);
lp_config_set_int(lc->config,"video","capture",lc->video_conf.capture);
lp_config_set_int(lc->config,"video","show_local",linphone_core_video_preview_enabled(lc));
lp_config_set_int(lc->config,"video","self_view",linphone_core_self_view_enabled(lc));
if (lc->video_conf.cams)
ms_free(lc->video_conf.cams);
}
@ -5104,3 +5111,81 @@ void linphone_call_zoom_video(LinphoneCall* call, float zoom_factor, float* cx,
}else ms_warning("Could not apply zoom: video output wasn't activated.");
}
void linphone_core_set_device_identifier(LinphoneCore *lc,const char* device_id) {
if (lc->device_id) ms_free(lc->device_id);
lc->device_id=ms_strdup(device_id);
}
const char* linphone_core_get_device_identifier(const LinphoneCore *lc) {
return lc->device_id;
}
/**
* Set the DSCP field for SIP signaling channel.
*
* @ingroup network_parameters
* * The DSCP defines the quality of service in IP packets.
*
**/
void linphone_core_set_sip_dscp(LinphoneCore *lc, int dscp){
sal_set_dscp(lc->sal,dscp);
if (linphone_core_ready(lc))
lp_config_set_int_hex(lc->config,"sip","dscp",dscp);
}
/**
* Get the DSCP field for SIP signaling channel.
*
* @ingroup network_parameters
* * The DSCP defines the quality of service in IP packets.
*
**/
int linphone_core_get_sip_dscp(const LinphoneCore *lc){
return lp_config_get_int(lc->config,"sip","dscp",0x1a);
}
/**
* Set the DSCP field for outgoing audio streams.
*
* @ingroup network_parameters
* The DSCP defines the quality of service in IP packets.
*
**/
void linphone_core_set_audio_dscp(LinphoneCore *lc, int dscp){
if (linphone_core_ready(lc))
lp_config_set_int_hex(lc->config,"rtp","audio_dscp",dscp);
}
/**
* Get the DSCP field for outgoing audio streams.
*
* @ingroup network_parameters
* The DSCP defines the quality of service in IP packets.
*
**/
int linphone_core_get_audio_dscp(const LinphoneCore *lc){
return lp_config_get_int(lc->config,"rtp","audio_dscp",0x2e);
}
/**
* Set the DSCP field for outgoing video streams.
*
* @ingroup network_parameters
* The DSCP defines the quality of service in IP packets.
*
**/
void linphone_core_set_video_dscp(LinphoneCore *lc, int dscp){
if (linphone_core_ready(lc))
lp_config_set_int_hex(lc->config,"rtp","video_dscp",dscp);
}
/**
* Get the DSCP field for outgoing video streams.
*
* @ingroup network_parameters
* The DSCP defines the quality of service in IP packets.
*
**/
int linphone_core_get_video_dscp(const LinphoneCore *lc){
return lp_config_get_int(lc->config,"rtp","video_dscp",0x2e);
}

View file

@ -261,6 +261,24 @@ typedef struct _LinphoneCall LinphoneCall;
#define LINPHONE_CALL_STATS_AUDIO 0
#define LINPHONE_CALL_STATS_VIDEO 1
/**
* Enum describing ICE states.
* @ingroup initializing
**/
enum _LinphoneIceState{
LinphoneIceStateNotActivated, /**< ICE has not been activated for this call */
LinphoneIceStateInProgress, /**< ICE process is in progress */
LinphoneIceStateHostConnection, /**< ICE has established a direct connection to the remote host */
LinphoneIceStateReflexiveConnection, /**< ICE has established a connection to the remote host through one or several NATs */
LinphoneIceStateRelayConnection /**< ICE has established a connection through a relay */
};
/**
* Enum describing Ice states.
* @ingroup initializing
**/
typedef enum _LinphoneIceState LinphoneIceState;
/**
* The LinphoneCallStats objects carries various statistic informations regarding quality of audio or video streams.
*
@ -285,6 +303,7 @@ struct _LinphoneCallStats {
mblk_t* received_rtcp; /**<Last RTCP packet received, as a mblk_t structure. See oRTP documentation for details how to extract information from it*/
mblk_t* sent_rtcp;/**<Last RTCP packet sent, as a mblk_t structure. See oRTP documentation for details how to extract information from it*/
float round_trip_delay; /**<Round trip propagation time in seconds if known, -1 if unknown.*/
LinphoneIceState ice_state; /**< State of ICE processing. */
};
/**
@ -617,7 +636,6 @@ void linphone_chat_room_destroy(LinphoneChatRoom *cr);
*/
LinphoneChatMessage* linphone_chat_room_create_message(const LinphoneChatRoom *cr,const char* message);
/**
* get peer address \link linphone_core_create_chat_room() associated to \endlink this #LinphoneChatRoom
@ -641,18 +659,61 @@ typedef enum _LinphoneChatMessageStates {
LinphoneChatMessageStateNotDelivered /** message was not delivered*/
}LinphoneChatMessageState;
/**
* to string function
*/
const char* linphone_chat_message_state_to_string(const LinphoneChatMessageState state);
/**
* clone a chat message
*@param message #LinphoneChatMessage obj
*@return #LinphoneChatMessage
*/
LinphoneChatMessage* linphone_chat_message_clone(const LinphoneChatMessage* message);
/**
* set origine of the message
*@param message #LinphoneChatMessage obj
*@param from #LinphoneAddress origin of this message (copied)
*/
void linphone_chat_message_set_from(LinphoneChatMessage* message, const LinphoneAddress* from);
/**
* get origine of the message
*@param message #LinphoneChatMessage obj
*@return #LinphoneAddress
*/
LinphoneAddress* linphone_chat_message_get_from(const LinphoneChatMessage* message);
/**
* Linphone message can carry external body as defined by rfc2017
* @param message #LinphoneChatMessage
* @return return external body url null if not present.
*/
const char* linphone_chat_message_get_external_body_url(const LinphoneChatMessage* message);
/**
* Linphone message can carry external body as defined by rfc2017
*
* @param #LinphoneChatMessage
* @param url ex: access-type=URL; URL="http://www.foo.com/file"
*/
void linphone_chat_message_set_external_body_url(LinphoneChatMessage* message,const char* url);
/**
* get text part of this message
*@return text or NULL if no text.
*/
const char * linphone_chat_message_get_text(const LinphoneChatMessage* message);
/**
* user pointer get function
*/
void* linphone_chat_message_get_user_data(const LinphoneChatMessage* message);
/**
* user pointer set function
*/
void linphone_chat_message_set_user_data(LinphoneChatMessage* message,void*);
/**
* user pointer get function
*/
void* linphone_chat_message_get_user_data(const LinphoneChatMessage* message);
/**
* Call back used to notify message delivery status
@ -669,7 +730,10 @@ typedef void (*LinphoneChatMessageStateChangeCb)(LinphoneChatMessage* msg,Linpho
* @param ud user data for the status cb.
*/
void linphone_chat_room_send_message2(LinphoneChatRoom *cr, LinphoneChatMessage* msg,LinphoneChatMessageStateChangeCb status_cb,void* ud);
LinphoneCore* linphone_chat_room_get_lc(LinphoneChatRoom *cr);
LinphoneChatRoom* linphone_chat_message_get_chat_room(LinphoneChatMessage *msg);
char* linphone_chat_message_get_message(LinphoneChatMessage *msg);
const LinphoneAddress* linphone_chat_message_get_peer_address(LinphoneChatMessage *msg);
void linphone_chat_room_set_user_data(LinphoneChatRoom *cr, void * ud);
void * linphone_chat_room_get_user_data(LinphoneChatRoom *cr);
@ -741,6 +805,7 @@ typedef void (*AuthInfoRequested)(struct _LinphoneCore *lc, const char *realm, c
typedef void (*CallLogUpdated)(struct _LinphoneCore *lc, struct _LinphoneCallLog *newcl);
/**
* Callback prototype
* @deprecated use #MessageReceived instead.
*
* @param lc #LinphoneCore object
* @param room #LinphoneChatRoom involved in this conversation. Can be be created by the framework in case \link #LinphoneAddress the from \endlink is not present in any chat room.
@ -748,6 +813,15 @@ typedef void (*CallLogUpdated)(struct _LinphoneCore *lc, struct _LinphoneCallLog
* @param message incoming message
* */
typedef void (*TextMessageReceived)(LinphoneCore *lc, LinphoneChatRoom *room, const LinphoneAddress *from, const char *message);
/**
* Chat message callback prototype
*
* @param lc #LinphoneCore object
* @param room #LinphoneChatRoom involved in this conversation. Can be be created by the framework in case \link #LinphoneAddress the from \endlink is not present in any chat room.
* @param LinphoneChatMessage incoming message
* */
typedef void (*MessageReceived)(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage *message);
/** Callback prototype */
typedef void (*DtmfReceived)(struct _LinphoneCore* lc, LinphoneCall *call, int dtmf);
/** Callback prototype */
@ -771,7 +845,8 @@ typedef struct _LinphoneVTable{
NewSubscribtionRequestCb new_subscription_request; /**< Notify about pending subscription request */
AuthInfoRequested auth_info_requested; /**< Ask the application some authentication information */
CallLogUpdated call_log_updated; /**< Notifies that call log list has been updated */
TextMessageReceived text_received; /**< A text message has been received */
TextMessageReceived text_received; /** @deprecated, use #message_received instead <br> A text message has been received */
MessageReceived message_received; /** a message is received, can be text or external body*/
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 */
@ -827,6 +902,24 @@ LinphoneCore *linphone_core_new(const LinphoneCoreVTable *vtable,
/* function to be periodically called in a main loop */
void linphone_core_iterate(LinphoneCore *lc);
#if 0 /*not implemented yet*/
/**
* @ingroup initializing
* Provide Linphone Core with an unique identifier. This be later used to identified contact address coming from this device.
* Value is not saved.
* @param lc object
* @param string identifying the device, can be EMEI or UDID
*
*/
void linphone_core_set_device_identifier(LinphoneCore *lc,const char* device_id);
/**
* @ingroup initializing
* get Linphone unique identifier
*
*/
const char* linphone_core_get_device_identifier(const LinphoneCore *lc);
#endif
LinphoneAddress * linphone_core_interpret_url(LinphoneCore *lc, const char *url);
@ -1249,6 +1342,8 @@ void linphone_core_set_rtp_transport_factories(LinphoneCore* lc, LinphoneRtpTran
int linphone_core_get_current_call_stats(LinphoneCore *lc, rtp_stats_t *local, rtp_stats_t *remote);
int linphone_core_get_calls_nb(const LinphoneCore *lc);
const MSList *linphone_core_get_calls(LinphoneCore *lc);
LinphoneGlobalState linphone_core_get_global_state(const LinphoneCore *lc);
@ -1313,6 +1408,15 @@ LinphoneTunnel *linphone_core_get_tunnel(LinphoneCore *lc);
void linphone_call_zoom_video(LinphoneCall* call, float zoom_factor, float* cx, float* cy);
void linphone_core_set_sip_dscp(LinphoneCore *lc, int dscp);
int linphone_core_get_sip_dscp(const LinphoneCore *lc);
void linphone_core_set_audio_dscp(LinphoneCore *lc, int dscp);
int linphone_core_get_audio_dscp(const LinphoneCore *lc);
void linphone_core_set_video_dscp(LinphoneCore *lc, int dscp);
int linphone_core_get_video_dscp(const LinphoneCore *lc);
#ifdef __cplusplus
}
#endif

View file

@ -109,6 +109,7 @@ public:
vTable.call_state_changed = callStateChange;
vTable.call_encryption_changed = callEncryptionChange;
vTable.text_received = text_received;
vTable.message_received = message_received;
vTable.new_subscription_request = new_subscription_request;
vTable.notify_presence_recv = notify_presence_recv;
@ -132,6 +133,9 @@ public:
callStateClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneCall$State"));
callStateFromIntId = env->GetStaticMethodID(callStateClass,"fromInt","(I)Lorg/linphone/core/LinphoneCall$State;");
chatMessageStateClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneChatMessage$State"));
chatMessageStateFromIntId = env->GetStaticMethodID(chatMessageStateClass,"fromInt","(I)Lorg/linphone/core/LinphoneChatMessage$State;");
/*callEncryption(LinphoneCore lc, LinphoneCall call, boolean encrypted,String auth_token);*/
callEncryptionChangedId=env->GetMethodID(listenerClass,"callEncryptionChanged","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCall;ZLjava/lang/String;)V");
@ -148,6 +152,7 @@ public:
/*void textReceived(LinphoneCore lc, LinphoneChatRoom cr,LinphoneAddress from,String message);*/
textReceivedId = env->GetMethodID(listenerClass,"textReceived","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneChatRoom;Lorg/linphone/core/LinphoneAddress;Ljava/lang/String;)V");
messageReceivedId = env->GetMethodID(listenerClass,"messageReceived","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneChatRoom;Lorg/linphone/core/LinphoneAddress;Lorg/linphone/core/LinphoneChatMessage;)V");
proxyClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneProxyConfigImpl"));
proxyCtrId = env->GetMethodID(proxyClass,"<init>", "(J)V");
@ -155,6 +160,9 @@ public:
callClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneCallImpl"));
callCtrId = env->GetMethodID(callClass,"<init>", "(J)V");
chatMessageClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneChatMessageImpl"));
chatMessageCtrId = env->GetMethodID(chatMessageClass,"<init>", "(J)V");
chatRoomClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneChatRoomImpl"));
chatRoomCtrId = env->GetMethodID(chatRoomClass,"<init>", "(J)V");
@ -176,8 +184,10 @@ public:
env->DeleteGlobalRef(globalStateClass);
env->DeleteGlobalRef(registrationStateClass);
env->DeleteGlobalRef(callStateClass);
env->DeleteGlobalRef(chatMessageStateClass);
env->DeleteGlobalRef(proxyClass);
env->DeleteGlobalRef(callClass);
env->DeleteGlobalRef(chatMessageClass);
env->DeleteGlobalRef(chatRoomClass);
env->DeleteGlobalRef(friendClass);
@ -191,6 +201,7 @@ public:
jmethodID newSubscriptionRequestId;
jmethodID notifyPresenceReceivedId;
jmethodID textReceivedId;
jmethodID messageReceivedId;
jclass globalStateClass;
jmethodID globalStateId;
@ -204,6 +215,9 @@ public:
jmethodID callStateId;
jmethodID callStateFromIntId;
jclass chatMessageStateClass;
jmethodID chatMessageStateFromIntId;
jmethodID callEncryptionChangedId;
jclass ecCalibratorStatusClass;
@ -216,6 +230,9 @@ public:
jclass callClass;
jmethodID callCtrId;
jclass chatMessageClass;
jmethodID chatMessageCtrId;
jclass chatRoomClass;
jmethodID chatRoomCtrId;
@ -373,6 +390,21 @@ public:
,env->NewObject(lcData->addressClass,lcData->addressCtrId,(jlong)from)
,message ? env->NewStringUTF(message) : NULL);
}
static void message_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage *msg) {
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->messageReceivedId
,lcData->core
,env->NewObject(lcData->chatRoomClass,lcData->chatRoomCtrId,(jlong)room)
,env->NewObject(lcData->addressClass,lcData->addressCtrId,(jlong)msg->from)
,env->NewObject(lcData->chatMessageClass,lcData->chatMessageCtrId,(jlong)msg));
}
static void ecCalibrationStatus(LinphoneCore *lc, LinphoneEcCalibratorStatus status, int delay_ms, void *data) {
JNIEnv *env = 0;
jint result = jvm->AttachCurrentThread(&env,NULL);
@ -955,6 +987,11 @@ extern "C" jstring Java_org_linphone_core_LinphoneProxyConfigImpl_getProxy(JNIEn
return NULL;
}
}
extern "C" void Java_org_linphone_core_LinphoneProxyConfigImpl_setContactParameters(JNIEnv* env,jobject thiz,jlong proxyCfg,jstring jparams) {
const char* params = env->GetStringUTFChars(jparams, NULL);
linphone_proxy_config_set_contact_parameters((LinphoneProxyConfig*)proxyCfg, params);
env->ReleaseStringUTFChars(jparams, params);
}
extern "C" int Java_org_linphone_core_LinphoneProxyConfigImpl_setRoute(JNIEnv* env,jobject thiz,jlong proxyCfg,jstring jroute) {
if (jroute != NULL) {
const char* route = env->GetStringUTFChars(jroute, NULL);
@ -1353,16 +1390,88 @@ extern "C" long Java_org_linphone_core_LinphoneChatRoomImpl_getPeerAddress(JNIEn
,jlong ptr) {
return (long) linphone_chat_room_get_peer_address((LinphoneChatRoom*)ptr);
}
extern "C" jlong Java_org_linphone_core_LinphoneChatRoomImpl_createLinphoneChatMessage(JNIEnv* env
,jobject thiz
,jlong ptr
,jstring jmessage) {
const char* message = env->GetStringUTFChars(jmessage, NULL);
LinphoneChatMessage *chatMessage = linphone_chat_room_create_message((LinphoneChatRoom *)ptr, message);
env->ReleaseStringUTFChars(jmessage, message);
return (jlong) chatMessage;
}
extern "C" void Java_org_linphone_core_LinphoneChatMessageImpl_setUserData(JNIEnv* env
,jobject thiz
,jlong ptr) {
jobject ud = env->NewGlobalRef(thiz);
linphone_chat_message_set_user_data((LinphoneChatMessage*)ptr,(void*) ud);
}
extern "C" jstring Java_org_linphone_core_LinphoneChatMessageImpl_getMessage(JNIEnv* env
,jobject thiz
,jlong ptr) {
jstring jvalue =env->NewStringUTF(linphone_chat_message_get_message((LinphoneChatMessage*)ptr));
return jvalue;
}
extern "C" jstring Java_org_linphone_core_LinphoneChatMessageImpl_getExternalBodyUrl(JNIEnv* env
,jobject thiz
,jlong ptr) {
jstring jvalue =env->NewStringUTF(linphone_chat_message_get_external_body_url((LinphoneChatMessage*)ptr));
return jvalue;
}
extern "C" void Java_org_linphone_core_LinphoneChatMessageImpl_setExternalBodyUrl(JNIEnv* env
,jobject thiz
,jlong ptr
,jstring jurl) {
const char* url = env->GetStringUTFChars(jurl, NULL);
linphone_chat_message_set_external_body_url((LinphoneChatMessage *)ptr, url);
env->ReleaseStringUTFChars(jurl, url);
}
extern "C" long Java_org_linphone_core_LinphoneChatMessageImpl_getPeerAddress(JNIEnv* env
,jobject thiz
,jlong ptr) {
return (long) linphone_chat_message_get_peer_address((LinphoneChatMessage*)ptr);
}
extern "C" void Java_org_linphone_core_LinphoneChatRoomImpl_sendMessage(JNIEnv* env
,jobject thiz
,jlong ptr
,jstring jmessage) {
const char* message = env->GetStringUTFChars(jmessage, NULL);
linphone_chat_room_send_message((LinphoneChatRoom*)ptr,message);
linphone_chat_room_send_message((LinphoneChatRoom*)ptr, message);
env->ReleaseStringUTFChars(jmessage, message);
}
static void chat_room_impl_callback(LinphoneChatMessage* msg, LinphoneChatMessageState state, void* ud) {
JNIEnv *env = 0;
jint result = jvm->AttachCurrentThread(&env,NULL);
if (result != 0) {
ms_error("cannot attach VM\n");
return;
}
jobject listener = (jobject) ud;
jclass clazz = (jclass) env->GetObjectClass(listener);
jmethodID method = env->GetMethodID(clazz, "onLinphoneChatMessageStateChanged","(Lorg/linphone/core/LinphoneChatMessage;Lorg/linphone/core/LinphoneChatMessage$State;)V");
LinphoneCore *lc = linphone_chat_room_get_lc(linphone_chat_message_get_chat_room(msg));
LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc);
env->CallVoidMethod(
listener,
method,
(jobject)linphone_chat_message_get_user_data(msg),
env->CallStaticObjectMethod(lcData->chatMessageStateClass,lcData->chatMessageStateFromIntId,(jint)state));
if (state == LinphoneChatMessageStateDelivered || state == LinphoneChatMessageStateNotDelivered) {
env->DeleteGlobalRef(listener);
}
}
extern "C" void Java_org_linphone_core_LinphoneChatRoomImpl_sendMessage2(JNIEnv* env
,jobject thiz
,jlong ptr
,jlong jmessage
,jobject jlistener) {
jobject listener = env->NewGlobalRef(jlistener);
linphone_chat_room_send_message2((LinphoneChatRoom*)ptr, (LinphoneChatMessage*)jmessage, chat_room_impl_callback, (void*)listener);
}
extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setVideoWindowId(JNIEnv* env
,jobject thiz
,jlong lc

View file

@ -86,7 +86,15 @@ typedef bool_t (*LinphoneCoreIterateHook)(void *data);
void linphone_core_add_iterate_hook(LinphoneCore *lc, LinphoneCoreIterateHook hook, void *hook_data);
void linphone_core_remove_iterate_hook(LinphoneCore *lc, LinphoneCoreIterateHook hook, void *hook_data);
/**
* @ingroup misc
*Function to get call country code from ISO 3166-1 alpha-2 code, ex: FR returns 33
*@param iso country code alpha2
*@return call country code or -1 if not found
*/
int linphone_dial_plan_lookup_ccc_from_iso(const char* iso);
#ifdef __cplusplus
}
#endif

View file

@ -273,7 +273,13 @@ const char *lp_config_get_string(LpConfig *lpconfig, const char *section, const
int lp_config_get_int(LpConfig *lpconfig,const char *section, const char *key, int default_value){
const char *str=lp_config_get_string(lpconfig,section,key,NULL);
if (str!=NULL) return atoi(str);
if (str!=NULL) {
int ret=0;
if (strstr(str,"0x")==str){
sscanf(str,"%x",&ret);
}else ret=atoi(str);
return ret;
}
else return default_value;
}
@ -324,6 +330,12 @@ void lp_config_set_int(LpConfig *lpconfig,const char *section, const char *key,
lp_config_set_string(lpconfig,section,key,tmp);
}
void lp_config_set_int_hex(LpConfig *lpconfig,const char *section, const char *key, int value){
char tmp[30];
snprintf(tmp,sizeof(tmp),"0x%x",value);
lp_config_set_string(lpconfig,section,key,tmp);
}
void lp_config_set_int64(LpConfig *lpconfig,const char *section, const char *key, int64_t value){
char tmp[30];
snprintf(tmp,sizeof(tmp),"%lli",(long long)value);

View file

@ -96,6 +96,14 @@ void lp_config_set_string(LpConfig *lpconfig,const char *section, const char *ke
* @ingroup misc
**/
void lp_config_set_int(LpConfig *lpconfig,const char *section, const char *key, int value);
/**
* Sets an integer config item, but store it as hexadecimal
*
* @ingroup misc
**/
void lp_config_set_int_hex(LpConfig *lpconfig,const char *section, const char *key, int value);
/**
* Sets a 64 bits integer config item
*

View file

@ -466,12 +466,13 @@ static int recvStunResponse(ortp_socket_t sock, char *ipaddr, int *port, int *id
return len;
}
void linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){
/* this functions runs a simple stun test and return the number of milliseconds to complete the tests, or -1 if the test were failed.*/
int linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call, StunCandidate *ac, StunCandidate *vc){
const char *server=linphone_core_get_stun_server(lc);
if (lc->sip_conf.ipv6_enabled){
ms_warning("stun support is not implemented for ipv6");
return;
return -1;
}
if (server!=NULL){
struct sockaddr_storage ss;
@ -482,30 +483,28 @@ void linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){
bool_t got_audio,got_video;
bool_t cone_audio=FALSE,cone_video=FALSE;
struct timeval init,cur;
SalEndpointCandidate *ac,*vc;
ac=&call->localdesc->streams[0].candidates[0];
vc=&call->localdesc->streams[1].candidates[0];
double elapsed;
int ret=0;
if (parse_hostname_to_addr(server,&ss,&ss_len)<0){
ms_error("Fail to parser stun server address: %s",server);
return;
return -1;
}
if (lc->vtable.display_status!=NULL)
lc->vtable.display_status(lc,_("Stun lookup in progress..."));
/*create the two audio and video RTP sockets, and send STUN message to our stun server */
sock1=create_socket(call->audio_port);
if (sock1==-1) return;
if (sock1==-1) return -1;
if (video_enabled){
sock2=create_socket(call->video_port);
if (sock2==-1) return ;
if (sock2==-1) return -1;
}
got_audio=FALSE;
got_video=FALSE;
gettimeofday(&init,NULL);
do{
double elapsed;
int id;
if (loops%20==0){
ms_message("Sending stun requests...");
@ -544,10 +543,12 @@ void linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){
elapsed=((cur.tv_sec-init.tv_sec)*1000.0) + ((cur.tv_usec-init.tv_usec)/1000.0);
if (elapsed>2000) {
ms_message("Stun responses timeout, going ahead.");
ret=-1;
break;
}
loops++;
}while(!(got_audio && (got_video||sock2==-1) ) );
if (ret==0) ret=(int)elapsed;
if (!got_audio){
ms_error("No stun server response for audio port.");
}else{
@ -564,15 +565,32 @@ void linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){
}
}
}
if ((ac->addr[0]!='\0' && vc->addr[0]!='\0' && strcmp(ac->addr,vc->addr)==0)
|| sock2==-1){
strcpy(call->localdesc->addr,ac->addr);
}
close_socket(sock1);
if (sock2!=-1) close_socket(sock2);
return ret;
}
return -1;
}
void linphone_core_adapt_to_network(LinphoneCore *lc, int ping_time_ms, LinphoneCallParams *params){
if (lp_config_get_int(lc->config,"net","activate_edge_workarounds",0)==1){
ms_message("Stun server ping time is %i ms",ping_time_ms);
int threshold=lp_config_get_int(lc->config,"net","edge_ping_time",500);
if (ping_time_ms>threshold){
int edge_ptime=lp_config_get_int(lc->config,"net","edge_ptime",100);
int edge_bw=lp_config_get_int(lc->config,"net","edge_bw",20);
/* we are in a 2G network*/
params->up_bw=params->down_bw=edge_bw;
params->up_ptime=params->down_ptime=edge_ptime;
params->has_video=FALSE;
}/*else use default settings */
}
}
int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call)
{
char local_addr[64];
@ -606,16 +624,57 @@ int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call)
}
ice_add_local_candidate(audio_check_list, "host", local_addr, call->audio_port, 1, NULL);
ice_add_local_candidate(audio_check_list, "host", local_addr, call->audio_port + 1, 2, NULL);
call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateInProgress;
if (call->params.has_video && (video_check_list != NULL)) {
ice_add_local_candidate(video_check_list, "host", local_addr, call->video_port, 1, NULL);
ice_add_local_candidate(video_check_list, "host", local_addr, call->video_port + 1, 2, NULL);
call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateInProgress;
}
ms_message("ICE: gathering candidate from [%s]",server);
/* Gather local srflx candidates. */
ice_session_gather_candidates(call->ice_session, ss, ss_len);
return 0;
}
void linphone_core_update_ice_state_in_call_stats(LinphoneCall *call)
{
IceCheckList *audio_check_list;
IceCheckList *video_check_list;
if (call->ice_session == NULL) return;
audio_check_list = ice_session_check_list(call->ice_session, 0);
video_check_list = ice_session_check_list(call->ice_session, 1);
if (audio_check_list == NULL) return;
switch (ice_check_list_selected_valid_candidate_type(audio_check_list)) {
case ICT_HostCandidate:
call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateHostConnection;
break;
case ICT_ServerReflexiveCandidate:
case ICT_PeerReflexiveCandidate:
call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateReflexiveConnection;
break;
case ICT_RelayedCandidate:
call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateRelayConnection;
break;
}
if (call->params.has_video && (video_check_list != NULL)) {
switch (ice_check_list_selected_valid_candidate_type(video_check_list)) {
case ICT_HostCandidate:
call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateHostConnection;
break;
case ICT_ServerReflexiveCandidate:
case ICT_PeerReflexiveCandidate:
call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateReflexiveConnection;
break;
case ICT_RelayedCandidate:
call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateRelayConnection;
break;
}
}
}
void linphone_core_update_local_media_description_from_ice(SalMediaDescription *desc, IceSession *session)
{
const char *rtp_addr, *rtcp_addr;

View file

@ -240,7 +240,6 @@ static void initiate_incoming(const SalStreamDescription *local_cap,
if (result->payloads && !only_telephone_event(result->payloads) && (remote_offer->rtp_port!=0 || remote_offer->rtp_port==SalStreamSendOnly)){
strcpy(result->rtp_addr,local_cap->rtp_addr);
strcpy(result->rtcp_addr,local_cap->rtcp_addr);
memcpy(result->candidates,local_cap->candidates,sizeof(result->candidates));
result->rtp_port=local_cap->rtp_port;
result->rtcp_port=local_cap->rtcp_port;
result->bandwidth=local_cap->bandwidth;

View file

@ -69,8 +69,12 @@ struct _LinphoneCallParams{
LinphoneCall *referer; /*in case this call creation is consecutive to an incoming transfer, this points to the original call */
int audio_bw; /* bandwidth limit for audio stream */
LinphoneMediaEncryption media_encryption;
PayloadType *audio_codec;
PayloadType *video_codec;
PayloadType *audio_codec; /*audio codec currently in use */
PayloadType *video_codec; /*video codec currently in use */
int down_bw;
int up_bw;
int down_ptime;
int up_ptime;
bool_t has_video;
bool_t real_early_media; /*send real media even during early media (for outgoing calls)*/
bool_t in_conference; /*in conference mode */
@ -87,11 +91,13 @@ typedef struct _CallCallbackObj
static const int linphone_call_magic=0x3343;
struct _LinphoneChatMessage {
const char* message;
char* message;
LinphoneChatRoom* chat_room;
LinphoneChatMessageStateChangeCb cb;
void* cb_ud;
void* message_userdata;
char* external_body_url;
LinphoneAddress* from;
};
struct _LinphoneCall
@ -179,10 +185,7 @@ int parse_hostname_to_addr(const char *server, struct sockaddr_storage *ss, sock
int set_lock_file();
int get_lock_file();
int remove_lock_file();
int do_registration(LinphoneCore *lc, bool_t doit);
void check_for_registration(LinphoneCore *lc);
void check_sound_device(LinphoneCore *lc);
void linphone_core_verify_codecs(LinphoneCore *lc);
void linphone_core_get_local_ip(LinphoneCore *lc, const char *to, char *result);
bool_t host_has_ipv6_network();
bool_t lp_spawn_command_line_sync(const char *command, char **result,int *command_ret);
@ -229,8 +232,16 @@ MSList *linphone_find_friend(MSList *fl, const LinphoneAddress *fri, LinphoneFri
void linphone_core_update_allocated_audio_bandwidth(LinphoneCore *lc);
void linphone_core_update_allocated_audio_bandwidth_in_call(LinphoneCall *call, const PayloadType *pt);
void linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call);
typedef struct StunCandidate{
char addr[64];
int port;
}StunCandidate;
int linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call, StunCandidate *ac, StunCandidate *vc);
void linphone_core_adapt_to_network(LinphoneCore *lc, int ping_time_ms, LinphoneCallParams *params);
int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call);
void linphone_core_update_ice_state_in_call_stats(LinphoneCall *call);
void linphone_core_update_local_media_description_from_ice(SalMediaDescription *desc, IceSession *session);
void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call, const SalMediaDescription *md);
void linphone_core_deactivate_ice_for_deactivated_media_streams(LinphoneCall *call, const SalMediaDescription *md);
@ -251,7 +262,7 @@ void linphone_proxy_config_write_to_config_file(struct _LpConfig* config,Linphon
int linphone_proxy_config_normalize_number(LinphoneProxyConfig *cfg, const char *username, char *result, size_t result_len);
void linphone_core_text_received(LinphoneCore *lc, const char *from, const char *msg);
void linphone_core_message_received(LinphoneCore *lc, const char *from, const char *raw_msg,const char* external_url);
void linphone_core_play_tone(LinphoneCore *lc);
@ -386,6 +397,7 @@ typedef struct rtp_config
/* stop rtp xmit when audio muted */
bool_t audio_adaptive_jitt_comp_enabled;
bool_t video_adaptive_jitt_comp_enabled;
bool_t pad;
}rtp_config_t;
@ -400,7 +412,6 @@ typedef struct net_config
int upload_bw;
int firewall_policy;
int mtu;
int down_ptime;
bool_t nat_sdp_only;
}net_config_t;
@ -413,10 +424,10 @@ typedef struct sound_config
struct _MSSndCard * lsd_card; /* dummy playback card for Linphone Sound Daemon extension */
const char **cards;
int latency; /* latency in samples of the current used sound device */
float soft_play_lev; /*playback gain in db.*/
char rec_lev;
char play_lev;
char ring_lev;
char soft_play_lev;
char source;
char *local_ring;
char *remote_ring;
@ -539,6 +550,7 @@ struct _LinphoneCore
int device_rotation;
int max_calls;
LinphoneTunnel *tunnel;
char* device_id;
};
LinphoneTunnel *linphone_core_tunnel_new(LinphoneCore *lc);

View file

@ -375,21 +375,33 @@ bool_t linphone_proxy_config_get_dial_escape_plus(const LinphoneProxyConfig *cfg
*/
typedef struct dial_plan{
const char *country;
const char* iso_country_code; /* ISO 3166-1 alpha-2 code, ex: FR for France*/
char ccc[8]; /*country calling code*/
int nnl; /*maximum national number length*/
const char * icp; /*international call prefix, ex: 00 in europe*/
}dial_plan_t;
/* TODO: fill with information for all countries over the world*/
static dial_plan_t const dial_plans[]={
{"France" , "33" , 9 , "00" },
{"United States", "1" , 10 , "011" },
{"Turkey" , "90" , 10 , "00" },
{"Switzerland" , "41" , 9 , "00" },
{NULL , "" , 0 , NULL }
{"France" ,"FR" , "33" , 9 , "00" },
{"United States" ,"US" , "1" , 10 , "011" },
{"Turkey" ,"TR" , "90" , 10 , "00" },
{"Switzerland" ,"XK" , "41" , 9 , "00" },
{NULL ,NULL,"" , 0 , NULL }
};
static dial_plan_t most_common_dialplan={ "generic" , "", 10, "00"};
static dial_plan_t most_common_dialplan={ "generic" ,"", "", 10, "00"};
int linphone_dial_plan_lookup_ccc_from_iso(const char* iso) {
dial_plan_t* dial_plan;
for (dial_plan=(dial_plan_t*)dial_plans; dial_plan->country!=NULL; dial_plan++) {
if (strcmp(iso, dial_plan->iso_country_code)==0) {
return atoi(dial_plan->ccc);
}
}
return -1;
}
static void lookup_dial_plan(const char *ccc, dial_plan_t *plan){
int i;
@ -728,6 +740,9 @@ void linphone_proxy_config_write_to_config_file(LpConfig *config, LinphoneProxyC
if (obj->reg_identity!=NULL){
lp_config_set_string(config,key,"reg_identity",obj->reg_identity);
}
if (obj->contact_params!=NULL){
lp_config_set_string(config,key,"contact_params",obj->contact_params);
}
lp_config_set_int(config,key,"reg_expires",obj->expires);
lp_config_set_int(config,key,"reg_sendregister",obj->reg_sendregister);
lp_config_set_int(config,key,"publish",obj->publish);
@ -762,6 +777,8 @@ LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(LpConfig *config
tmp=lp_config_get_string(config,key,"reg_route",NULL);
if (tmp!=NULL) linphone_proxy_config_set_route(cfg,tmp);
linphone_proxy_config_set_contact_parameters(cfg,lp_config_get_string(config,key,"contact_parameters",NULL));
linphone_proxy_config_expires(cfg,lp_config_get_int(config,key,"reg_expires",DEFAULT_INT(config,reg_expires,600)));
linphone_proxy_config_enableregister(cfg,lp_config_get_int(config,key,"reg_sendregister",0));

View file

@ -105,11 +105,6 @@ typedef enum{
SalStreamInactive
}SalStreamDir;
typedef struct SalEndpointCandidate{
char addr[64];
int port;
}SalEndpointCandidate;
#define SAL_ENDPOINT_CANDIDATE_MAX 2
#define SAL_MEDIA_DESCRIPTION_MAX_ICE_ADDR_LEN 64
@ -159,7 +154,6 @@ typedef struct SalStreamDescription{
MSList *payloads; //<list of PayloadType
int bandwidth;
int ptime;
SalEndpointCandidate candidates[SAL_ENDPOINT_CANDIDATE_MAX];
SalStreamDir dir;
SalSrtpCryptoAlgo crypto[SAL_CRYPTO_ALGO_MAX];
unsigned int crypto_local_tag;
@ -259,6 +253,12 @@ typedef enum SalSubscribeStatus{
SalSubscribeTerminated
}SalSubscribeStatus;
typedef enum SalTextDeliveryStatus{
SalTextDeliveryInProgress,
SalTextDeliveryDone,
SalTextDeliveryFailed
}SalTextDeliveryStatus;
typedef void (*SalOnCallReceived)(SalOp *op);
typedef void (*SalOnCallRinging)(SalOp *op);
typedef void (*SalOnCallAccepted)(SalOp *op);
@ -275,6 +275,8 @@ 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 (*SalOnMessageExternalBodyReceived)(Sal *sal, const char *from, const char *url);
typedef void (*SalOnTextDeliveryUpdate)(SalOp *op, SalTextDeliveryStatus status);
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);
@ -299,6 +301,8 @@ typedef struct SalCallbacks{
SalOnDtmfReceived dtmf_received;
SalOnRefer refer_received;
SalOnTextReceived text_received;
SalOnMessageExternalBodyReceived message_external_body;
SalOnTextDeliveryUpdate text_delivery_update;
SalOnNotify notify;
SalOnNotifyPresence notify_presence;
SalOnNotifyRefer notify_refer;
@ -321,6 +325,7 @@ void sal_auth_info_delete(const SalAuthInfo* auth_info);
void sal_set_callbacks(Sal *ctx, const SalCallbacks *cbs);
int sal_listen_port(Sal *ctx, const char *addr, int port, SalTransport tr, int is_secure);
int sal_unlisten_ports(Sal *ctx);
void sal_set_dscp(Sal *ctx, int dscp);
int sal_reset_transports(Sal *ctx);
ortp_socket_t sal_get_socket(Sal *ctx);
void sal_set_user_agent(Sal *ctx, const char *user_agent);
@ -400,6 +405,7 @@ int sal_unregister(SalOp *h);
/*Messaging */
int sal_text_send(SalOp *op, const char *from, const char *to, const char *text);
int sal_message_send(SalOp *op, const char *from, const char *to, const char* content_type, const char *msg);
/*presence Subscribe/notify*/
int sal_subscribe_presence(SalOp *op, const char *from, const char *to);

View file

@ -21,7 +21,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#endif
#include "sal_eXosip2.h"
#include "private.h"
#include "offeranswer.h"
#ifdef ANDROID
@ -98,12 +97,12 @@ static void sal_remove_register(Sal *sal, int rid){
}
}
static SalOp * sal_find_other(Sal *sal, osip_message_t *response){
static SalOp * sal_find_other(Sal *sal, osip_message_t *message){
const MSList *elem;
SalOp *op;
osip_call_id_t *callid=osip_message_get_call_id(response);
osip_call_id_t *callid=osip_message_get_call_id(message);
if (callid==NULL) {
ms_error("There is no call-id in this response !");
ms_error("There is no call-id in this message !");
return NULL;
}
for(elem=sal->other_transactions;elem!=NULL;elem=elem->next){
@ -284,6 +283,7 @@ Sal * sal_init(){
sal->rootCa = 0;
sal->verify_server_certs=TRUE;
sal->expire_old_contact=FALSE;
sal->dscp=-1;
return sal;
}
@ -342,6 +342,8 @@ void sal_set_callbacks(Sal *ctx, const SalCallbacks *cbs){
ctx->callbacks.text_received=(SalOnTextReceived)unimplemented_stub;
if (ctx->callbacks.ping_reply==NULL)
ctx->callbacks.ping_reply=(SalOnPingReply)unimplemented_stub;
if (ctx->callbacks.message_external_body==NULL)
ctx->callbacks.message_external_body=(SalOnMessageExternalBodyReceived)unimplemented_stub;
}
int sal_unlisten_ports(Sal *ctx){
@ -379,6 +381,12 @@ static void set_tls_options(Sal *ctx){
#endif
}
void sal_set_dscp(Sal *ctx, int dscp){
ctx->dscp=dscp;
if (dscp!=-1)
eXosip_set_option(EXOSIP_OPT_SET_DSCP,&ctx->dscp);
}
int sal_listen_port(Sal *ctx, const char *addr, int port, SalTransport tr, int is_secure){
int err;
bool_t ipv6;
@ -405,6 +413,7 @@ int sal_listen_port(Sal *ctx, const char *addr, int port, SalTransport tr, int i
eXosip_set_option(EXOSIP_OPT_USE_RPORT,&use_rports);
int dont_use_101 = !ctx->use_101; // Copy char to int to avoid bad alignment
eXosip_set_option(EXOSIP_OPT_DONT_SEND_101,&dont_use_101);
sal_set_dscp(ctx,ctx->dscp);
ipv6=strchr(addr,':')!=NULL;
eXosip_enable_ipv6(ipv6);
@ -931,9 +940,9 @@ void sal_op_authenticate(SalOp *h, const SalAuthInfo *info){
}
void sal_op_cancel_authentication(SalOp *h) {
if (h->rid >0) {
sal_op_get_sal(h)->callbacks.register_failure(h,SalErrorFailure, SalReasonForbidden,_("Authentication failure"));
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);
sal_op_get_sal(h)->callbacks.call_failure(h,SalErrorFailure, SalReasonForbidden,"Authentication failure",0);
} else {
ms_warning("Auth failure not handled");
}
@ -999,6 +1008,7 @@ static SalOp *find_op(Sal *sal, eXosip_event_t *ev){
return sal_find_in_subscribe(sal,ev->nid);
}
if (ev->response) return sal_find_other(sal,ev->response);
else if (ev->request) return sal_find_other(sal,ev->request);
return NULL;
}
@ -1701,15 +1711,44 @@ static bool_t comes_from_local_if(osip_message_t *msg){
static void text_received(Sal *sal, eXosip_event_t *ev){
osip_body_t *body=NULL;
char *from=NULL,*msg;
osip_content_type_t* content_type;
osip_uri_param_t* external_body_url;
char unquoted_external_body_url [256];
int external_body_size=0;
content_type= osip_message_get_content_type(ev->request);
if (!content_type) {
ms_error("Could not get message because no content type");
return;
}
osip_from_to_str(ev->request->from,&from);
if (content_type->type
&& strcmp(content_type->type, "text")==0
&& content_type->subtype
&& strcmp(content_type->subtype, "plain")==0 ) {
osip_message_get_body(ev->request,0,&body);
if (body==NULL){
ms_error("Could not get text message from SIP body");
return;
}
msg=body->body;
osip_from_to_str(ev->request->from,&from);
sal->callbacks.text_received(sal,from,msg);
} if (content_type->type
&& strcmp(content_type->type, "message")==0
&& content_type->subtype
&& strcmp(content_type->subtype, "external-body")==0 ) {
osip_content_type_param_get_byname(content_type, "URL", &external_body_url);
/*remove both first and last character*/
strncpy(unquoted_external_body_url
,&external_body_url->gvalue[1]
,external_body_size=MIN(strlen(external_body_url->gvalue)-1,sizeof(unquoted_external_body_url)));
unquoted_external_body_url[external_body_size-1]='\0';
sal->callbacks.message_external_body(sal,from,unquoted_external_body_url);
} else {
ms_warning("Unsupported content type [%s/%s]",content_type->type,content_type->subtype);
}
osip_free(from);
}
@ -1953,26 +1992,27 @@ static bool_t registration_failure(Sal *sal, eXosip_event_t *ev){
static void other_request_reply(Sal *sal,eXosip_event_t *ev){
SalOp *op=find_op(sal,ev);
LinphoneChatMessage* chat_msg;
ms_message("Processing reponse status [%i] for method [%s]",ev->response->status_code,osip_message_get_method(ev->request));
if (op==NULL){
ms_warning("other_request_reply(): Receiving response to unknown request.");
return;
}
if (ev->response){
ms_message("Processing reponse status [%i] for method [%s]",ev->response->status_code,osip_message_get_method(ev->request));
update_contact_from_response(op,ev->response);
if (ev->request && strcmp(osip_message_get_method(ev->request),"OPTIONS")==0)
sal->callbacks.ping_reply(op);
else if (ev->request && strcmp(osip_message_get_method(ev->request),"MESSAGE")==0) {
/*out of call message acknolegment*/
chat_msg=(LinphoneChatMessage* )op->base.user_pointer;
if (chat_msg->cb) {
chat_msg->cb(chat_msg
,(ev->response->status_code==200?LinphoneChatMessageStateDelivered:LinphoneChatMessageStateNotDelivered)
,chat_msg->cb_ud);
}
if (ev->request && strcmp(osip_message_get_method(ev->request),"MESSAGE")==0) {
/*out of call message acknolegment*/
SalTextDeliveryStatus status=SalTextDeliveryFailed;
if (ev->response){
if (ev->response->status_code<200){
status=SalTextDeliveryInProgress;
}else if (ev->response->status_code<300 && ev->response->status_code>=200){
status=SalTextDeliveryDone;
}
linphone_chat_message_destroy(chat_msg);
}
sal->callbacks.text_delivery_update(op,status);
}
}
@ -2081,8 +2121,8 @@ static bool_t process_event(Sal *sal, eXosip_event_t *ev){
if (ev->response && (ev->response->status_code == 407 || ev->response->status_code == 401)){
return process_authentication(sal,ev);
}
case EXOSIP_SUBSCRIPTION_SERVERFAILURE:
case EXOSIP_SUBSCRIPTION_GLOBALFAILURE:
case EXOSIP_SUBSCRIPTION_SERVERFAILURE:
case EXOSIP_SUBSCRIPTION_GLOBALFAILURE:
sal_exosip_subscription_closed(sal,ev);
break;
case EXOSIP_REGISTRATION_FAILURE:
@ -2221,12 +2261,28 @@ int sal_register(SalOp *h, const char *proxy, const char *from, int expires){
int sal_register_refresh(SalOp *op, int expires){
osip_message_t *msg=NULL;
const char *contact=sal_op_get_contact(op);
if (op->rid==-1){
ms_error("Unexistant registration context, not possible to refresh.");
return -1;
}
#ifdef HAVE_EXOSIP_TRYLOCK
{
int tries=0;
/*iOS hack: in the keep alive handler, we have no more than 10 seconds to refresh registers, otherwise the application is suspended forever.
* In order to prevent this case that can occur when the exosip thread is busy with DNS while network isn't in a good shape, we try to take
* the exosip lock in a non blocking way, and give up if it takes too long*/
while (eXosip_trylock()!=0){
ms_usleep(100000);
if (tries>30) {/*after 3 seconds, give up*/
ms_warning("Could not obtain exosip lock in a reasonable time, giving up.");
return -1;
}
}
}
#else
eXosip_lock();
#endif
eXosip_register_build_register(op->rid,expires,&msg);
if (msg!=NULL){
if (contact) register_set_contact(msg,contact);

View file

@ -41,6 +41,7 @@ struct Sal{
int keepalive_period;
void *up; /*user pointer*/
char* rootCa; /* File _or_ folder containing root CA */
int dscp;
bool_t one_matching_codec;
bool_t double_reg;
bool_t use_rports;

View file

@ -81,7 +81,7 @@ void sal_remove_in_subscribe(Sal *sal, SalOp *op){
sal->in_subscribes=ms_list_remove(sal->in_subscribes,op);
}
int sal_text_send(SalOp *op, const char *from, const char *to, const char *msg){
int sal_message_send(SalOp *op, const char *from, const char *to, const char* content_type, const char *msg){
osip_message_t *sip=NULL;
if(op->cid == -1)
@ -97,8 +97,8 @@ int sal_text_send(SalOp *op, const char *from, const char *to, const char *msg){
eXosip_message_build_request(&sip,"MESSAGE",sal_op_get_to(op),
sal_op_get_from(op),sal_op_get_route(op));
if (sip!=NULL){
osip_message_set_content_type(sip,"text/plain");
osip_message_set_body(sip,msg,strlen(msg));
osip_message_set_content_type(sip,content_type);
if (msg) osip_message_set_body(sip,msg,strlen(msg));
sal_add_other(op->base.root,op,sip);
eXosip_message_send_request(sip);
}else{
@ -118,14 +118,16 @@ int sal_text_send(SalOp *op, const char *from, const char *to, const char *msg){
eXosip_unlock();
return -1;
}
osip_message_set_content_type(sip,"text/plain");
osip_message_set_body(sip,msg,strlen(msg));
osip_message_set_content_type(sip,content_type);
if (msg) osip_message_set_body(sip,msg,strlen(msg));
eXosip_call_send_request(op->did,sip);
eXosip_unlock();
}
return 0;
}
int sal_text_send(SalOp *op, const char *from, const char *to, const char *msg) {
return sal_message_send(op,from,to,"text/plain",msg);
}
/*presence Subscribe/notify*/
int sal_subscribe_presence(SalOp *op, const char *from, const char *to){
osip_message_t *msg=NULL;

View file

@ -18,6 +18,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "ortp/port.h"
#include "ortp/b64.h"
#include "ortp/ortp_srtp.h"
#include "sal.h"
@ -279,10 +280,6 @@ static void add_line(sdp_message_t *msg, int lineno, const SalStreamDescription
rtcp_addr=desc->rtcp_addr;
rtp_port=desc->rtp_port;
rtcp_port=desc->rtcp_port;
if (desc->candidates[0].addr[0]!='\0'){
rtp_addr=desc->candidates[0].addr;
rtp_port=desc->candidates[0].port;
}
if (desc->proto == SalProtoRtpSavp) {
int i;

View file

@ -9,7 +9,8 @@ UI_FILES= about.ui \
log.ui \
buddylookup.ui \
tunnel_config.ui \
waiting.ui
waiting.ui \
dscp_settings.ui
PIXMAPS= \
stock_people.png

View file

@ -19,6 +19,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "linphone.h"
#ifdef HAVE_GTK_OSX
#include <gtkosxapplication.h>
#endif
GtkWidget * linphone_gtk_init_chatroom(LinphoneChatRoom *cr, const char *with){
GtkWidget *w;
GtkTextBuffer *b;
@ -37,6 +42,7 @@ GtkWidget * linphone_gtk_init_chatroom(LinphoneChatRoom *cr, const char *with){
}
void linphone_gtk_create_chatroom(const char *with){
LinphoneChatRoom *cr=linphone_core_create_chat_room(linphone_gtk_get_core(),with);
if (!cr) return;
linphone_gtk_init_chatroom(cr,with);
@ -84,6 +90,10 @@ const char* linphone_gtk_get_used_identity(){
else return linphone_core_get_primary_contact(lc);
}
static void on_chat_state_changed(LinphoneChatMessage *msg, LinphoneChatMessageState state, void *user_pointer){
g_message("chat message state is %s",linphone_chat_message_state_to_string(state));
}
void linphone_gtk_send_text(GtkWidget *button){
GtkWidget *w=gtk_widget_get_toplevel(button);
GtkWidget *entry=linphone_gtk_get_widget(w,"text_entry");
@ -91,19 +101,37 @@ void linphone_gtk_send_text(GtkWidget *button){
const gchar *entered;
entered=gtk_entry_get_text(GTK_ENTRY(entry));
if (strlen(entered)>0) {
LinphoneChatMessage *msg;
linphone_gtk_push_text(GTK_TEXT_VIEW(linphone_gtk_get_widget(w,"textlog")),
linphone_gtk_get_used_identity(),
entered,TRUE);
linphone_chat_room_send_message(cr,entered);
msg=linphone_chat_room_create_message(cr,entered);
linphone_chat_room_send_message2(cr,msg,on_chat_state_changed,NULL);
gtk_entry_set_text(GTK_ENTRY(entry),"");
}
}
void linphone_gtk_text_received(LinphoneCore *lc, LinphoneChatRoom *room, const LinphoneAddress *from, const char *message){
GtkWidget *w=(GtkWidget*)linphone_chat_room_get_user_data(room);
if (w==NULL){
GtkWidget *w=(GtkWidget*)linphone_chat_room_get_user_data(room);
if (w==NULL){
w=linphone_gtk_init_chatroom(room,linphone_address_as_string_uri_only(from));
g_object_set_data(G_OBJECT(w),"is_notified",GINT_TO_POINTER(FALSE));
}
#ifdef HAVE_GTK_OSX
/* Notified when a new message is sent */
linphone_gtk_status_icon_set_blinking(TRUE);
#else
if (!gtk_window_is_active((GtkWindow*)w)){
if(!GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w),"is_notified"))){
linphone_gtk_notify(NULL,message);
g_object_set_data(G_OBJECT(w),"is_notified",GINT_TO_POINTER(TRUE));
}
} else {
g_object_set_data(G_OBJECT(w),"is_notified",GINT_TO_POINTER(FALSE));
}
#endif
linphone_gtk_push_text(GTK_TEXT_VIEW(linphone_gtk_get_widget(w,"textlog")),
linphone_address_as_string_uri_only(from),
message,FALSE);

178
gtk/dscp_settings.ui Normal file
View file

@ -0,0 +1,178 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk+" version="2.24"/>
<!-- interface-naming-policy project-wide -->
<object class="GtkDialog" id="dscp_settings">
<property name="can_focus">False</property>
<property name="border_width">5</property>
<property name="title" translatable="yes">Dscp settings</property>
<property name="modal">True</property>
<property name="type_hint">dialog</property>
<signal name="response" handler="linphone_gtk_dscp_edit_response" swapped="no"/>
<child internal-child="vbox">
<object class="GtkVBox" id="dialog-vbox1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">2</property>
<child internal-child="action_area">
<object class="GtkHButtonBox" id="dialog-action_area1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="button2">
<property name="label">gtk-close</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_action_appearance">False</property>
<property name="use_stock">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="button1">
<property name="label">gtk-ok</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_action_appearance">False</property>
<property name="use_stock">True</property>
</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="fill">True</property>
<property name="pack_type">end</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkFrame" id="frame1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label_xalign">0</property>
<property name="shadow_type">none</property>
<child>
<object class="GtkTable" id="table1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="n_rows">3</property>
<property name="n_columns">2</property>
<property name="homogeneous">True</property>
<child>
<object class="GtkEntry" id="sip_dscp">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">•</property>
<property name="invisible_char_set">True</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
<property name="primary_icon_sensitive">True</property>
<property name="secondary_icon_sensitive">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="audio_dscp">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">•</property>
<property name="invisible_char_set">True</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
<property name="primary_icon_sensitive">True</property>
<property name="secondary_icon_sensitive">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="video_dscp">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">•</property>
<property name="invisible_char_set">True</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
<property name="primary_icon_sensitive">True</property>
<property name="secondary_icon_sensitive">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">SIP</property>
</object>
</child>
<child>
<object class="GtkLabel" id="label3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Audio RTP stream</property>
</object>
<packing>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label4">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Video RTP stream</property>
</object>
<packing>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
</packing>
</child>
</object>
</child>
<child type="label">
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">&lt;b&gt;Set DSCP values (in hexadecimal)&lt;/b&gt;</property>
<property name="use_markup">True</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
<action-widgets>
<action-widget response="-6">button2</action-widget>
<action-widget response="-5">button1</action-widget>
</action-widgets>
</object>
</interface>

View file

@ -97,6 +97,9 @@ void * linphone_gtk_wait(LinphoneCore *lc, void *ctx, LinphoneWaitingState ws, c
void linphone_gtk_show_directory_search(void);
void linphone_gtk_status_icon_set_blinking(gboolean val);
void linphone_gtk_notify(LinphoneCall *call, const char *msg);
/*functions controlling the different views*/
gboolean linphone_gtk_use_in_call_view();
LinphoneCall *linphone_gtk_get_currently_displayed_call(gboolean *is_conf);

View file

@ -65,10 +65,11 @@ static void linphone_gtk_call_state_changed(LinphoneCore *lc, LinphoneCall *call
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);
void linphone_gtk_status_icon_set_blinking(gboolean val);
void _linphone_gtk_enable_video(gboolean val);
static gboolean verbose=0;
static gboolean auto_answer = 0;
static gchar * addr_to_call = NULL;
@ -1028,18 +1029,20 @@ static void make_notification(const char *title, const char *body){
#endif
static void linphone_gtk_notify(LinphoneCall *call, const char *msg){
void linphone_gtk_notify(LinphoneCall *call, const char *msg){
#ifdef HAVE_NOTIFY
if (!notify_is_initted())
if (!notify_init ("Linphone")) ms_error("Libnotify failed to init.");
#endif
if (!call) {
#ifdef HAVE_NOTIFY
if (!notify_notification_show(notify_notification_new("Linphone",msg,NULL
#ifdef HAVE_NOTIFY1
,NULL
#endif
),NULL))
ms_error("Failed to send notification.");
#else
linphone_gtk_show_main_window();
@ -1347,7 +1350,7 @@ static gboolean do_icon_blink(GtkStatusIcon *gi){
#endif
static void linphone_gtk_status_icon_set_blinking(gboolean val){
void linphone_gtk_status_icon_set_blinking(gboolean val){
#ifdef HAVE_GTK_OSX
static gint attention_id;
GtkOSXApplication *theMacApp=(GtkOSXApplication*)g_object_new(GTK_TYPE_OSX_APPLICATION, NULL);

View file

@ -207,10 +207,10 @@
<child>
<object class="GtkCheckButton" id="mtu_set">
<property name="label" translatable="yes">Set Maximum Transmission Unit:</property>
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_action_appearance">False</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="linphone_gtk_mtu_set" swapped="no"/>
</object>
@ -247,10 +247,10 @@
<child>
<object class="GtkCheckButton" id="dtmf_sipinfo">
<property name="label" translatable="yes">Send DTMFs as SIP info</property>
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_action_appearance">False</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="linphone_gtk_use_sip_info_dtmf_toggled" swapped="no"/>
</object>
@ -263,11 +263,11 @@
<child>
<object class="GtkCheckButton" id="ipv6_enabled">
<property name="label" translatable="yes">Use IPv6 instead of IPv4</property>
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="use_action_appearance">False</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="linphone_gtk_ipv6_toggled" swapped="no"/>
</object>
@ -315,7 +315,7 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="n_rows">5</property>
<property name="n_rows">6</property>
<property name="n_columns">2</property>
<child>
<object class="GtkComboBox" id="proto_combo">
@ -377,23 +377,24 @@
<property name="label" translatable="yes">Tunnel</property>
</object>
<packing>
<property name="top_attach">4</property>
<property name="bottom_attach">5</property>
<property name="top_attach">5</property>
<property name="bottom_attach">6</property>
</packing>
</child>
<child>
<object class="GtkButton" id="tunnel_edit_button">
<property name="label" translatable="yes">edit</property>
<property name="use_action_appearance">False</property>
<property name="label">gtk-edit</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_action_appearance">False</property>
<property name="use_stock">True</property>
<signal name="clicked" handler="linphone_gtk_edit_tunnel" swapped="no"/>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">4</property>
<property name="bottom_attach">5</property>
<property name="top_attach">5</property>
<property name="bottom_attach">6</property>
</packing>
</child>
<child>
@ -462,6 +463,34 @@
<property name="bottom_attach">3</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label13">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">DSCP fields</property>
</object>
<packing>
<property name="top_attach">4</property>
<property name="bottom_attach">5</property>
</packing>
</child>
<child>
<object class="GtkButton" id="dscp_edit_button">
<property name="label">gtk-edit</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_action_appearance">False</property>
<property name="use_stock">True</property>
<signal name="clicked" handler="linphone_gtk_dscp_edit" swapped="no"/>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">4</property>
<property name="bottom_attach">5</property>
</packing>
</child>
</object>
</child>
</object>
@ -496,10 +525,10 @@
<child>
<object class="GtkRadioButton" id="no_nat">
<property name="label" translatable="yes">Direct connection to the Internet</property>
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_action_appearance">False</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="linphone_gtk_no_firewall_toggled" swapped="no"/>
@ -517,10 +546,10 @@
<child>
<object class="GtkRadioButton" id="use_nat_address">
<property name="label" translatable="yes">Behind NAT / Firewall (specify gateway IP below)</property>
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_action_appearance">False</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
<property name="group">no_nat</property>
@ -585,10 +614,10 @@
<child>
<object class="GtkRadioButton" id="use_stun">
<property name="label" translatable="yes">Behind NAT / Firewall (use STUN to resolve)</property>
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_action_appearance">False</property>
<property name="draw_indicator">True</property>
<property name="group">no_nat</property>
<signal name="toggled" handler="linphone_gtk_use_stun_toggled" swapped="no"/>
@ -602,10 +631,10 @@
<child>
<object class="GtkRadioButton" id="use_ice">
<property name="label" translatable="yes">Behind NAT / Firewall (use ICE)</property>
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_action_appearance">False</property>
<property name="draw_indicator">True</property>
<property name="group">no_nat</property>
<signal name="toggled" handler="linphone_gtk_use_ice_toggled" swapped="no"/>
@ -743,9 +772,6 @@
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="n_rows">6</property>
<property name="n_columns">2</property>
<child>
<placeholder/>
</child>
<child>
<object class="GtkHBox" id="ring_sound_box">
<property name="visible">True</property>
@ -767,11 +793,11 @@
<child>
<object class="GtkButton" id="play_ring">
<property name="label">gtk-media-play</property>
<property name="use_action_appearance">False</property>
<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>
<property name="use_action_appearance">False</property>
<property name="use_stock">True</property>
<signal name="clicked" handler="linphone_gtk_play_ring_file" swapped="no"/>
</object>
@ -944,10 +970,10 @@
<child>
<object class="GtkCheckButton" id="echo_cancelation">
<property name="label" translatable="yes">Enable echo cancellation</property>
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_action_appearance">False</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="linphone_gtk_echo_cancelation_toggled" swapped="no"/>
</object>
@ -958,6 +984,9 @@
<property name="bottom_attach">6</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</object>
</child>
</object>
@ -1293,10 +1322,10 @@
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<child>
<object class="GtkButton" id="wizard">
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_action_appearance">False</property>
<signal name="clicked" handler="linphone_gtk_display_wizard" swapped="no"/>
<child>
<object class="GtkHBox" id="hbox5">
@ -1340,11 +1369,11 @@
</child>
<child>
<object class="GtkButton" id="add_proxy">
<property name="use_action_appearance">False</property>
<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>
<property name="use_action_appearance">False</property>
<signal name="clicked" handler="linphone_gtk_add_proxy" swapped="no"/>
<child>
<object class="GtkHBox" id="hbox14">
@ -1388,11 +1417,11 @@
</child>
<child>
<object class="GtkButton" id="edit_proxy">
<property name="use_action_appearance">False</property>
<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>
<property name="use_action_appearance">False</property>
<signal name="clicked" handler="linphone_gtk_edit_proxy" swapped="no"/>
<child>
<object class="GtkHBox" id="hbox16">
@ -1436,11 +1465,11 @@
</child>
<child>
<object class="GtkButton" id="remove_proxy">
<property name="use_action_appearance">False</property>
<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>
<property name="use_action_appearance">False</property>
<signal name="clicked" handler="linphone_gtk_remove_proxy" swapped="no"/>
<child>
<object class="GtkHBox" id="hbox7">
@ -1484,9 +1513,9 @@
</child>
<child>
<object class="GtkButton" id="create_phonics">
<property name="use_action_appearance">False</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_action_appearance">False</property>
<signal name="clicked" handler="linphone_gtk_create_fonics_account" swapped="no"/>
<child>
<object class="GtkHBox" id="hbox1">
@ -1573,11 +1602,11 @@ virtual network !</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="GtkButton" id="erase_passwords">
<property name="use_action_appearance">False</property>
<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>
<property name="use_action_appearance">False</property>
<signal name="clicked" handler="linphone_gtk_clear_passwords" swapped="no"/>
<child>
<object class="GtkHBox" id="hbox18">
@ -1759,11 +1788,11 @@ virtual network !</property>
<child>
<object class="GtkButton" id="button4">
<property name="label">gtk-go-up</property>
<property name="use_action_appearance">False</property>
<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>
<property name="use_action_appearance">False</property>
<property name="use_stock">True</property>
<signal name="clicked" handler="linphone_gtk_codec_up" swapped="no"/>
</object>
@ -1776,11 +1805,11 @@ virtual network !</property>
<child>
<object class="GtkButton" id="up_codec">
<property name="label">gtk-go-down</property>
<property name="use_action_appearance">False</property>
<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>
<property name="use_action_appearance">False</property>
<property name="use_stock">True</property>
<signal name="clicked" handler="linphone_gtk_codec_down" swapped="no"/>
</object>
@ -1792,11 +1821,11 @@ virtual network !</property>
</child>
<child>
<object class="GtkButton" id="enable_codec">
<property name="use_action_appearance">False</property>
<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>
<property name="use_action_appearance">False</property>
<signal name="clicked" handler="linphone_gtk_codec_enable" swapped="no"/>
<child>
<object class="GtkHBox" id="hbox8">
@ -1840,11 +1869,11 @@ virtual network !</property>
</child>
<child>
<object class="GtkButton" id="disable_codec">
<property name="use_action_appearance">False</property>
<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>
<property name="use_action_appearance">False</property>
<signal name="clicked" handler="linphone_gtk_codec_disable" swapped="no"/>
<child>
<object class="GtkHBox" id="hbox9">
@ -2007,10 +2036,10 @@ virtual network !</property>
<child>
<object class="GtkCheckButton" id="adaptive_rate_control">
<property name="label" translatable="yes">Enable adaptive rate control</property>
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_action_appearance">False</property>
<property name="xalign">0</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="linphone_gtk_adaptive_rate_control_toggled" swapped="no"/>
@ -2162,10 +2191,10 @@ virtual network !</property>
<child>
<object class="GtkCheckButton" id="ui_level">
<property name="label" translatable="yes">Show advanced settings</property>
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_action_appearance">False</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="linphone_gtk_ui_level_toggled" swapped="no"/>
</object>
@ -2242,11 +2271,11 @@ virtual network !</property>
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="button5">
<property name="use_action_appearance">False</property>
<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>
<property name="use_action_appearance">False</property>
<signal name="clicked" handler="linphone_gtk_parameters_closed" swapped="no"/>
<child>
<object class="GtkHBox" id="hbox3">

View file

@ -1131,3 +1131,55 @@ void linphone_gtk_tunnel_ok(GtkButton *button){
void linphone_gtk_tunnel_cancel(GtkButton *button){
}
static void show_dscp(GtkWidget *entry, int val){
char tmp[20];
snprintf(tmp,sizeof(tmp),"0x%x",val);
gtk_entry_set_text(GTK_ENTRY(entry),tmp);
}
static int read_dscp(GtkWidget *entry){
const char *val=gtk_entry_get_text(GTK_ENTRY(entry));
const char *begin;
int ret=0;
if (val==NULL || val[0]=='\0') return 0;
/*skip potential 0x*/
begin=strstr(val,"0x");
if (begin) begin+=2;
else begin=val;
if (sscanf(begin,"%x",&ret)==1)
return ret;
return -1;
}
void linphone_gtk_dscp_edit(){
LinphoneCore *lc=linphone_gtk_get_core();
GtkWidget *widget=linphone_gtk_create_window("dscp_settings");
show_dscp(linphone_gtk_get_widget(widget,"sip_dscp"),
linphone_core_get_sip_dscp(lc));
show_dscp(linphone_gtk_get_widget(widget,"audio_dscp"),
linphone_core_get_audio_dscp(lc));
show_dscp(linphone_gtk_get_widget(widget,"video_dscp"),
linphone_core_get_video_dscp(lc));
gtk_widget_show(widget);
}
void linphone_gtk_dscp_edit_response(GtkWidget *dialog, guint response_id){
LinphoneCore *lc=linphone_gtk_get_core();
switch(response_id){
case GTK_RESPONSE_OK:
linphone_core_set_sip_dscp(lc,
read_dscp(linphone_gtk_get_widget(dialog,"sip_dscp")));
linphone_core_set_audio_dscp(lc,
read_dscp(linphone_gtk_get_widget(dialog,"audio_dscp")));
linphone_core_set_video_dscp(lc,
read_dscp(linphone_gtk_get_widget(dialog,"video_dscp")));
break;
default:
break;
}
gtk_widget_destroy(dialog);
}

View file

@ -21,7 +21,7 @@ package org.linphone.core;
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)}
* Object representing a call. Calls are created using {@link LinphoneCore#invite(LinphoneAddress)} or passed to the application by listener {@link LinphoneCoreListener#callState}
*
*/

View file

@ -0,0 +1,90 @@
package org.linphone.core;
import java.util.Vector;
public interface LinphoneChatMessage {
interface StateListener{
void onLinphoneChatMessageStateChanged(LinphoneChatMessage msg, State state);
}
static class State {
@SuppressWarnings("rawtypes")
static private Vector values = new Vector();
private final int mValue;
public final int value() {return mValue;}
private final String mStringValue;
/**
* Idle
*/
public final static State Idle = new State(0,"Idle");
/**
* Incoming call received.
*/
public final static State InProgress = new State(1,"InProgress");
/**
* Outgoing call initialiazed.
*/
public final static State Delivered = new State(2,"Delivered");
/**
* Outgoing call in progress.
*/
public final static State NotDelivered = new State(3,"NotDelivered");
@SuppressWarnings("unchecked")
private State(int value,String stringValue) {
mValue = value;
values.addElement(this);
mStringValue=stringValue;
}
public static State fromInt(int value) {
for (int i=0; i<values.size();i++) {
State state = (State) values.elementAt(i);
if (state.mValue == value) return state;
}
throw new RuntimeException("state not found ["+value+"]");
}
public String toString() {
return mStringValue;
}
public int toInt() {
return mValue;
}
}
long getNativePtr();
Object getUserData();
void setUserData();
/**
* get text associated to this LinphoneChatMessage
*
* @return text sent along with the message
*/
String getMessage();
/**
* get peer address associated to this LinphoneChatMessage
*
* @return LinphoneAddress peer address
*/
LinphoneAddress getPeerAddress();
/**
* Linphone message can carry external body as defined by rfc2017
* @param message #LinphoneChatMessage
* @return return external body url null if not present.
*/
String getExternalBodyUrl();
/**
* Linphone message can carry external body as defined by rfc2017
* @param #LinphoneChatMessage
* @param url ex: access-type=URL; URL="http://www.foo.com/file"
*/
void setExternalBodyUrl(String url);
}

View file

@ -35,5 +35,23 @@ public interface LinphoneChatRoom {
* @param message to be sent
*/
void sendMessage(String message);
/**
* Send a message to peer member of this chat room.
* @param chat message
*/
void sendMessage(LinphoneChatMessage message, LinphoneChatMessage.StateListener listener);
/**
* DEPRECATED
* @param opaque
* @param message
*/
void sendMessage(Object opaque, String message);
/**
* Create a LinphoneChatMessage
* @param chatRoom chat room associated to the message
* @param message message to send
* @return LinphoneChatMessage object
*/
LinphoneChatMessage createLinphoneChatMessage(String message);
}

View file

@ -373,7 +373,7 @@ public interface LinphoneCore {
* Accept an incoming call.
*
* Basically the application is notified of incoming calls within the
* {@link LinphoneCoreListener#inviteReceived(LinphoneCore, String)} listener.
* {@link LinphoneCoreListener#callState} listener method.
* The application can later respond positively to the call using
* this method.
* @throws LinphoneCoreException
@ -384,7 +384,7 @@ public interface LinphoneCore {
* Accept an incoming call.
*
* Basically the application is notified of incoming calls within the
* {@link LinphoneCoreListener#inviteReceived(LinphoneCore, String)} listener.
* {@link LinphoneCoreListener#callState} listener method.
* The application can later respond positively to the call using
* this method.
* @throws LinphoneCoreException
@ -395,7 +395,7 @@ public interface LinphoneCore {
* Accept call modifications initiated by other end.
*
* Basically the application is notified of incoming calls within the
* {@link LinphoneCoreListener#inviteReceived(LinphoneCore, String)} listener.
* {@link LinphoneCoreListener#callState} listener method.
* The application can later respond positively to the call using
* this method.
* @throws LinphoneCoreException
@ -407,7 +407,7 @@ public interface LinphoneCore {
* Prevent LinphoneCore from performing an automatic answer
*
* Basically the application is notified of incoming calls within the
* {@link LinphoneCoreListener#inviteReceived(LinphoneCore, String)} listener.
* {@link LinphoneCoreListener#callState} listener method.
* The application can later respond positively to the call using
* this method.
* @throws LinphoneCoreException

View file

@ -24,27 +24,10 @@ package org.linphone.core;
*This interface holds all callbacks that the application should implement. None is mandatory.
*/
public interface LinphoneCoreListener {
/**< Notifies the application that it should show up
* @return */
void show(LinphoneCore lc);
/**< Ask the application some authentication information
* @return */
void authInfoRequested(LinphoneCore lc,String realm,String username);
/**< Callback that notifies various events with human readable text.
* @return */
void displayStatus(LinphoneCore lc,String message);
/**< Callback to display a message to the user
* @return */
void displayMessage(LinphoneCore lc,String message);
/** Callback to display a warning to the user
* @return */
void displayWarning(LinphoneCore lc,String message);
/** General State notification
* @param state LinphoneCore.State
* @return
@ -93,7 +76,16 @@ public interface LinphoneCoreListener {
* @param from LinphoneAddress from
* @param message incoming message
*/
void textReceived(LinphoneCore lc, LinphoneChatRoom cr,LinphoneAddress from,String message);
void textReceived(LinphoneCore lc, LinphoneChatRoom cr, LinphoneAddress from, String message);
/**
* invoked when a new linphone chat message is received
* @param lc LinphoneCore
* @param room LinphoneChatRoom involved in this conversation. Can be be created by the framework in case the from is not present in any chat room.
* @param from LinphoneAddress from
* @param message incoming linphone chat message message
*/
void messageReceived(LinphoneCore lc, LinphoneChatRoom cr, LinphoneAddress from, LinphoneChatMessage message);
/**
* Invoked when echo cancalation calibration is completed
@ -112,5 +104,22 @@ public interface LinphoneCoreListener {
*
*/
void notifyReceived(LinphoneCore lc, LinphoneCall call, LinphoneAddress from, byte[] event);
/**< @Deprecated Notifies the application that it should show up
* @return */
void show(LinphoneCore lc);
/**< @Deprecated Callback that notifies various events with human readable text.
* @return */
void displayStatus(LinphoneCore lc,String message);
/**< @Deprecated Callback to display a message to the user
* @return */
void displayMessage(LinphoneCore lc,String message);
/** @Deprecated Callback to display a warning to the user
* @return */
void displayWarning(LinphoneCore lc,String message);
}

View file

@ -133,4 +133,10 @@ public interface LinphoneProxyConfig {
* @param delay expiration time in seconds
*/
void setExpires(int delay);
/**
* Sets parameters for the contact
* @param parameters to add
*/
public void setContactParameters(String params);
}

View file

@ -41,14 +41,18 @@ Liblinphone is a high level library for bringing SIP video call functionnality i
LibLinphone package is organized in submodules.
<ul>
<li><a href="#proxy">Managing proxies</a>
<li><a href="#proxy">Managing proxies</a></li>
</ul>
<ul>
<li><a href="#buddy">Managing Buddies and buddy list and presence</a>
<li><a href="#buddy">Managing Buddies and buddy list and presence</a></li>
</ul>
<ul>
<li><a href="#chat">Chat room and Messaging</a>
<li><a href="#chat">Chat room and Messaging</a></li>
</ul>
<ul>
<li><a href="#echo">Sound and echo cancellation settings</a></li>
</ul>
<h2>Related Documentation</h2>
@ -155,7 +159,12 @@ Any subsequente modifications to {@link org.linphone.core.LinphoneFriend} must b
my_friend.enableSubscribes(true); /*disable subscription for this friend*/
my_friend.done(); /*commit changes triggering an UNSUBSCRIBE message*/
</code>
</pre>
</pre> Do not display status messages
-J<flag> Pass <flag> directly to the runtime system
Provided by Standard doclet:
-d <directory> Destination directory for output files
-use
<b> Publishing presence status </b>
<br>Local presence status can be changed using function {@link org.linphone.core.LinphoneCore#setPresenceInfo }.New status is propagated to all friends {@link org.linphone.core.LinphoneCore#addFriend(LinphoneFriend lf) previously added } to LinphoneCore.
@ -189,6 +198,80 @@ from a peer sip uri.
System.out.println("Message ["+message+"] received from ["+from+"] ");
}
</code>
</pre>
<h3>
<a name="echo">Sound and echo cancellation settings</a>
</h3>
<b>Sound levels</b>
<br>
It is possible to tune the microphone input gain and speaker/receiver output gain by setting parameters into the linphonerc factory config file loaded when instanciating the {@link org.linphone.core.LinphoneCore LinphoneCore}. These gains are liblinphone's internal software gains and are unrelated to volume levels managed by the operating system. For example: <br>
<pre>
<code>
[sound]
#set the speaker or receiver playback gain in dbm0 (0 db = no change).
playback_gain_db=-3
#set the microphone gain in linear scale:
mic_gain=0.1
</code>
</pre>
<br>
<b>Echo cancellation</b>
<br>
On Android devices, echo is a problem, especially with low-end devices. The root cause is the unpredictable latency of Android's sound system. The liblinphone software {@link org.linphone.core.LinphoneCore#enableEchoCancellation echo canceller} that is operating well on desktop platforms (Mac, Linux, Windows) is unable to operate under Android platform. The situation is very heterogenous:<br>
<ul>
<li>On new (after 2011) high end devices, manufacturers often include a hardware echo cancellation. If available, liblinphone will make use of it and no software correction is required.
Source file linphone-android/submodules/linphone/mediastreamer2/java/src/org/linphone/mediastream/video/capture/hwconf/Hacks.java contains a method hasBuiltInEchoCanceller() that returns true if an hardware echo canceller is available, based on device model identifier. The current list is incomplete.
</li>
<li>On former models with decent CPU power (armv7), sound system behaves in a nearly predictive way so that it is possible to use {@link org.linphone.core.LinphoneCore#enableEchoLimiter echo limiter}. Echo limiter is a simple echo attenuation technique which consists in strongly attenuating the microphone input when speaker is playing voice, in order to cut the echo. The main drawback of echo limiter is that the conversation is perceived as half duplex by users, because they won't hear background noise from the remote side while they are speaking.
</li>
<li>On low class android devices or very old models (armv5 processor), no solution works.
</li>
</ul>
<br>
In order to benefit from the best echo cancellation solution, we recommend applications to run the following algorithm, when it is run for the first time:<br>
First of {@link org.linphone.core.LinphoneCore#enableEchoCancellation echo canceller} should not be used, in any case.
<ul>
<li>Use the Hacks.hasBuiltInEchoCanceller() method to first check if the device has hardware echo canceller. If yes, then echo limiter must be turned off.</li>
<li>If no the hasBuiltInEchoCanceller() returned false, then it is possible to use the echo calibration procedure. If the calibration procedure fails, it means that
probably the phone performs hardware echo cancellation, so in this case echo limiter must be turned off.</li>
<li>If the echo calibration succeeded, then echo is present, so it is recommended to enable echo limiter.
</ul>
<br>
<b>Echo calibration procedure</b>
<br>
The echo calibration procedure is a five second test which consists in playing small beeps to the speaker while the microphone input is recorded.
If the device is subject to echo (or doesn't have hardware echo cancellation), then beeps recorded by the microphone will be detected and a measurement of echo delay can be computed.
Echo calibration procedure can be started by calling {@link org.linphone.core.LinphoneCore#startEchoCalibration LinphoneCore.startEchoCalibration}.
<br><br>
<b>Echo limiter settings</b><br>
Echo limiter requires settings to be defined in linphonerc factory config file for correction operation.
Typical settings are:
<pre>
<code>
[sound]
el_type=mic
#speaker energy threshold (linear scale) above which echo limiter decreases mic gain.
el_thres=0.03
#attenuation applied to mic gain (linear scale)
el_force=100000
#minimum time in milliseconds during which attenuation is applied
el_sustain=600
#double talk detection: threshold of ratio mic-energy/speaker-energy above which mic input is sent anyway.
el_transmit_thres=1.7
#noise gate floorgain (gain applied when no voice is detected).
ng_floorgain=0.01
</code>
</pre>
Up to date settings must be found from linphone-android/res/raw/linphonerc file.
<br>
</body>
</html>

View file

@ -1,3 +0,0 @@
.deps
Makefile
Makefile.in

View file

@ -1,135 +0,0 @@
MEDIA API DESIGN DRAFT
**********************
The objective of the media_api is to construct and run the necessary
processing on audio and video data flows for a given call (two party call) or
conference.
The media_api must support calls where callmember can be remote as well
local hosted, in other words the media_api can be used inside linphone as
well as in sip conferencing server. The api must support multiples way of
getting media data: from disk, from rtp, from soundcard...
The media_api is object oriented in C, and is based on the mediastreamer library
to deal with audio or video signals, and on glib for types and usefull routines.
The api must provide object and methods that describes the call, and then functions
that executes the processing (using the mediastreamer) that is necessary for the
call described.
Proposed API:
************************************************************************
object: MediaFlow
This object reprensent a media that is shared between all members of the call,
for example voice.
methods:
MediaFlow *media_flow_new(char *id_string,gint type,gint duplex);
type can be FLOW_AUDIO, FLOW_VIDEO.
if duplex is 1, it means that the media flow is used by every member in both
receiving and sending mode.
id_string is just a string to identify the flow.
void media_flow_destroy(MediaFlow *flow);
destructor
**************************************************************************
object: CallMember
This object reprensent a member of a call.
methods:
CallMember *call_member_new();
gint call_member_setup_flow(CallMember *member, MediaFlow *flow,
char *rx_endpoint, char *tx_endpoint);
This is the most important function of the API. It describes the way each
call member receives and send a given media flow.
The MediaFlow "flow" is added to the list of flows used by the member "member".
rx_endpoint is a string that described how data is received by the call member.
It should be an url, for example "rtp://213.21.54.127:7080". In this case it
means that data will be received on port 7080 at ip address 213.21.54.127.
tx_endpoint is a string that described how data is sent by the call member.
The role of url is very important. They can be:
"rtp://213.21.54.127:7080"
"file://tmp/media.out" -a file on disk
"oss://0" -souncard 0 using oss api
"alsa://0" -soundcard 0 using alsa api.
In order to work, the call member must be part of a BasicCall, as well as
the flow must be part of the BasicCall too (using basic_call_add_flow())
This function may (on the backend) create a MediaEndpoint object that stores
the rx_endpoint and tx_endpoint parameter. This object is added to:
-the list of MediaEndpoint maintained by the member (list per member)
-the list of MediaEndpoint maintained by the flow (list per flow)
**************************************************************************
object: BasicCall
This object handles simple calls (two party calls). It defines inside itself
two CallMember objects.
method:
BasicCall *basic_call_new();
CallMember *basic_call_get_member(BasicCall *call, gint member_number);
Returns a member of a BasicCall according to a number.
void basic_call_add_flow(BasicCall *call, MediaFlow *flow);
Adds a flow to the call's list of flow.
gint basic_call_start_flow(BasicCall *call, MediaFlow *flow);
This function construct the mediastreamer processing chain necessary to make
the call running, if not done, and runs it using ms_start()
gint basic_call_stop_flow(BasicCall *call, MediaFlow *flow);
gint basic_call_start_all_flows(BasicCall *call);
void basic_call_destroy(BasicCall *call);
Destroy all data used by the call: call members, call flows.
**************************************************************************
object: ConferenceCall
This object handles conference call (which are quite much complicated than basic
calls). But this object should have the same method as the BasicCall object.
*******************************************************************
EXAMPLE
*******************************************************************
Two party call between call member A on machine "linphone.org" and call member B on machine "home.com".
The media_api is running on "home.com".
A (on linphone.org) B (on home.com)
------>(send to rtp://home.com:7080 MSRTPReceiver------>Decode----->(send to oss:/0)
------<(recv on rtp://linphone.org:7020 MSRTPSender<--------Encode<-----(read on oss://0)
This is how to setup this call using the media_api:
BasicCall *call;
CallMember *memberA,*memberB;
MediaFlow *flow;
/* create a basic call*/
call=basic_call_new();
/* get a pointer to the pre-define members of the call */
memberA=basic_call_get_member(call,0);
memberB=basic_call_get_member(call,1);
/* create a media flow */
flow=media_flow_new("voice",FLOW_AUDIO,1);
/* tell that the flow is used by the call */
basic_call_add_flow(call,flow);
/* tell how each member uses the flow (how is the interface ?)*/
call_member_setup_flow(memberA,flow,"rtp://linphone.org:7020","rtp://home.com:7080");
/* note: it is not efficient to do name resolution at this stage: that's why in reality numeric ip address
should be given instead of host name */
call_member_setup_flow(memberB,flow,"oss://0","oss://0");
/* start the flow */
basic_call_start_flow(call,flow);
In case where the media api is running on another host called "toto" (in a media translator application for example),
the only thing that would change is the url given to memberB: tx="rtp://home.com:8820" for example and
rx="rtp://toto:9522".
In the sipomatic application (the test application I use to test linphone (it answers to call and plays
a short annoucement)), I would write rx="file://path_to_annoucement.raw" and tx="file://dev/null" instead of
"oss://0".

View file

@ -1,31 +0,0 @@
## Process this file with automake to produce Makefile.in
if BUILD_MEDIA_API
#the media_api library is the only one we have to build here
lib_LTLIBRARIES=libmedia_api.la
#definition of the sources of libmedia_api
libmedia_api_la_SOURCES= basiccall.c callmember.c mediaflow.c
# libmedia_api needs libmediastreamer
libmedia_api_la_LIBADD=$(top_srcdir)/mediastreamer/libmediastreamer.la
#the media_api test program
bin_PROGRAMS=apitest
apitest_SOURCES= apitest.c
# the test program links to libmedia_api
apitest_LDADD=libmedia_api.la
endif
DEFS=@DEFS@ @SOUNDDEFS@ -DDEBUG -DG_LOG_DOMAIN=\"MediaApi\"
INCLUDES=-I$(top_srcdir)/mediastreamer \
-I$(top_srcdir)/speex \
-I$(top_srcdir)/gsmlib \
$(ORTP_CFLAGS) \
-I$(top_srcdir)/lpc10-1.5 \
-I$(top_srcdir)/ffmpeg

View file

@ -1,36 +0,0 @@
#include "basiccall.h"
#include <signal.h>
static int flag = 1;
void stop(int sign){
flag = 0;
}
int main(){
BasicCall *call;
char *id;
CallMember *memberA, *memberB;
MediaFlow *flow, *flow1;
signal(SIGINT, stop);
call = basic_call_new();
memberA = basic_call_get_member(call,MemberA);
memberB = basic_call_get_member(call,MemberB);
id = "test_voice";
printf("\n");
flow = media_flow_new(id, MEDIA_FLOW_VOICE);
basic_call_add_flow(call, flow);
call_member_setup_flow(memberA, flow, "file://temp", "oss://0");
call_member_setup_flow(memberB, flow, "oss://0", "oss://0");
media_flow_setup_fd(flow, memberA, memberB, MEDIA_FLOW_HALF_DUPLEX);
basic_call_start_flow(call, flow);
while(flag){
sleep(1);
}
}

View file

View file

@ -1,170 +0,0 @@
/*
The objective of the media_api is to construct and run the necessary processing
on audio and video data flows for a given call (two party call) or conference.
Copyright (C) 2001 Sharath Udupa skuds@gmx.net
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "basiccall.h"
#include "../mediastreamer/mscodec.h"
#define ONESYNC 10
#define MULTISYNC 20
BasicCall *basic_call_new(){
BasicCall *bc = (BasicCall*) g_malloc(sizeof(BasicCall));
api_trace("basic_call_new: creating a basic call");
bc->memberA = call_member_new("memberA");
bc->memberB = call_member_new("memberB");
return bc;
}
CallMember *basic_call_get_member(BasicCall *call, int member_nu){
api_trace("basic_call_get_member: called for %d",member_nu);
if(member_nu == MemberA){
return call->memberA;
}
else if(member_nu == MemberB){
return call->memberB;
}
}
void basic_call_add_flow(BasicCall *call, MediaFlow *flow){
api_trace("basic_call_add_flow: called for %s",flow->id);
call->flows = g_list_append( call->flows, flow);
return 1;
}
int find_mediaflow(gconstpointer llist, gconstpointer flow){
//MediaFlow *mf = (MediaFlow *) ((BasicCallFlow*)llist)->mediaFlow;
if(((MediaFlow*)flow)->id == ((MediaFlow*)llist)->id){
return 0;
}
return 1;
}
int basic_call_start_flow(BasicCall *call, MediaFlow *flow){
int i=0;
int syncFlag=0;
int nFlowDirections;
MSSync *sync;
Members *source, *destination;
FlowDirections *fd;
GList *elem, *selem;
GList *snd_read = NULL, *snd_write = NULL, *filter = NULL;
//Commented by Sharat
//This is initialized in media_api.c
//when should these functions be really called?
//ms_init();
//ortp_init();
api_trace("basic_call_start_flow: called for flow %s", flow->id);
elem = g_list_find_custom( call->flows, flow, &find_mediaflow);
if(elem == NULL){
api_error("basic_call_start_flow: Called for unregistered mediaflow %s", flow->id);
}
nFlowDirections = g_list_length(flow->flowDirections);
if(flow->type == MEDIA_FLOW_VOICE){
syncFlag = ONESYNC;
sync = ms_timer_new();
}
else{
syncFlag = MULTISYNC;
}
for(i=0;i< nFlowDirections; i++){
if(syncFlag == MULTISYNC){
sync = ms_timer_new();
}
fd = (FlowDirections*)g_list_nth_data(flow->flowDirections,i);
source = fd->source;
destination = fd->destination;
media_flow_start_fd(fd, sync);
if(fd->type == MEDIA_FLOW_DUPLEX){
switch(source->tx_endpoint->protocol){
case MEDIA_ALSA:
case MEDIA_OSS:
snd_read = g_list_append(snd_read, fd->recv);
}
switch(destination->rx_endpoint->protocol){
case MEDIA_ALSA:
case MEDIA_OSS:
snd_write = g_list_append(snd_write, fd->play);
}
switch(destination->tx_endpoint->protocol){
case MEDIA_ALSA:
case MEDIA_OSS:
snd_read = g_list_append(snd_read, fd->read);
}
switch(source->rx_endpoint->protocol){
case MEDIA_ALSA:
case MEDIA_OSS:
snd_write = g_list_append(snd_write, fd->send);
}
}
else if(fd->type == MEDIA_FLOW_HALF_DUPLEX){
switch(source->tx_endpoint->protocol){
case MEDIA_ALSA:
case MEDIA_OSS:
snd_read = g_list_append(snd_read, fd->recv);
}
switch(destination->rx_endpoint->protocol){
case MEDIA_ALSA:
case MEDIA_OSS:
snd_write = g_list_append(snd_write, fd->play);
}
}
if(syncFlag == MULTISYNC){
flow->sync = g_list_append(flow->sync, sync);
}
}
if(syncFlag == ONESYNC){
ms_start(sync);
flow->sync = g_list_append(flow->sync, sync);
}
if(syncFlag == MULTISYNC){
selem = flow->sync;
while(selem != NULL){
ms_start(selem->data);
selem = g_list_next(selem);
}
}
filter = snd_read;
while(filter != NULL){
ms_sound_read_start(MS_SOUND_READ((MSFilter*)filter->data));
filter = g_list_next(filter);
}
filter = snd_write;
while(filter != NULL){
ms_sound_write_start(MS_SOUND_WRITE((MSFilter*)filter->data));
filter = g_list_next(filter);
}
return 1;
}
int basic_call_stop_flow(BasicCall *call, MediaFlow *flow){
}

View file

@ -1,51 +0,0 @@
/*
The objective of the media_api is to construct and run the necessary processing
on audio and video data flows for a given call (two party call) or conference.
Copyright (C) 2001 Sharath Udupa skuds@gmx.net
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "common.h"
#include "mediaflow.h"
#include "callmember.h"
//other includes required to be done here
#define MemberA 1
#define MemberB 2
struct _BasicCall{
CallMember *memberA, *memberB;
GList *flows; //linked list of MediaFlows
};
typedef struct _BasicCall BasicCall;
BasicCall *basic_call_new();
CallMember *basic_call_get_member(BasicCall *call, int member_nu);
void basic_call_add_flow(BasicCall *call, MediaFlow *flow);
int basic_call_start_flow(BasicCall *call, MediaFlow *flow);
int basic_call_stop_flow(BasicCall *call, MediaFlow *flow);
int basic_call_start_all_flows(BasicCall *call);
int basic_call_destroy(BasicCall *call);

View file

@ -1,153 +0,0 @@
/*
The objective of the media_api is to construct and run the necessary processing
on audio and video data flows for a given call (two party call) or conference.
Copyright (C) 2001 Sharath Udupa skuds@gmx.net
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <string.h>
#include "common.h"
#include "callmember.h"
#include "mediaflow.h"
CallMember *call_member_new(char *name){
CallMember *member = (CallMember*) g_malloc(sizeof(CallMember));
api_trace("call_member_new: creating %s", name);
member->name = name;
member->flows = NULL;
member->profile = NULL;
return member;
}
int call_member_set_rtp_profile(CallMember *member, RtpProfile *profile){
member->profile = profile;
return 1;
}
int call_member_setup_flow(CallMember *member, MediaFlow *flow, char* rx, char *tx){
Members *mem = (Members*) g_malloc(sizeof(Members));
Flows *flows = (Flows*) g_malloc(sizeof(Flows));
api_trace("call_member_setup_flow: setting up flow for: CallMember->%s , MediaFlow->%s", member->name, flow->id);
mem->member = member;
mem->rx_endpoint = parse_end_point(rx);
mem->tx_endpoint = parse_end_point(tx);
flow->members = g_list_append(flow->members, mem);
flows->flow = flow;
flows->rx_endpoint = parse_end_point(rx);
flows->tx_endpoint = parse_end_point(tx);
member->flows = g_list_append(member->flows, flows);
return 1;
}
EndPoint *parse_end_point(char *endpoint){
EndPoint *result = (EndPoint*) g_malloc(sizeof(EndPoint));
int i=0,len1,len2,len, tlen;
char *str2, temp[30], *host_str;
//api_trace("parse_end_point: parsing %s\n", endpoint);
result->pt = -1;
while(1){
str2 = (char*) strpbrk(endpoint, ":");
if(str2 == NULL){
str2 = (char*) strpbrk(endpoint, ";");
if(str2 == NULL){
len = strlen(endpoint);
}
else{
len1 = strlen(endpoint);
len2 = strlen(str2);
len = len1-len2;
}
}
else{
len1 = strlen(endpoint);
len2 = strlen(str2);
len = len1-len2;
}
strncpy(temp,endpoint,len);
temp[len] = '\0';
tlen = strlen(temp);
if((tlen >= 2)&&(temp[0] == '/')&&(temp[1] == '/')){
host_str = remove_slash(temp);
}
switch(i){
case 0: if(strcmp(temp,"rtp")==0){
result->protocol=MEDIA_RTP;
}
else if(strcmp(temp,"oss")==0){
result->protocol=MEDIA_OSS;
}
else if(strcmp(temp,"alsa")==0){
result->protocol=MEDIA_ALSA;
}
else if(strcmp(temp,"file")==0){
result->protocol=MEDIA_FILE;
}
break;
case 1: if(result->protocol==MEDIA_FILE){
result->file=host_str;
}
else{
result->host = host_str;
}
break;
case 2: result->port = to_digits(temp);
break;
case 3: result->pt = pt_digits(temp);
break;
default://result->options[result->nOptions++] = temp;
break;
}
if(str2 != NULL) endpoint = str2+1;
else break;
i++;
}
return result;
}
int to_digits(char *str){
int nu=0,a,len,i;
len = strlen(str);
for(i=0;i<len;i++){
a=str[i];
a=a-'0';
nu = nu*10+a;
}
return nu;
}
int pt_digits(char *str){
int len;
len = strlen(str);
if((len>3)&&(str[0]=='p')&&(str[1]=='t')&&(str[2]=='=')){
return to_digits(str+3);
}
else{
api_warn("Wrong parameters passed in the endpoints");
return 0;
//ERROR handling
}
}
char *remove_slash(char var[]){
char *temp = (char*) g_malloc(10*sizeof(char));
int len,i;
len=strlen(var);
for(i=2;i<len;i++){
temp[i-2]=var[i];
}
return temp;
}

View file

@ -1,59 +0,0 @@
/*
The objective of the media_api is to construct and run the necessary processing
on audio and video data flows for a given call (two party call) or conference.
Copyright (C) 2001 Sharath Udupa skuds@gmx.net
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
struct _CallMember{
char *name;
GList *flows;
RtpProfile *profile;
};
typedef struct _CallMember CallMember;
struct _EndPoint{
int protocol;
char *host;
char *file;
int port;
int pt;
};
typedef struct _EndPoint EndPoint;
struct _Flows{
struct _MediaFlow *flow;
EndPoint *rx_endpoint;
EndPoint *tx_endpoint;
};
typedef struct _Flows Flows;
CallMember *call_member_new(char *);
int call_member_setup_flow(CallMember *member, struct _MediaFlow *flow, char *rx_enndpoint, char *tx_endpoint);
/* Internal functions */
EndPoint *parse_end_point(char *endpoint);
char *remove_slash(char[]);
int to_digits(char*);
int pt_digits(char*);

View file

@ -1 +0,0 @@
gcc -I/home/skudupa/linphone/mediastreamer -I/home/skudupa/linphone/ffmpeg/libavcodec -I/home/skudupa/linphone/gsmlib -I/home/skudupa/linphone/lpc10-1.5 -I/home/skudupa/linphone/oRTP/src -I/usr/include/glib-1.2 -I/usr/lib/glib/include -I/usr/include/gtk-1.2 -I/usr/include/glib-1.2 -I/usr/lib/glib/include -I/usr/X11R6/include -I/home/skudupa/linphone/oRTP mediaflow.c

View file

@ -1,31 +0,0 @@
#ifndef COMMON_H
#define COMMON_H
#include "media_api.h"
#include <glib.h>
#define api_trace g_message
#define api_error g_error
#define api_warn g_warning
#define MEDIA_FLOW_DUPLEX 1
#define MEDIA_FLOW_HALF_DUPLEX 2
//Mediaflow type
#define MEDIA_FLOW_VIDEO 1
#define MEDIA_FLOW_VOICE 2
//Mediaflow protocols
#define MEDIA_RTP 1
#define MEDIA_OSS 2
#define MEDIA_ALSA 3
#define MEDIA_FILE 4
//Mediaflow codec function
#define MEDIA_API_DECODER 1
#define MEDIA_API_ENCODER 2
#endif

View file

@ -1,69 +0,0 @@
/*
The objective of the media_api is to construct and run the necessary processing
on audio and video data flows for a given call (two party call) or conference.
Copyright (C) 2001 Sharath Udupa skuds@gmx.net
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "media_api.h"
/* non-standard payload types for oRTP */
PayloadType lpc1015={
PAYLOAD_AUDIO_PACKETIZED,
8000,
0,
NULL,
0,
2400,
"1015/8000/1"
};
PayloadType speex_nb={
PAYLOAD_AUDIO_PACKETIZED,
8000,
0,
NULL,
0,
15000,
"speex/8000/1"
};
PayloadType speex_nb_lbr={
PAYLOAD_AUDIO_PACKETIZED,
8000,
0,
NULL,
0,
8000,
"speex-lbr/8000/1"
};
void media_api_init()
{
ortp_init();
ortp_set_debug_file("oRTP",NULL);
rtp_profile_set_payload(&av_profile,115,&lpc1015);
rtp_profile_set_payload(&av_profile,110,&speex_nb);
rtp_profile_set_payload(&av_profile,111,&speex_nb_lbr);
rtp_profile_set_payload(&av_profile,101,&telephone_event);
ms_init();
ms_speex_codec_init();
#ifdef HAVE_AVCODEC
ms_AVCodec_init();
#endif
}

View file

@ -1,69 +0,0 @@
/*
The objective of the media_api is to construct and run the necessary processing
on audio and video data flows for a given call (two party call) or conference.
Copyright (C) 2001 Sharath Udupa skuds@gmx.net
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef MEDIA_API_H
#define MEDIA_API_H
/* some mediastreamer include files....*/
#include "ms.h"
/* audio codecs ; all these header are not really required as we should use ms_codec_new..() to
create codec filters*/
/*Commented by Sharath Udupa
#include <mscodec.h>
#include <msMUlawdec.h>
#include <msMUlawenc.h>
#include <msAlawdec.h>
#include <msAlawenc.h>
#include <msGSMdecoder.h>
#include <msGSMencoder.h>
#include <msLPC10decoder.h>
#include <msLPC10encoder.h>
#ifdef BUILD_FFMPEG
#include <msavdecoder.h>
#include <msavencoder.h>*/
#endif
/* some usefull filters of the mediastreamer */
#include "mscopy.h"
#include "msfdispatcher.h"
#include "msqdispatcher.h"
/* some synchronisation sources */
#include <msnosync.h>
#include <mstimer.h>
/* some streams sources and sinks */
#include <msossread.h>
#include <msosswrite.h>
#include <msread.h>
#include <mswrite.h>
#include <msringplayer.h>
#include <msrtprecv.h>
#include <msrtpsend.h>
#include <msv4l.h>
#include <msvideooutput.h>
#endif

View file

@ -1,179 +0,0 @@
/*
The objective of the media_api is to construct and run the necessary processing
on audio and video data flows for a given call (two party call) or conference.
Copyright (C) 2001 Sharath Udupa skuds@gmx.net
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "common.h"
#include "mediaflow.h"
#include "callmember.h"
MediaFlow *media_flow_new(char *id_string, int type){
MediaFlow *flow = (MediaFlow *) g_malloc(sizeof(MediaFlow)); //malloc required?
api_trace("media_flow_new: creating %s",id_string);
flow->id = id_string;
flow->type = type;
flow->flowDirections = NULL;
flow->members = NULL;
return flow;
}
int media_flow_destroy(MediaFlow *flow){
g_free(flow);
return 1;
}
int media_flow_setup_fd(MediaFlow *flow, CallMember* csource, CallMember *cdestination, int direction){
GList *source, *destination;
char *dir;
FlowDirections *fd = (FlowDirections *) g_malloc(sizeof(FlowDirections));
if(direction == MEDIA_FLOW_DUPLEX) dir = "DUPLEX";
else if(direction == MEDIA_FLOW_HALF_DUPLEX) dir = "HALF_DUPLEX";
api_trace("media_flow_setup_fd: setting up %s flow for %s , %s",dir, csource->name, cdestination->name);
source = g_list_find_custom(flow->members, csource, &find);
destination =g_list_find_custom(flow->members, cdestination, &find);
if(source == NULL){
api_error("media_flow_setup_fd: Invalid source %s specified", csource->name);
}
if(destination == NULL){
api_error("media_flow_setup_fd: Invalid destination %s specified", cdestination->name);
//ERROR handling to be done here
}
fd->source = (Members*)source->data;
fd->destination = (Members*)destination->data;
fd->type = direction;
flow->flowDirections = g_list_append(flow->flowDirections, fd);
return 1;
}
int find(gconstpointer mem, gconstpointer cmember){
if(!strcmp(((Members*)mem)->member->name, ((CallMember*)cmember)->name)){
return 0;
}
return 1;
}
int media_flow_start_fd(FlowDirections *fd, MSSync *sync){
Members *source, *destination;
source = fd->source;
destination = fd->destination;
if(fd->type == MEDIA_FLOW_DUPLEX){
fd->recv = set_MSFilter(source->tx_endpoint,1,fd);
fd->dec = set_CODECFilter(source->member->profile, source->tx_endpoint->pt,MEDIA_API_DECODER);
fd->play = set_MSFilter(destination->rx_endpoint,0,fd);
ms_filter_add_link(fd->recv,fd->dec);
ms_filter_add_link(fd->dec,fd->play);
ms_sync_attach(sync, fd->recv);
fd->read = set_MSFilter(destination->tx_endpoint,1,fd);
fd->enc = set_CODECFilter(destination->member->profile, destination->tx_endpoint->pt,MEDIA_API_ENCODER);
fd->send = set_MSFilter(source->rx_endpoint,0,fd);
ms_filter_add_link(fd->read, fd->enc);
ms_filter_add_link(fd->enc, fd->send);
ms_sync_attach(sync, fd->read);
}
else if(fd->type == MEDIA_FLOW_HALF_DUPLEX){
fd->recv = set_MSFilter(source->tx_endpoint,1,fd);
fd->dec = set_CODECFilter(sourcec->member->profile, source->tx_endpoint->pt,MEDIA_API_DECODER);
fd->play = set_MSFilter(destination->rx_endpoint,0,fd);
ms_filter_add_link(fd->recv,fd->dec);
ms_filter_add_link(fd->dec,fd->play);
ms_sync_attach(sync, fd->recv);
}
return 1;
}
MSFilter *set_MSFilter(EndPoint *endpoint, int type, FlowDirections *fdir){
MSFilter *filter;
RtpSession *rtps;
switch(endpoint->protocol){
case MEDIA_RTP:
rtps = rtp_session_new(RTP_SESSION_RECVONLY);
rtp_session_set_local_addr(rtps,"0.0.0.0",8000,8001);
rtp_session_set_scheduling_mode(rtps,0);
rtp_session_set_blocking_mode(rtps,0);
if(type == 1){
filter = ms_rtp_recv_new();
ms_rtp_recv_set_session(MS_RTP_RECV(filter), rtps);
fdir->rtpSessions = g_list_append(fdir->rtpSessions, rtps);
return filter;
}
else{
//ms_rtp_send_new
}
case MEDIA_OSS:
if(type == 1){
filter = ms_oss_read_new();
ms_sound_read_set_device(MS_SOUND_READ(filter),0);
return filter;
}
else{
filter = ms_oss_write_new();
ms_sound_write_set_device(MS_SOUND_WRITE(filter),0);
return filter;
}
case MEDIA_FILE:
if(type == 1){
filter = ms_read_new(endpoint->file);
return filter;
}
if(type == 0){
filter = ms_write_new(endpoint->file);
return filter;
}
}
}
MSFilter *set_CODECFilter(RtpProfile *profile, int pt, int mode){
PayloadType *payload;
switch(mode){
case MEDIA_API_DECODER:
payload = rtp_profile_get_payload(profile, pt);
if(payload == NULL){
api_error("media_api: undefined payload in URL\n");
return NULL;
}
return ms_decoder_new_with_string_id(payload->mime_type);
//Commented this to include the new RtpProfile
/*if(pt != -1) return ms_decoder_new_with_pt(pt);
*else return ms_copy_new();
*/
case MEDIA_API_ENCODER:
payload = rtp_profile_get_payload(profile, pt);
if(payload == NULL){
api_error("media_api: undefined payload in URL\n");
return NULL;
}
return ms_encoder_new_with_string_id(payload->mime_type);
/*if(pt != -1) return ms_encoder_new_with_pt(pt);
*else return ms_copy_new();
*/
}
}

View file

@ -1,68 +0,0 @@
/*
The objective of the media_api is to construct and run the necessary processing
on audio and video data flows for a given call (two party call) or conference.
Copyright (C) 2001 Sharath Udupa skuds@gmx.net
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a c:opy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
struct _MediaFlow{
char *id;
int type;
GList *members;
GList *flowDirections;
GList *sync; //holds all the filters in this MediaFlow
};
typedef struct _MediaFlow MediaFlow;
struct _Members{
struct _CallMember *member;
struct _EndPoint *rx_endpoint;
struct _EndPoint *tx_endpoint;
};
typedef struct _Members Members;
struct _FlowDirections{
Members *source, *destination;
MSFilter *recv,
*dec,
*play;
MSFilter *read, //Filters used
*enc, //if type==DUPLEX
*send;
GList *rtpSessions;
int type;
};
typedef struct _FlowDirections FlowDirections;
MediaFlow *media_flow_new(char *id_string, int type);
int media_flow_setup_fd(MediaFlow*, struct _CallMember *, struct _CallMember *, int);
int media_flow_start_fd(FlowDirections *fd, MSSync *sync);
int media_flow_destroy(MediaFlow *flow);
/* Internal functions */
int find(gconstpointer, gconstpointer);
MSFilter *set_MSFilter(struct _EndPoint *, int, FlowDirections *);
MSFilter *set_CODECFilter(RtpProfile* , int, int);

@ -1 +1 @@
Subproject commit 0e62557bfedcb090b10c81697a41d6f1b3a85e1e
Subproject commit 88b9146ccbd33c9d8d3317be92078f6211498907

2
oRTP

@ -1 +1 @@
Subproject commit 716ac0178612a7416c828fd74261e4dda44930de
Subproject commit b7c5f78d83f8a310ba3700e93174c7eb1234d2d3

View file

@ -1,5 +1,4 @@
# List of source files containing translatable strings.
gtk/tunnel_config.ui
gtk/calllogs.c
gtk/conference.c
gtk/logging.c
@ -25,6 +24,8 @@ gtk/loginframe.c
[type: gettext/glade]gtk/parameters.ui
[type: gettext/glade]gtk/buddylookup.ui
[type: gettext/glade]gtk/waiting.ui
[type: gettext/glade]gtk/dscp_settings.ui
[type: gettext/glade]gtk/tunnel_config.ui
coreapi/linphonecore.c
coreapi/misc.c
coreapi/presence.c