diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c
index 30b5f0d55..343161492 100644
--- a/coreapi/callbacks.c
+++ b/coreapi/callbacks.c
@@ -421,6 +421,16 @@ static void internal_message(Sal *sal, const char *msg){
lc->vtable.show(lc);
}
+static void ping_reply(SalOp *op){
+ LinphoneCall *call=(LinphoneCall*) sal_op_get_user_pointer(op);
+ ms_message("ping reply !");
+ if (call){
+ if (call->state==LCStatePreEstablishing){
+ linphone_core_start_invite(call->core,call,NULL);
+ }
+ }
+}
+
SalCallbacks linphone_sal_callbacks={
call_received,
call_ringing,
@@ -440,7 +450,8 @@ SalCallbacks linphone_sal_callbacks={
notify,
subscribe_received,
subscribe_closed,
- internal_message
+ internal_message,
+ ping_reply
};
diff --git a/coreapi/chat.c b/coreapi/chat.c
index 11c3c978f..c1a884964 100644
--- a/coreapi/chat.c
+++ b/coreapi/chat.c
@@ -27,13 +27,13 @@
LinphoneChatRoom * linphone_core_create_chat_room(LinphoneCore *lc, const char *to){
LinphoneAddress *parsed_url=NULL;
- char *route;
- if (linphone_core_interpret_url(lc,to,&parsed_url,&route)){
+
+ if ((parsed_url=linphone_core_interpret_url(lc,to))!=NULL){
LinphoneChatRoom *cr=ms_new0(LinphoneChatRoom,1);
cr->lc=lc;
cr->peer=linphone_address_as_string(parsed_url);
cr->peer_url=parsed_url;
- cr->route=route;
+ cr->route=ms_strdup(linphone_core_get_route(lc));
lc->chatrooms=ms_list_append(lc->chatrooms,(void *)cr);
return cr;
}
diff --git a/coreapi/exevents.c b/coreapi/exevents.c
index 75dc954ef..d634cb357 100644
--- a/coreapi/exevents.c
+++ b/coreapi/exevents.c
@@ -482,6 +482,10 @@ int linphone_set_audio_offer(sdp_context_t *ctx)
payload.a_rtpmap="telephone-event/8000";
payload.a_fmtp="0-11";
if (lc->dw_audio_bw>0) payload.b_as_bandwidth=lc->dw_audio_bw;
+ if (lc->down_ptime>0) {
+ payload.a_ptime=lc->down_ptime;
+ ms_message("ptime [%i]",payload.a_ptime);
+ }
sdp_context_add_audio_payload(ctx,&payload);
return 0;
}
diff --git a/coreapi/friend.c b/coreapi/friend.c
index 080dffb4e..68f43e659 100644
--- a/coreapi/friend.c
+++ b/coreapi/friend.c
@@ -141,8 +141,10 @@ void __linphone_friend_do_subscribe(LinphoneFriend *fr){
if (fr->outsub==NULL){
/* people for which we don't have yet an answer should appear as offline */
fr->status=LINPHONE_STATUS_OFFLINE;
+ /*
if (fr->lc->vtable.notify_recv)
fr->lc->vtable.notify_recv(fr->lc,(LinphoneFriend*)fr);
+ */
}else{
sal_op_release(fr->outsub);
fr->outsub=NULL;
@@ -297,13 +299,18 @@ static void linphone_friend_unsubscribe(LinphoneFriend *lf){
}
}
-void linphone_friend_destroy(LinphoneFriend *lf){
+void linphone_friend_close_subscriptions(LinphoneFriend *lf){
linphone_friend_notify(lf,LINPHONE_STATUS_OFFLINE);
linphone_friend_unsubscribe(lf);
if (lf->insub){
sal_notify_close(lf->insub);
sal_op_release(lf->insub);
+ lf->insub=NULL;
}
+}
+
+void linphone_friend_destroy(LinphoneFriend *lf){
+
if (lf->uri!=NULL) linphone_address_destroy(lf->uri);
if (lf->info!=NULL) buddy_info_free(lf->info);
ms_free(lf);
diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c
index e6e65930e..230776bda 100644
--- a/coreapi/linphonecore.c
+++ b/coreapi/linphonecore.c
@@ -63,20 +63,21 @@ int lc_callback_obj_invoke(LCCallbackObj *obj, LinphoneCore *lc){
}
-static MSList *make_codec_list(const MSList *codecs){
+static MSList *make_codec_list(const MSList *codecs, bool_t only_one_codec){
MSList *l=NULL;
const MSList *it;
for(it=codecs;it!=NULL;it=it->next){
PayloadType *pt=(PayloadType*)it->data;
if (pt->flags & PAYLOAD_TYPE_ENABLED){
l=ms_list_append(l,payload_type_clone(pt));
+ if (only_one_codec) break;
}
}
return l;
}
static SalMediaDescription *create_local_media_description(LinphoneCore *lc,
- const char *localip, const char *username){
+ const char *localip, const char *username, bool_t only_one_codec){
MSList *l;
PayloadType *pt;
SalMediaDescription *md=sal_media_description_new();
@@ -88,7 +89,8 @@ static SalMediaDescription *create_local_media_description(LinphoneCore *lc,
md->streams[0].port=linphone_core_get_audio_port(lc);
md->streams[0].proto=SalProtoRtpAvp;
md->streams[0].type=SalAudio;
- l=make_codec_list(lc->codecs_conf.audio_codecs);
+ md->streams[0].ptime=lc->net_conf.down_ptime;
+ l=make_codec_list(lc->codecs_conf.audio_codecs,only_one_codec);
pt=payload_type_clone(rtp_profile_get_payload_from_mime(&av_profile,"telephone-event"));
l=ms_list_append(l,pt);
md->streams[0].payloads=l;
@@ -101,7 +103,7 @@ static SalMediaDescription *create_local_media_description(LinphoneCore *lc,
md->streams[1].port=linphone_core_get_video_port(lc);
md->streams[1].proto=SalProtoRtpAvp;
md->streams[1].type=SalVideo;
- l=make_codec_list(lc->codecs_conf.video_codecs);
+ l=make_codec_list(lc->codecs_conf.video_codecs,only_one_codec);
md->streams[1].payloads=l;
if (lc->dw_video_bw)
md->streams[1].bandwidth=lc->dw_video_bw;
@@ -141,7 +143,7 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr
call->core=lc;
linphone_core_get_local_ip(lc,linphone_address_get_domain(to),call->localip);
call->localdesc=create_local_media_description (lc,call->localip,
- linphone_address_get_username(from));
+ linphone_address_get_username(from),FALSE);
linphone_call_init_common(call,from,to);
discover_mtu(lc,linphone_address_get_domain (to));
return call;
@@ -150,16 +152,30 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr
LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, SalOp *op){
LinphoneCall *call=ms_new0(LinphoneCall,1);
LinphoneAddress *me=linphone_core_get_primary_contact_parsed(lc);
+ char *to_str;
+ char *from_str;
call->dir=LinphoneCallIncoming;
sal_op_set_user_pointer(op,call);
call->op=op;
call->core=lc;
+
+ if (lc->sip_conf.ping_with_options){
+ /*the following sends an option request back to the caller so that
+ we get a chance to discover our nat'd address before answering.*/
+ call->ping_op=sal_op_new(lc->sal);
+ to_str=linphone_address_as_string(to);
+ from_str=linphone_address_as_string(from);
+ sal_op_set_route(call->ping_op,sal_op_get_network_origin(call->op));
+ sal_ping(call->ping_op,to_str,from_str);
+ ms_free(to_str);
+ ms_free(from_str);
+ }
linphone_address_clean(from);
linphone_core_get_local_ip(lc,linphone_address_get_domain(from),call->localip);
call->localdesc=create_local_media_description (lc,call->localip,
- linphone_address_get_username(me));
+ linphone_address_get_username(me),lc->sip_conf.only_one_codec);
linphone_call_init_common(call, from, to);
discover_mtu(lc,linphone_address_get_domain(from));
linphone_address_destroy(me);
@@ -171,9 +187,21 @@ void linphone_call_destroy(LinphoneCall *obj)
linphone_core_notify_all_friends(obj->core,obj->core->prev_mode);
linphone_call_log_completed(obj->log,obj);
linphone_core_update_allocated_audio_bandwidth(obj->core);
- if (obj->op!=NULL) sal_op_release(obj->op);
- if (obj->resultdesc!=NULL) sal_media_description_unref(obj->resultdesc);
- if (obj->localdesc!=NULL) sal_media_description_unref(obj->localdesc);
+ if (obj->op!=NULL) {
+ sal_op_release(obj->op);
+ obj->op=NULL;
+ }
+ if (obj->resultdesc!=NULL) {
+ sal_media_description_unref(obj->resultdesc);
+ obj->resultdesc=NULL;
+ }
+ if (obj->localdesc!=NULL) {
+ sal_media_description_unref(obj->localdesc);
+ obj->localdesc=NULL;
+ }
+ if (obj->ping_op) {
+ sal_op_release(obj->ping_op);
+ }
ms_free(obj);
}
@@ -271,6 +299,7 @@ void linphone_call_log_completed(LinphoneCallLog *calllog, LinphoneCall *call){
calllog->duration=time(NULL)-call->start_time;
switch(call->state){
case LCStateInit:
+ case LCStatePreEstablishing:
calllog->status=LinphoneCallAborted;
break;
case LCStateRinging:
@@ -466,6 +495,9 @@ net_config_read (LinphoneCore *lc)
lc->net_conf.nat_sdp_only=tmp;
tmp=lp_config_get_int(lc->config,"net","mtu",0);
linphone_core_set_mtu(lc,tmp);
+ tmp=lp_config_get_int(lc->config,"net","download_ptime",0);
+ linphone_core_set_download_ptime(lc,tmp);
+
}
static void build_sound_devices_table(LinphoneCore *lc){
@@ -634,11 +666,12 @@ static void sip_config_read(LinphoneCore *lc)
}
}
- /*for test*/
+ /*for tuning or test*/
lc->sip_conf.sdp_200_ack=lp_config_get_int(lc->config,"sip","sdp_200_ack",0);
lc->sip_conf.only_one_codec=lp_config_get_int(lc->config,"sip","only_one_codec",0);
lc->sip_conf.register_only_when_network_is_up=
lp_config_get_int(lc->config,"sip","register_only_when_network_is_up",1);
+ lc->sip_conf.ping_with_options=lp_config_get_int(lc->config,"sip","ping_with_options",1);
}
static void rtp_config_read(LinphoneCore *lc)
@@ -914,6 +947,17 @@ int linphone_core_get_download_bandwidth(const LinphoneCore *lc){
int linphone_core_get_upload_bandwidth(const LinphoneCore *lc){
return lc->net_conf.upload_bw;
}
+/**
+ * set audio packetization time linphone expect to received from peer
+ */
+void linphone_core_set_download_ptime(LinphoneCore *lc, int ptime) {
+ lc->net_conf.down_ptime=ptime;
+}
+
+int linphone_core_get_download_ptime(LinphoneCore *lc) {
+ return lc->net_conf.down_ptime;
+}
+
/**
* Returns liblinphone's version as a string.
@@ -1016,6 +1060,7 @@ static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vta
lc->vtable.display_status(lc,_("Ready"));
gstate_new_state(lc, GSTATE_POWER_ON, NULL);
lc->auto_net_state_mon=TRUE;
+
lc->ready=TRUE;
}
@@ -1347,7 +1392,6 @@ int linphone_core_get_sip_port(LinphoneCore *lc)
return lc->sip_conf.sip_port;
}
-static bool_t exosip_running=FALSE;
static char _ua_name[64]="Linphone";
static char _ua_version[64]=LINPHONE_VERSION;
@@ -1585,7 +1629,10 @@ void linphone_core_iterate(LinphoneCore *lc){
if (lc->call!=NULL){
LinphoneCall *call=lc->call;
-
+ if (call->state==LCStatePreEstablishing && (curtime-call->start_time>=2)){
+ /*start the call even if the OPTIONS reply did not arrive*/
+ linphone_core_start_invite(lc,call,NULL);
+ }
if (call->dir==LinphoneCallIncoming && call->state==LCStateRinging){
elapsed=curtime-call->start_time;
ms_message("incoming call ringing for %i seconds",elapsed);
@@ -1631,32 +1678,25 @@ void linphone_core_iterate(LinphoneCore *lc){
}
-bool_t linphone_core_interpret_url(LinphoneCore *lc, const char *url, LinphoneAddress **real_parsed_url, char **route){
+LinphoneAddress * linphone_core_interpret_url(LinphoneCore *lc, const char *url){
enum_lookup_res_t *enumres=NULL;
- LinphoneAddress *parsed_url=NULL;
char *enum_domain=NULL;
LinphoneProxyConfig *proxy=lc->default_proxy;;
char *tmpurl;
- const char *tmproute;
LinphoneAddress *uri;
- if (real_parsed_url!=NULL) *real_parsed_url=NULL;
- *route=NULL;
- tmproute=linphone_core_get_route(lc);
-
if (is_enum(url,&enum_domain)){
lc->vtable.display_status(lc,_("Looking for telephone number destination..."));
if (enum_lookup(enum_domain,&enumres)<0){
lc->vtable.display_status(lc,_("Could not resolve this number."));
ms_free(enum_domain);
- return FALSE;
+ return NULL;
}
ms_free(enum_domain);
tmpurl=enumres->sip_address[0];
- if (real_parsed_url!=NULL) *real_parsed_url=linphone_address_new(tmpurl);
+ uri=linphone_address_new(tmpurl);
enum_lookup_res_free(enumres);
- if (tmproute) *route=ms_strdup(tmproute);
- return TRUE;
+ return uri;
}
/* check if we have a "sip:" */
if (strstr(url,"sip:")==NULL){
@@ -1667,8 +1707,7 @@ bool_t linphone_core_interpret_url(LinphoneCore *lc, const char *url, LinphoneAd
uri=linphone_address_new(tmpurl);
ms_free(tmpurl);
if (uri){
- if (real_parsed_url!=NULL) *real_parsed_url=uri;
- return TRUE;
+ return uri;
}
}
@@ -1678,31 +1717,24 @@ bool_t linphone_core_interpret_url(LinphoneCore *lc, const char *url, LinphoneAd
char normalized_username[128];
uri=linphone_address_new(identity);
if (uri==NULL){
- return FALSE;
+ return NULL;
}
linphone_address_set_display_name(uri,NULL);
linphone_proxy_config_normalize_number(proxy,url,normalized_username,
sizeof(normalized_username));
linphone_address_set_username(uri,normalized_username);
-
- if (real_parsed_url!=NULL) *real_parsed_url=uri;
- if (tmproute) *route=ms_strdup(tmproute);
- return TRUE;
- }else return FALSE;
+ return uri;
+ }else return NULL;
}
- parsed_url=linphone_address_new(url);
- if (parsed_url!=NULL){
- if (real_parsed_url!=NULL) *real_parsed_url=parsed_url;
- else linphone_address_destroy(parsed_url);
- if (tmproute) *route=ms_strdup(tmproute);
-
- return TRUE;
+ uri=linphone_address_new(url);
+ if (uri!=NULL){
+ return uri;
}
/* else we could not do anything with url given by user, so display an error */
if (lc->vtable.display_warning!=NULL){
lc->vtable.display_warning(lc,_("Could not parse given sip address. A sip url usually looks like sip:user@domain"));
}
- return FALSE;
+ return NULL;
}
/**
@@ -1753,16 +1785,18 @@ static char *get_fixed_contact(LinphoneCore *lc, LinphoneCall *call , LinphonePr
LinphoneAddress *ctt;
const char *localip=call->localip;
+ /* first use user's supplied ip address if asked*/
if (linphone_core_get_firewall_policy(lc)==LINPHONE_POLICY_USE_NAT_ADDRESS){
ctt=linphone_core_get_primary_contact_parsed(lc);
return ms_strdup_printf("sip:%s@%s",linphone_address_get_username(ctt),
linphone_core_get_nat_address(lc));
}
-
+
+ /* if already choosed, don't change it */
if (call->op && sal_op_get_contact(call->op)!=NULL){
return NULL;
}
-
+ /*if using a proxy, use the contact address as guessed with the REGISTERs*/
if (dest_proxy && dest_proxy->op){
const char *fixed_contact=sal_op_get_contact(dest_proxy->op);
if (fixed_contact) {
@@ -1770,6 +1804,16 @@ static char *get_fixed_contact(LinphoneCore *lc, LinphoneCall *call , LinphonePr
return ms_strdup(fixed_contact);
}
}
+ /* if the ping OPTIONS request succeeded use the contact guessed from the
+ received, rport*/
+ if (call->ping_op){
+ const char *guessed=sal_op_get_contact(call->ping_op);
+ if (guessed){
+ ms_message("Contact has been fixed using OPTIONS to %s",guessed);
+ return ms_strdup(guessed);
+ }
+ }
+
ctt=linphone_core_get_primary_contact_parsed(lc);
if (ctt!=NULL){
@@ -1785,23 +1829,78 @@ static char *get_fixed_contact(LinphoneCore *lc, LinphoneCall *call , LinphonePr
return NULL;
}
+int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call, LinphoneProxyConfig *dest_proxy){
+ int err;
+ char *contact;
+ char *real_url,*barmsg;
+ char *from;
+ /*try to be best-effort in giving real local or routable contact address */
+ contact=get_fixed_contact(lc,call,dest_proxy);
+ if (contact){
+ sal_op_set_contact(call->op, contact);
+ ms_free(contact);
+ }
+ call->state=LCStateInit;
+ linphone_core_init_media_streams(lc,lc->call);
+ if (!lc->sip_conf.sdp_200_ack){
+ call->media_pending=TRUE;
+ sal_call_set_local_media_description(call->op,call->localdesc);
+ }
+ real_url=linphone_address_as_string(call->log->to);
+ from=linphone_address_as_string(call->log->from);
+ err=sal_call(call->op,from,real_url);
+
+ if (lc->sip_conf.sdp_200_ack){
+ call->media_pending=TRUE;
+ sal_call_set_local_media_description(call->op,call->localdesc);
+ }
+ barmsg=ortp_strdup_printf("%s %s", _("Contacting"), real_url);
+ lc->vtable.display_status(lc,barmsg);
+ ms_free(barmsg);
+
+ if (err<0){
+ ms_warning("Could not initiate call.");
+ lc->vtable.display_status(lc,_("could not call"));
+ linphone_core_stop_media_streams(lc,call);
+ linphone_call_destroy(call);
+ lc->call=NULL;
+ }else gstate_new_state(lc, GSTATE_CALL_OUT_INVITE, real_url);
+ ms_free(real_url);
+ ms_free(from);
+ return err;
+}
+
/**
* Initiates an outgoing call
*
* @ingroup call_control
* @param lc the LinphoneCore object
+ * @param url the destination of the call (sip address, or phone number).
+**/
+int linphone_core_invite(LinphoneCore *lc, const char *url){
+ LinphoneAddress *addr=linphone_core_interpret_url(lc,url);
+ if (addr){
+ int err=linphone_core_invite_address(lc,addr);
+ linphone_address_destroy(addr);
+ return err;
+ }
+ return -1;
+}
+
+/**
+ * Initiates an outgoing call given a destination LinphoneAddress
+ *
+ * @ingroup call_control
+ * @param lc the LinphoneCore object
* @param url the destination of the call (sip address).
**/
-int linphone_core_invite(LinphoneCore *lc, const char *url)
+int linphone_core_invite_address(LinphoneCore *lc, const LinphoneAddress *real_parsed_url)
{
- char *barmsg;
int err=0;
- char *route=NULL;
+ const char *route=NULL;
const char *from=NULL;
- char *contact=NULL;
LinphoneProxyConfig *proxy=NULL;
LinphoneAddress *parsed_url2=NULL;
- LinphoneAddress *real_parsed_url=NULL;
char *real_url=NULL;
LinphoneProxyConfig *dest_proxy=NULL;
LinphoneCall *call;
@@ -1812,9 +1911,8 @@ int linphone_core_invite(LinphoneCore *lc, const char *url)
}
linphone_core_get_default_proxy(lc,&proxy);
- if (!linphone_core_interpret_url(lc,url,&real_parsed_url,&route)){
- return -1;
- }
+ route=linphone_core_get_route(lc);
+
real_url=linphone_address_as_string(real_parsed_url);
dest_proxy=linphone_core_lookup_known_proxy(lc,real_parsed_url);
@@ -1833,57 +1931,34 @@ int linphone_core_invite(LinphoneCore *lc, const char *url)
parsed_url2=linphone_address_new(from);
- call=linphone_call_new_outgoing(lc,parsed_url2,real_parsed_url);
+ call=linphone_call_new_outgoing(lc,parsed_url2,linphone_address_clone(real_parsed_url));
sal_op_set_route(call->op,route);
-
- /*try to be best-effort in giving real local or routable contact address */
- contact=get_fixed_contact(lc,call,dest_proxy);
- if (contact){
- sal_op_set_contact(call->op, contact);
- ms_free(contact);
- }
-
- lc->call=call;
-
- linphone_core_init_media_streams(lc,lc->call);
- if (!lc->sip_conf.sdp_200_ack){
- call->media_pending=TRUE;
- sal_call_set_local_media_description(call->op,call->localdesc);
- }
- err=sal_call(call->op,from,real_url);
-
- if (lc->sip_conf.sdp_200_ack){
- call->media_pending=TRUE;
- sal_call_set_local_media_description(call->op,call->localdesc);
- }
- barmsg=ortp_strdup_printf("%s %s", _("Contacting"), real_url);
- lc->vtable.display_status(lc,barmsg);
- ms_free(barmsg);
- if (err<0){
- ms_warning("Could not initiate call.");
- lc->vtable.display_status(lc,_("could not call"));
- linphone_core_stop_media_streams(lc,call);
- linphone_call_destroy(call);
- lc->call=NULL;
- }else gstate_new_state(lc, GSTATE_CALL_OUT_INVITE, url);
-
+ lc->call=call;
+ if (dest_proxy!=NULL || lc->sip_conf.ping_with_options==FALSE){
+ err=linphone_core_start_invite(lc,call,dest_proxy);
+ }else{
+ /*defer the start of the call after the OPTIONS ping*/
+ call->state=LCStatePreEstablishing;
+ call->ping_op=sal_op_new(lc->sal);
+ sal_ping(call->ping_op,from,real_url);
+ call->start_time=time(NULL);
+ }
+
if (real_url!=NULL) ms_free(real_url);
- if (route!=NULL) ms_free(route);
- return (err<0) ? -1 : 0;
+ return err;
}
int linphone_core_refer(LinphoneCore *lc, const char *url)
{
char *real_url=NULL;
- LinphoneAddress *real_parsed_url=NULL;
+ LinphoneAddress *real_parsed_url=linphone_core_interpret_url(lc,url);
LinphoneCall *call;
- char *route;
- if (!linphone_core_interpret_url(lc,url,&real_parsed_url, &route)){
+
+ if (!real_parsed_url){
/* bad url */
return -1;
}
- if (route!=NULL) ms_free(route);
call=lc->call;
if (call==NULL){
ms_warning("No established call to refer.");
@@ -3071,7 +3146,7 @@ void linphone_core_set_play_file(LinphoneCore *lc, const char *file){
}
if (file!=NULL) {
lc->play_file=ms_strdup(file);
- if (lc->audiostream)
+ if (lc->audiostream->ticker)
audio_stream_play(lc->audiostream,file);
}
}
@@ -3311,6 +3386,8 @@ static void linphone_core_uninit(LinphoneCore *lc)
linphone_core_iterate(lc);
}
}
+ if (lc->friends)
+ ms_list_for_each(lc->friends,(void (*)(void *))linphone_friend_close_subscriptions);
gstate_new_state(lc, GSTATE_POWER_SHUTDOWN, NULL);
#ifdef VIDEO_ENABLED
if (lc->previewstream!=NULL){
@@ -3334,7 +3411,6 @@ static void linphone_core_uninit(LinphoneCore *lc)
linphone_core_free_payload_types();
ortp_exit();
- exosip_running=FALSE;
gstate_new_state(lc, GSTATE_POWER_OFF, NULL);
}
diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h
index 07a108540..ee515f4e9 100644
--- a/coreapi/linphonecore.h
+++ b/coreapi/linphonecore.h
@@ -458,6 +458,7 @@ typedef struct _LinphoneCore LinphoneCore;
*/
bool_t auto_net_state_mon;
bool_t network_reachable;
+ int down_ptime;
/* THE main API */
@@ -474,8 +475,12 @@ LinphoneCore *linphone_core_new(const LinphoneCoreVTable *vtable,
/* function to be periodically called in a main loop */
void linphone_core_iterate(LinphoneCore *lc);
+LinphoneAddress * linphone_core_interpret_url(LinphoneCore *lc, const char *url);
+
int linphone_core_invite(LinphoneCore *lc, const char *url);
+int linphone_core_invite_address(LinphoneCore *lc, const LinphoneAddress *addr);
+
int linphone_core_refer(LinphoneCore *lc, const char *url);
bool_t linphone_core_inc_invite_pending(LinphoneCore*lc);
@@ -506,7 +511,17 @@ void linphone_core_set_upload_bandwidth(LinphoneCore *lc, int bw);
int linphone_core_get_download_bandwidth(const LinphoneCore *lc);
int linphone_core_get_upload_bandwidth(const LinphoneCore *lc);
-
+/**
+ * set audio packetization time linphone expect to received from peer
+ * @ingroup media_parameters
+ *
+ */
+void linphone_core_set_download_ptime(LinphoneCore *lc, int ptime);
+/**
+ * get audio packetization time linphone expect to received from peer, 0 means unspecified
+ * @ingroup media_parameters
+ */
+int linphone_core_get_download_ptime(LinphoneCore *lc);
#ifdef VINCENT_MAURY_RSVP
/* QoS functions */
diff --git a/coreapi/private.h b/coreapi/private.h
index 6fc176116..a3f2155f6 100644
--- a/coreapi/private.h
+++ b/coreapi/private.h
@@ -56,6 +56,7 @@
typedef enum _LCState{
LCStateInit,
+ LCStatePreEstablishing,
LCStateRinging,
LCStateAVRunning
}LCState;
@@ -71,6 +72,7 @@ typedef struct _LinphoneCall
struct _RtpProfile *video_profile;
struct _LinphoneCallLog *log;
SalOp *op;
+ SalOp *ping_op;
char localip[LINPHONE_IPADDR_SIZE]; /* our best guess for local ipaddress for this call */
time_t start_time; /*time at which the call was initiated*/
time_t media_start_time; /*time at which it was accepted, media streams established*/
@@ -99,7 +101,7 @@ void linphone_core_refresh_subscribes(LinphoneCore *lc);
int linphone_proxy_config_send_publish(LinphoneProxyConfig *cfg, LinphoneOnlineStatus os);
int linphone_online_status_to_eXosip(LinphoneOnlineStatus os);
-
+void linphone_friend_close_subscriptions(LinphoneFriend *lf);
void linphone_friend_notify(LinphoneFriend *lf, LinphoneOnlineStatus os);
LinphoneFriend *linphone_find_friend_by_inc_subscribe(MSList *l, SalOp *op);
LinphoneFriend *linphone_find_friend_by_out_subscribe(MSList *l, SalOp *op);
@@ -175,11 +177,11 @@ void linphone_core_start_media_streams(LinphoneCore *lc, struct _LinphoneCall *c
void linphone_core_stop_media_streams(LinphoneCore *lc, struct _LinphoneCall *call);
const char * linphone_core_get_identity(LinphoneCore *lc);
const char * linphone_core_get_route(LinphoneCore *lc);
-bool_t linphone_core_interpret_url(LinphoneCore *lc, const char *url, LinphoneAddress **real_parsed_url, char **route);
void linphone_core_start_waiting(LinphoneCore *lc, const char *purpose);
void linphone_core_update_progress(LinphoneCore *lc, const char *purpose, float progresses);
void linphone_core_stop_waiting(LinphoneCore *lc);
+int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call, LinphoneProxyConfig *dest_proxy);
extern SalCallbacks linphone_sal_callbacks;
@@ -254,6 +256,7 @@ typedef struct sip_config
bool_t sdp_200_ack;
bool_t only_one_codec; /*in SDP answers*/
bool_t register_only_when_network_is_up;
+ bool_t ping_with_options;
} sip_config_t;
typedef struct rtp_config
@@ -276,6 +279,7 @@ typedef struct net_config
int upload_bw;
int firewall_policy;
int mtu;
+ int down_ptime;
bool_t nat_sdp_only;
}net_config_t;
diff --git a/coreapi/sal.c b/coreapi/sal.c
index ae432d565..750555016 100644
--- a/coreapi/sal.c
+++ b/coreapi/sal.c
@@ -128,11 +128,20 @@ const char *sal_op_get_proxy(const SalOp *op){
return ((SalOpBase*)op)->route;
}
+const char *sal_op_get_network_origin(const SalOp *op){
+ return ((SalOpBase*)op)->origin;
+}
+
void __sal_op_init(SalOp *b, Sal *sal){
memset(b,0,sizeof(SalOpBase));
((SalOpBase*)b)->root=sal;
}
+void __sal_op_set_network_origin(SalOp *op, const char *origin){
+ assign_string(&((SalOpBase*)op)->origin,origin);
+}
+
+
void __sal_op_free(SalOp *op){
SalOpBase *b=(SalOpBase *)op;
if (b->from) {
@@ -151,6 +160,10 @@ void __sal_op_free(SalOp *op){
ms_free(b->contact);
b->contact=NULL;
}
+ if (b->origin){
+ ms_free(b->origin);
+ b->origin=NULL;
+ }
if (b->local_media)
sal_media_description_unref(b->local_media);
if (b->remote_media)
diff --git a/coreapi/sal.h b/coreapi/sal.h
index eb8042361..e672216c9 100644
--- a/coreapi/sal.h
+++ b/coreapi/sal.h
@@ -124,6 +124,7 @@ typedef struct SalOpBase{
char *contact;
char *from;
char *to;
+ char *origin;
SalMediaDescription *local_media;
SalMediaDescription *remote_media;
void *user_pointer;
@@ -186,6 +187,7 @@ typedef void (*SalOnNotify)(SalOp *op, SalSubscribeState ss, SalPresenceStatus s
typedef void (*SalOnSubscribeReceived)(SalOp *salop, const char *from);
typedef void (*SalOnSubscribeClosed)(SalOp *salop, const char *from);
typedef void (*SalOnInternalMsg)(Sal *sal, const char *msg);
+typedef void (*SalOnPingReply)(SalOp *salop);
typedef struct SalCallbacks{
SalOnCallReceived call_received;
@@ -207,6 +209,7 @@ typedef struct SalCallbacks{
SalOnSubscribeReceived subscribe_received;
SalOnSubscribeClosed subscribe_closed;
SalOnInternalMsg internal_message;
+ SalOnPingReply ping_reply;
}SalCallbacks;
typedef struct SalAuthInfo{
@@ -219,7 +222,6 @@ typedef struct SalAuthInfo{
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);
void sal_set_user_agent(Sal *ctx, const char *user_agent);
-void sal_masquerade(Sal *ctx, const char *ip);
void sal_use_session_timers(Sal *ctx, int expires);
int sal_iterate(Sal *sal);
MSList * sal_get_pending_auths(Sal *sal);
@@ -242,6 +244,8 @@ const char *sal_op_get_to(const SalOp *op);
const char *sal_op_get_contact(const SalOp *op);
const char *sal_op_get_route(const SalOp *op);
const char *sal_op_get_proxy(const SalOp *op);
+/*for incoming requests, returns the origin of the packet as a sip uri*/
+const char *sal_op_get_network_origin(const SalOp *op);
void *sal_op_get_user_pointer(const SalOp *op);
/*Call API*/
@@ -273,6 +277,10 @@ int sal_notify_close(SalOp *op);
/*presence publish */
int sal_publish(SalOp *op, const char *from, const char *to, SalPresenceStatus status);
+
+/*ping: main purpose is to obtain its own contact address behind firewalls*/
+int sal_ping(SalOp *op, const char *from, const char *to);
+
#define payload_type_set_number(pt,n) (pt)->user_data=(void*)((long)n);
#define payload_type_get_number(pt) ((int)(long)(pt)->user_data)
@@ -282,6 +290,7 @@ void sal_get_default_local_ip(Sal *sal, int address_family, char *ip, size_t ipl
/*internal API */
void __sal_op_init(SalOp *b, Sal *sal);
+void __sal_op_set_network_origin(SalOp *op, const char *origin /*a sip uri*/);
void __sal_op_free(SalOp *b);
diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c
index daae709db..5f337b3fa 100644
--- a/coreapi/sal_eXosip2.c
+++ b/coreapi/sal_eXosip2.c
@@ -64,6 +64,36 @@ static void sal_remove_register(Sal *sal, int rid){
}
}
+static SalOp * sal_find_other(Sal *sal, osip_message_t *response){
+ const MSList *elem;
+ SalOp *op;
+ osip_call_id_t *callid=osip_message_get_call_id(response);
+ if (callid==NULL) {
+ ms_error("There is no call-id in this response !");
+ return NULL;
+ }
+ for(elem=sal->other_transactions;elem!=NULL;elem=elem->next){
+ op=(SalOp*)elem->data;
+ if (osip_call_id_match(callid,op->call_id)==0) return op;
+ }
+ return NULL;
+}
+
+static void sal_add_other(Sal *sal, SalOp *op, osip_message_t *request){
+ osip_call_id_t *callid=osip_message_get_call_id(request);
+ if (callid==NULL) {
+ ms_error("There is no call id in the request !");
+ return;
+ }
+ osip_call_id_clone(callid,&op->call_id);
+ sal->other_transactions=ms_list_append(sal->other_transactions,op);
+}
+
+static void sal_remove_other(Sal *sal, SalOp *op){
+ sal->other_transactions=ms_list_remove(sal->other_transactions,op);
+}
+
+
static void sal_add_pending_auth(Sal *sal, SalOp *op){
sal->pending_auths=ms_list_append(sal->pending_auths,op);
}
@@ -107,6 +137,7 @@ SalOp * sal_op_new(Sal *sal){
op->pending_auth=NULL;
op->sdp_answer=NULL;
op->reinvite=FALSE;
+ op->call_id=NULL;
return op;
}
@@ -122,11 +153,21 @@ void sal_op_release(SalOp *op){
ms_message("Cleaning cid %i",op->cid);
eXosip_call_set_reference(op->cid,NULL);
}
+ if (op->sid!=-1){
+ sal_remove_out_subscribe(op->base.root,op);
+ }
+ if (op->nid!=-1){
+ sal_remove_in_subscribe(op->base.root,op);
+ }
if (op->pending_auth){
sal_remove_pending_auth(op->base.root,op);
}
if (op->result)
sal_media_description_unref(op->result);
+ if (op->call_id){
+ sal_remove_other(op->base.root,op);
+ osip_call_id_free(op->call_id);
+ }
__sal_op_free(op);
}
@@ -191,11 +232,6 @@ void *sal_get_user_pointer(const Sal *sal){
return sal->up;
}
-void sal_masquerade(Sal *ctx, const char *ip){
- ms_message("Masquerading SIP with %s",ip);
- eXosip_set_option(EXOSIP_OPT_SET_IPV4_FOR_GATEWAY,ip);
-}
-
static void unimplemented_stub(){
ms_warning("Unimplemented SAL callback");
}
@@ -232,6 +268,8 @@ void sal_set_callbacks(Sal *ctx, const SalCallbacks *cbs){
ctx->callbacks.text_received=(SalOnTextReceived)unimplemented_stub;
if (ctx->callbacks.internal_message==NULL)
ctx->callbacks.internal_message=(SalOnInternalMsg)unimplemented_stub;
+ if (ctx->callbacks.ping_reply==NULL)
+ ctx->callbacks.ping_reply=(SalOnPingReply)unimplemented_stub;
}
int sal_listen_port(Sal *ctx, const char *addr, int port, SalTransport tr, int is_secure){
@@ -461,6 +499,24 @@ SalMediaDescription * sal_call_get_final_media_description(SalOp *h){
return h->result;
}
+int sal_ping(SalOp *op, const char *from, const char *to){
+ osip_message_t *options=NULL;
+
+ sal_op_set_from(op,from);
+ sal_op_set_to(op,to);
+ eXosip_options_build_request (&options, sal_op_get_to(op),
+ sal_op_get_from(op),sal_op_get_route(op));
+ if (options){
+ if (op->base.root->session_expires!=0){
+ osip_message_set_header(options, "Session-expires", "200");
+ osip_message_set_supported(options, "timer");
+ }
+ sal_add_other(sal_op_get_sal(op),op,options);
+ return eXosip_options_send_request(options);
+ }
+ return -1;
+}
+
int sal_refer(SalOp *h, const char *refer_to){
osip_message_t *msg=NULL;
int err=0;
@@ -518,11 +574,30 @@ void sal_op_authenticate(SalOp *h, const SalAuthInfo *info){
}
}
+static void set_network_origin(SalOp *op, osip_message_t *req){
+ const char *received=NULL;
+ int rport=5060;
+ char origin[64];
+ if (extract_received_rport(req,&received,&rport)!=0){
+ osip_via_t *via=NULL;
+ char *tmp;
+ osip_message_get_via(req,0,&via);
+ received=osip_via_get_host(via);
+ tmp=osip_via_get_port(via);
+ if (tmp) rport=atoi(tmp);
+ }
+ snprintf(origin,sizeof(origin)-1,"sip:%s:%i",received,rport);
+ __sal_op_set_network_origin(op,origin);
+}
+
static void inc_new_call(Sal *sal, eXosip_event_t *ev){
SalOp *op=sal_op_new(sal);
osip_from_t *from,*to;
char *tmp;
sdp_message_t *sdp=eXosip_get_sdp_info(ev->request);
+
+ set_network_origin(op,ev->request);
+
if (sdp){
op->sdp_offering=FALSE;
op->base.remote_media=sal_media_description_new();
@@ -613,22 +688,10 @@ static void handle_ack(Sal *sal, eXosip_event_t *ev){
}
}
-static int call_proceeding(Sal *sal, eXosip_event_t *ev){
- SalOp *op=(SalOp*)ev->external_reference;
+static void update_contact_from_response(SalOp *op, osip_message_t *response){
const char *received;
int rport;
-
- if (op==NULL) {
- ms_warning("This call has been canceled.");
- eXosip_lock();
- eXosip_call_terminate(ev->cid,ev->did);
- eXosip_unlock();
- return -1;
- }
- op->did=ev->did;
- op->tid=ev->tid;
- /* update contact if received and rport are set by the server */
- if (extract_received_rport(ev->response,&received,&rport)==0){
+ if (extract_received_rport(response,&received,&rport)==0){
const char *contact=sal_op_get_contact(op);
if (!contact){
/*no contact given yet, use from instead*/
@@ -640,11 +703,29 @@ static int call_proceeding(Sal *sal, eXosip_event_t *ev){
sal_address_set_domain(addr,received);
sal_address_set_port_int(addr,rport);
tmp=sal_address_as_string(addr);
- ms_message("Contact address automatically updated to %s for this call",tmp);
+ ms_message("Contact address updated to %s for this dialog",tmp);
sal_op_set_contact(op,tmp);
ms_free(tmp);
}
}
+}
+
+static int call_proceeding(Sal *sal, eXosip_event_t *ev){
+ SalOp *op=(SalOp*)ev->external_reference;
+
+ if (op==NULL) {
+ ms_warning("This call has been canceled.");
+ eXosip_lock();
+ eXosip_call_terminate(ev->cid,ev->did);
+ eXosip_unlock();
+ return -1;
+ }
+ op->did=ev->did;
+ op->tid=ev->tid;
+
+ /* update contact if received and rport are set by the server
+ note: will only be used by remote for next INVITE, if any...*/
+ update_contact_from_response(op,ev->response);
return 0;
}
@@ -668,6 +749,7 @@ static void call_accepted(Sal *sal, eXosip_event_t *ev){
osip_message_t *msg=NULL;
SalOp *op;
const char *contact;
+
op=(SalOp*)ev->external_reference;
if (op==NULL){
ms_error("A closed call is accepted ?");
@@ -778,6 +860,7 @@ static SalOp *find_op(Sal *sal, eXosip_event_t *ev){
if (ev->rid>0){
return sal_find_register(sal,ev->rid);
}
+ if (ev->response) return sal_find_other(sal,ev->response);
return NULL;
}
@@ -1152,6 +1235,19 @@ static bool_t registration_failure(Sal *sal, eXosip_event_t *ev){
return TRUE;
}
+static void other_request_reply(Sal *sal,eXosip_event_t *ev){
+ SalOp *op=find_op(sal,ev);
+
+ if (op==NULL){
+ ms_warning("other_request_reply(): Receiving response to unknown request.");
+ return;
+ }
+ if (ev->response){
+ update_contact_from_response(op,ev->response);
+ sal->callbacks.ping_reply(op);
+ }
+}
+
static bool_t process_event(Sal *sal, eXosip_event_t *ev){
switch(ev->type){
case EXOSIP_CALL_ANSWERED:
@@ -1220,7 +1316,7 @@ static bool_t process_event(Sal *sal, eXosip_event_t *ev){
sal_exosip_notify_recv(sal,ev);
break;
case EXOSIP_SUBSCRIPTION_ANSWERED:
- ms_message("EXOSIP_SUBSCRIPTION_ANSWERED, ev->sid=%i\n",ev->sid);
+ ms_message("EXOSIP_SUBSCRIPTION_ANSWERED, ev->sid=%i, ev->did=%i\n",ev->sid,ev->did);
sal_exosip_subscription_answered(sal,ev);
break;
case EXOSIP_SUBSCRIPTION_CLOSED:
@@ -1242,6 +1338,13 @@ static bool_t process_event(Sal *sal, eXosip_event_t *ev){
case EXOSIP_MESSAGE_NEW:
other_request(sal,ev);
break;
+ case EXOSIP_MESSAGE_PROCEEDING:
+ case EXOSIP_MESSAGE_ANSWERED:
+ case EXOSIP_MESSAGE_REDIRECTED:
+ case EXOSIP_MESSAGE_SERVERFAILURE:
+ case EXOSIP_MESSAGE_GLOBALFAILURE:
+ other_request_reply(sal,ev);
+ break;
case EXOSIP_MESSAGE_REQUESTFAILURE:
if (ev->response && (ev->response->status_code == 407 || ev->response->status_code == 401)){
return process_authentication(sal,ev);
diff --git a/coreapi/sal_eXosip2.h b/coreapi/sal_eXosip2.h
index 4e5d81240..6539dcae8 100644
--- a/coreapi/sal_eXosip2.h
+++ b/coreapi/sal_eXosip2.h
@@ -34,6 +34,7 @@ struct Sal{
MSList *out_subscribes;/*MSList of SalOp */
MSList *in_subscribes;/*MSList of SalOp */
MSList *pending_auths;/*MSList of SalOp */
+ MSList *other_transactions; /*MSList of SalOp */
int running;
int session_expires;
void *up;
@@ -51,11 +52,16 @@ struct SalOp{
SalMediaDescription *result;
sdp_message_t *sdp_answer;
eXosip_event_t *pending_auth;
+ osip_call_id_t *call_id; /*used for out of calls transaction in order
+ to retrieve the operation when receiving a response*/
bool_t supports_session_timers;
bool_t sdp_offering;
bool_t reinvite;
};
+void sal_remove_out_subscribe(Sal *sal, SalOp *op);
+void sal_remove_in_subscribe(Sal *sal, SalOp *op);
+
void sal_exosip_subscription_recv(Sal *sal, eXosip_event_t *ev);
void sal_exosip_subscription_answered(Sal *sal,eXosip_event_t *ev);
void sal_exosip_notify_recv(Sal *sal,eXosip_event_t *ev);
diff --git a/coreapi/sal_eXosip2_presence.c b/coreapi/sal_eXosip2_presence.c
index d4ab7ba41..760d8fd8d 100644
--- a/coreapi/sal_eXosip2_presence.c
+++ b/coreapi/sal_eXosip2_presence.c
@@ -35,16 +35,8 @@ static void sal_add_out_subscribe(Sal *sal, SalOp *op){
sal->out_subscribes=ms_list_append(sal->out_subscribes,op);
}
-static void sal_remove_out_subscribe(Sal *sal, int sid){
- MSList *elem;
- SalOp *op;
- for(elem=sal->out_subscribes;elem!=NULL;elem=elem->next){
- op=(SalOp*)elem->data;
- if (op->sid==sid) {
- sal->out_subscribes=ms_list_remove_link(sal->out_subscribes,elem);
- return;
- }
- }
+void sal_remove_out_subscribe(Sal *sal, SalOp *op){
+ sal->out_subscribes=ms_list_remove(sal->out_subscribes,op);
}
static SalOp * sal_find_in_subscribe(Sal *sal, int nid){
@@ -61,16 +53,8 @@ static void sal_add_in_subscribe(Sal *sal, SalOp *op){
sal->in_subscribes=ms_list_append(sal->in_subscribes,op);
}
-static void sal_remove_in_subscribe(Sal *sal, int nid){
- MSList *elem;
- SalOp *op;
- for(elem=sal->in_subscribes;elem!=NULL;elem=elem->next){
- op=(SalOp*)elem->data;
- if (op->nid==nid) {
- sal->in_subscribes=ms_list_remove_link(sal->in_subscribes,elem);
- return;
- }
- }
+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){
@@ -122,7 +106,8 @@ int sal_unsubscribe(SalOp *op){
if (msg){
osip_message_set_expires(msg,"0");
eXosip_subscribe_send_refresh_request(op->did,msg);
- }else ms_error("Could not build subscribe refresh request !");
+ }else ms_error("Could not build subscribe refresh request ! op->sid=%i, op->did=%i",
+ op->sid,op->did);
eXosip_unlock();
return 0;
}
@@ -130,8 +115,8 @@ int sal_unsubscribe(SalOp *op){
int sal_subscribe_accept(SalOp *op){
osip_message_t *msg;
eXosip_lock();
- eXosip_insubscription_build_answer(op->tid,202,&msg);
- eXosip_insubscription_send_answer(op->tid,202,msg);
+ eXosip_insubscription_build_answer(op->tid,200,&msg);
+ eXosip_insubscription_send_answer(op->tid,200,msg);
eXosip_unlock();
return 0;
}
@@ -439,7 +424,7 @@ int sal_notify_close(SalOp *op){
if (identity==NULL) identity=sal_op_get_to(op);
osip_message_set_contact(msg,identity);
eXosip_insubscription_send_request(op->did,msg);
- }else ms_error("could not create notify for incoming subscription.");
+ }else ms_error("sal_notify_close(): could not create notify for incoming subscription.");
eXosip_unlock();
return 0;
}
@@ -636,8 +621,6 @@ void sal_exosip_notify_recv(Sal *sal, eXosip_event_t *ev){
osip_from_to_str(from,&tmp);
if (strstr(body->body,"pending")!=NULL){
estatus=SalPresenceOffline;
- }else if ((strstr(body->body,"online")!=NULL) || (strstr(body->body,"open")!=NULL)) {
- estatus=SalPresenceOnline;
}else if (strstr(body->body,"busy")!=NULL){
estatus=SalPresenceBusy;
}else if (strstr(body->body,"berightback")!=NULL
@@ -653,12 +636,14 @@ void sal_exosip_notify_recv(Sal *sal, eXosip_event_t *ev){
estatus=SalPresenceOuttolunch;
}else if (strstr(body->body,"closed")!=NULL){
estatus=SalPresenceOffline;
+ }else if ((strstr(body->body,"online")!=NULL) || (strstr(body->body,"open")!=NULL)) {
+ estatus=SalPresenceOnline;
}else{
estatus=SalPresenceOffline;
}
ms_message("We are notified that %s has online status %i",tmp,estatus);
if (ev->ss_status==EXOSIP_SUBCRSTATE_TERMINATED) {
- sal_remove_out_subscribe(sal,op->sid);
+ sal_remove_out_subscribe(sal,op);
op->sid=-1;
op->did=-1;
ms_message("And outgoing subscription terminated by remote.");
@@ -682,9 +667,9 @@ void sal_exosip_subscription_closed(Sal *sal,eXosip_event_t *ev){
ms_error("Subscription closed but no associated op !");
return;
}
- sal_remove_in_subscribe(sal,op->nid);
+ sal_remove_in_subscribe(sal,op);
op->nid=-1;
- op->did=0;
+ op->did=-1;
}
diff --git a/coreapi/sal_eXosip2_sdp.c b/coreapi/sal_eXosip2_sdp.c
index c1a1761cc..580428765 100644
--- a/coreapi/sal_eXosip2_sdp.c
+++ b/coreapi/sal_eXosip2_sdp.c
@@ -179,6 +179,8 @@ static void add_line(sdp_message_t *msg, int lineno, const SalStreamDescription
osip_strdup ("RTP/AVP"));
if (desc->bandwidth>0) sdp_message_b_bandwidth_add (msg, lineno, osip_strdup ("AS"),
int_2char(desc->bandwidth));
+ if (desc->ptime>0) sdp_message_a_attribute_add(msg,lineno,osip_strdup("ptime"),
+ int_2char(desc->ptime));
for(elem=desc->payloads;elem!=NULL;elem=elem->next){
add_payload(msg, lineno, (PayloadType*)elem->data);
}
diff --git a/coreapi/sdphandler.c b/coreapi/sdphandler.c
index 890217289..bf622a92e 100644
--- a/coreapi/sdphandler.c
+++ b/coreapi/sdphandler.c
@@ -238,6 +238,11 @@ sdp_context_add_payload (sdp_context_t * ctx, sdp_payload_t * payload, char *med
attr_field);
}
}
+ if (payload->a_ptime !=0) {
+ attr_field = sstrdup_sprintf ("%i", payload->a_ptime);
+ sdp_message_a_attribute_add(offer, payload->line,osip_strdup ("ptime"),attr_field);
+ ms_message("adding ptime [%s]",attr_field);
+ }
}
void
diff --git a/gtk-glade/incall_view.c b/gtk-glade/incall_view.c
index 4d38dc988..1167c5ccd 100644
--- a/gtk-glade/incall_view.c
+++ b/gtk-glade/incall_view.c
@@ -38,18 +38,36 @@ gboolean linphone_gtk_use_in_call_view(){
void linphone_gtk_show_in_call_view(void){
GtkWidget *main_window=linphone_gtk_get_main_window();
- GtkWidget *idle_frame=linphone_gtk_get_widget(main_window,"idle_frame");
+ GtkNotebook *notebook=(GtkNotebook *)linphone_gtk_get_widget(main_window,"viewswitch");
GtkWidget *in_call_frame=linphone_gtk_get_widget(main_window,"in_call_frame");
- gtk_widget_hide(idle_frame);
+ gint idx;
+
+ /* Make the in call frame visible and arrange for the notebook to
+ show that page */
gtk_widget_show(in_call_frame);
+ idx = gtk_notebook_page_num(notebook, in_call_frame);
+ if (idx >= 0) {
+ gtk_notebook_set_current_page(notebook, idx);
+ }
}
void linphone_gtk_show_idle_view(void){
GtkWidget *main_window=linphone_gtk_get_main_window();
+ GtkNotebook *notebook=(GtkNotebook *)linphone_gtk_get_widget(main_window,"viewswitch");
GtkWidget *idle_frame=linphone_gtk_get_widget(main_window,"idle_frame");
GtkWidget *in_call_frame=linphone_gtk_get_widget(main_window,"in_call_frame");
- gtk_widget_show(idle_frame);
- gtk_widget_hide(in_call_frame);
+ gint idx;
+
+ /* Switch back to the idle frame page, maybe we should have
+ remembered where we were in gtk_show_in_call_view() to switch
+ back to that page of the notebook, but this should do in most
+ cases. */
+ gtk_widget_show(idle_frame); /* Make sure it is visible... */
+ idx = gtk_notebook_page_num(notebook, idle_frame);
+ if (idx >= 0) {
+ gtk_notebook_set_current_page(notebook, idx);
+ gtk_widget_hide(in_call_frame);
+ }
}
void display_peer_name_in_label(GtkWidget *label, const char *uri){
@@ -91,13 +109,11 @@ void linphone_gtk_in_call_view_set_calling(const char *uri){
GtkWidget *duration=linphone_gtk_get_widget(main_window,"in_call_duration");
GtkWidget *animation=linphone_gtk_get_widget(main_window,"in_call_animation");
GdkPixbufAnimation *pbuf=create_pixbuf_animation("calling_anim.gif");
- GtkWidget *terminate_button=linphone_gtk_get_widget(main_window,"in_call_terminate");
- gtk_widget_set_sensitive(terminate_button,TRUE);
gtk_label_set_markup(GTK_LABEL(status),_("Calling..."));
display_peer_name_in_label(callee,uri);
- gtk_label_set_text(GTK_LABEL(duration),"00:00:00");
+ gtk_label_set_text(GTK_LABEL(duration),_("00::00::00"));
if (pbuf!=NULL){
gtk_image_set_from_animation(GTK_IMAGE(animation),pbuf);
g_object_unref(G_OBJECT(pbuf));
@@ -112,13 +128,11 @@ void linphone_gtk_in_call_view_set_in_call(){
GtkWidget *duration=linphone_gtk_get_widget(main_window,"in_call_duration");
GtkWidget *animation=linphone_gtk_get_widget(main_window,"in_call_animation");
GdkPixbufAnimation *pbuf=create_pixbuf_animation("incall_anim.gif");
- GtkWidget *terminate_button=linphone_gtk_get_widget(main_window,"in_call_terminate");
const LinphoneAddress *uri=linphone_core_get_remote_uri(lc);
char *tmp=linphone_address_as_string(uri);
display_peer_name_in_label(callee,tmp);
ms_free(tmp);
- gtk_widget_set_sensitive(terminate_button,TRUE);
gtk_label_set_markup(GTK_LABEL(status),_("In call with"));
gtk_label_set_text(GTK_LABEL(duration),_("00::00::00"));
@@ -150,10 +164,8 @@ void linphone_gtk_in_call_view_terminate(const char *error_msg){
GtkWidget *main_window=linphone_gtk_get_main_window();
GtkWidget *status=linphone_gtk_get_widget(main_window,"in_call_status");
GtkWidget *animation=linphone_gtk_get_widget(main_window,"in_call_animation");
- GtkWidget *terminate_button=linphone_gtk_get_widget(main_window,"in_call_terminate");
GdkPixbuf *pbuf=create_pixbuf(linphone_gtk_get_ui_config("stop_call_icon","red.png"));
- gtk_widget_set_sensitive(terminate_button,FALSE);
if (error_msg==NULL)
gtk_label_set_markup(GTK_LABEL(status),_("Call ended."));
else{
@@ -174,11 +186,17 @@ void linphone_gtk_draw_mute_button(GtkToggleButton *button, gboolean active){
if (active){
GtkWidget *image=create_pixmap("mic_muted.png");
gtk_button_set_label(GTK_BUTTON(button),_("Unmute"));
- if (image!=NULL) gtk_button_set_image(GTK_BUTTON(button),image);
+ if (image!=NULL) {
+ gtk_button_set_image(GTK_BUTTON(button),image);
+ gtk_widget_show(image);
+ }
}else{
GtkWidget *image=create_pixmap("mic_active.png");
gtk_button_set_label(GTK_BUTTON(button),_("Mute"));
- if (image!=NULL) gtk_button_set_image(GTK_BUTTON(button),image);
+ if (image!=NULL) {
+ gtk_button_set_image(GTK_BUTTON(button),image);
+ gtk_widget_show(image);
+ }
}
}
@@ -190,5 +208,6 @@ void linphone_gtk_mute_toggled(GtkToggleButton *button){
void linphone_gtk_enable_mute_button(GtkToggleButton *button, gboolean sensitive){
gtk_widget_set_sensitive(GTK_WIDGET(button),sensitive);
+ gtk_object_set(GTK_OBJECT(button),"gtk-button-images",TRUE,NULL);
linphone_gtk_draw_mute_button(button,FALSE);
}
diff --git a/gtk-glade/main.c b/gtk-glade/main.c
index 888eb3f7a..64927abac 100644
--- a/gtk-glade/main.c
+++ b/gtk-glade/main.c
@@ -552,7 +552,6 @@ void linphone_gtk_call_terminated(const char *error){
GtkWidget *icw;
gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"terminate_call"),FALSE);
gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"start_call"),TRUE);
- gtk_widget_hide_all(linphone_gtk_get_widget(mw,"go_to_call_view_box"));
linphone_gtk_enable_mute_button(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(mw,"main_mute")),FALSE);
if (linphone_gtk_use_in_call_view())
linphone_gtk_in_call_view_terminate(error);
@@ -576,7 +575,6 @@ static gboolean in_call_timer(){
static void linphone_gtk_call_started(GtkWidget *mw){
gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"start_call"),FALSE);
gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"terminate_call"),TRUE);
- gtk_widget_show_all(linphone_gtk_get_widget(mw,"go_to_call_view_box"));
update_video_title();
if (linphone_gtk_use_in_call_view())
g_timeout_add(250,(GSourceFunc)in_call_timer,NULL);
@@ -1063,7 +1061,6 @@ static void linphone_gtk_configure_main_window(){
if (stop_call_icon){
GdkPixbuf *pbuf=create_pixbuf(stop_call_icon);
gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"terminate_call_icon")),pbuf);
- gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"in_call_terminate_icon")),pbuf);
g_object_unref(G_OBJECT(pbuf));
}
if (search_icon){
@@ -1097,6 +1094,8 @@ void linphone_gtk_manage_login(void){
}
static void linphone_gtk_init_main_window(){
+ GtkWidget *main_window;
+
linphone_gtk_configure_main_window();
linphone_gtk_manage_login();
load_uri_history();
@@ -1105,10 +1104,14 @@ static void linphone_gtk_init_main_window(){
linphone_gtk_show_friends();
linphone_gtk_connect_digits();
linphone_gtk_check_menu_items();
- linphone_gtk_enable_mute_button(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(linphone_gtk_get_main_window(),
+ main_window=linphone_gtk_get_main_window();
+ linphone_gtk_enable_mute_button(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(main_window,
"main_mute")),FALSE);
- linphone_gtk_enable_mute_button(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(linphone_gtk_get_main_window(),
+ linphone_gtk_enable_mute_button(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(main_window,
"incall_mute")),FALSE);
+ if (!linphone_gtk_use_in_call_view()) {
+ gtk_widget_show(linphone_gtk_get_widget(main_window, "main_mute"));
+ }
if (linphone_core_in_call(linphone_gtk_get_core())) linphone_gtk_call_started(
linphone_gtk_get_main_window());/*hide the call button, show terminate button*/
}
diff --git a/gtk-glade/main.glade b/gtk-glade/main.glade
index 62d730f31..55fa4fb61 100644
--- a/gtk-glade/main.glade
+++ b/gtk-glade/main.glade
@@ -10,6 +10,7 @@
True
GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+ vertical
True
@@ -219,12 +220,11 @@
True
-
+
True
- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
vertical
-
+
True
@@ -365,281 +365,373 @@
-
+
True
- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+ True
-
+
True
+ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
vertical
-
+
True
GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
- 0
-
+
True
- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
- 12
- 12
+ vertical
-
+
True
GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
- vertical
+ 0
-
+
True
+ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+ 12
+ 12
-
+
True
GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
- Lookup:
-
-
- 12
- 0
-
-
-
-
- True
- True
- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
- ●
-
-
-
- 4
- 1
-
-
-
-
- True
- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
- in
-
-
- 8
- 2
-
-
-
-
- True
- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
- 0
- All users
-Online users
-
-
-
- 4
- 3
-
-
-
-
- False
- 0
-
-
-
-
- True
- True
- automatic
- automatic
-
-
- 120
- True
- True
- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
-
-
-
-
-
-
-
-
- 1
-
-
-
-
- True
- 0
- none
-
-
- True
+ vertical
-
+
True
- True
- ●
-
-
-
-
+
+
+ True
+ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+ Lookup:
+
+
+ 12
+ 0
+
+
+
+
+ True
+ True
+ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+ ●
+
+
+
+ 4
+ 1
+
+
+
+
+ True
+ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+ in
+
+
+ 8
+ 2
+
+
+
+
+ True
+ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+ 0
+ All users
+Online users
+
+
+
+ 4
+ 3
+
+
+ False
0
-
+
True
True
- True
- none
-
+ automatic
+ automatic
-
+
+ 120
+ True
+ True
+ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+
+
+
+
+
+
+
+
+ 1
+
+
+
+
+ True
+ 0
+ none
+
+
True
-
+
True
- gtk-find
+ True
+ ●
+
+
+
+
0
-
+
True
- Search
+ True
+ True
+ none
+
+
+
+ True
+
+
+ True
+ gtk-find
+
+
+ 0
+
+
+
+
+ True
+ Search
+
+
+ 1
+
+
+
+
+ False
1
+
+
+ True
+ <b>Add contacts from directory</b>
+ True
+
+
+ label_item
+
+
False
- 1
+ False
+ 5
+ 2
-
-
- True
- <b>Add contacts from directory</b>
- True
-
-
- label_item
-
-
+
+
+
+
+ True
+ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+ <b>Contact list</b>
+ True
- False
- False
- 5
- 2
+ label_item
+
+ 8
+ 0
+
+
+
+
+ True
+
+
+ Mute
+ False
+ True
+ True
+
+
+
+ False
+ 0
+
+
+
+
+ False
+ False
+ 1
+
+
+
+
+
+
+ True
+ Internet connection:
+
+
+ 0
+
+
+
+
+ True
+ 0
+ ADSL
+Fiber Channel
+
+
+
+ 1
+
+
+
+
+ False
+ 2
+
-
-
-
- True
- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
- <b>Contact list</b>
- True
-
- label_item
+ 8
+ 0
- 8
0
-
+
True
-
- Mute
- False
- True
- True
-
+
+ True
+ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+ 0
+
+
+ True
+
+
+ True
+ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+ 12
+
+
+ True
+ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+ 0
+ Default
+
+
+
+
+
+ 0
+
+
+
+
+ True
+ True
+ True
+
+
+
+ False
+ 1
+
+
+
+
+
+
+ True
+ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+ My current identity:
+ True
+
+
+ label_item
+
+
- False
0
False
- False
1
-
-
-
-
- True
- Internet connection:
-
-
- 0
-
-
-
-
- True
- 0
- ADSL
-Fiber Channel
-
-
-
- 1
-
-
-
-
- False
- 2
-
-
+
+
+
+
+ True
+ Contacts
- 8
- 0
+ False
+ tab
-
+
True
- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
vertical
-
+
True
- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
- 0
+ 0.5
+ none
True
- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+ 0
+ 0
True
@@ -647,6 +739,8 @@ Fiber Channel
4
4
4
+ 20
+ 10
True
@@ -661,7 +755,7 @@ Fiber Channel
4
3
4
-
+ GTK_FILL
@@ -678,7 +772,7 @@ Fiber Channel
3
3
4
-
+ GTK_FILL
@@ -695,7 +789,7 @@ Fiber Channel
2
3
4
-
+ GTK_FILL
@@ -710,7 +804,7 @@ Fiber Channel
3
4
-
+ GTK_FILL
@@ -727,7 +821,7 @@ Fiber Channel
4
2
3
-
+ GTK_FILL
@@ -744,7 +838,7 @@ Fiber Channel
3
2
3
-
+ GTK_FILL
@@ -761,7 +855,7 @@ Fiber Channel
2
2
3
-
+ GTK_FILL
@@ -776,7 +870,7 @@ Fiber Channel
2
3
-
+ GTK_FILL
@@ -793,7 +887,7 @@ Fiber Channel
4
1
2
-
+ GTK_FILL
@@ -810,7 +904,7 @@ Fiber Channel
3
1
2
-
+ GTK_FILL
@@ -827,7 +921,7 @@ Fiber Channel
2
1
2
-
+ GTK_FILL
@@ -842,7 +936,7 @@ Fiber Channel
1
2
-
+ GTK_FILL
@@ -857,7 +951,7 @@ Fiber Channel
3
4
-
+ GTK_FILL
@@ -872,7 +966,7 @@ Fiber Channel
2
3
-
+ GTK_FILL
@@ -887,7 +981,7 @@ Fiber Channel
1
2
-
+ GTK_FILL
@@ -900,7 +994,7 @@ Fiber Channel
GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
-
+ GTK_FILL
@@ -909,85 +1003,154 @@ Fiber Channel
-
- True
- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
- Digits
- True
-
+
label_item
- False
- False
0
+
+
+
- False
- False
1
-
-
- 1
-
-
-
-
- True
-
+
True
- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
- 0
+ Keypad
+
+
+ 1
+ False
+ tab
+
+
+
+
+ 0.5
+ none
-
+
True
+ 12
+ 12
-
+
True
- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
- 12
+ vertical
-
+
True
- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
- 0
- Default
-
+ gtk-info
+ 5
+
+ 0
+
+
+
+
+ True
+ 0
+
+
+ True
+ label
+ center
+
+
+
+
+ True
+ True
+
+
+ label_item
+
+
+
+
+ 1
+
+
+
+
+ True
+ 0
+
+
+ True
+ vertical
+
+
+ True
+ Duration
+ center
+
+
+ 0
+
+
+
+
+
+
+ True
+ Duration:
+ True
+
+
+ label_item
+
+
+
+
+ False
+ 2
+
+
+
+
+ True
+
+
+ Mute
+ True
+ False
+ True
+ True
+
+
+
+ False
+ False
+ 0
+
+
+
+
+ False
+ False
+ 3
+
-
- 0
-
-
-
-
- True
- True
- True
-
-
-
- False
- 1
-
-
+
True
- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
- My current identity:
+ In call
True
+ center
label_item
@@ -995,57 +1158,23 @@ Fiber Channel
- 0
+ 2
-
-
- False
- 2
-
-
-
-
-
- True
- True
-
-
-
- True
-
-
- True
- gtk-go-forward
-
-
- 0
-
-
-
-
- True
- Show current call
-
-
- 1
-
-
-
-
+
+ True
+ Call Details
- False
- False
- 8
- end
- 0
+ 2
+ False
+ tab
- 3
+ 1
@@ -1053,231 +1182,6 @@ Fiber Channel
0
-
-
- 0.5
-
-
- True
- 12
- 12
-
-
- True
- vertical
-
-
- True
- gtk-info
- 5
-
-
- 0
-
-
-
-
- True
- 0
-
-
- True
- label
- center
-
-
-
-
- True
- True
-
-
- label_item
-
-
-
-
- 1
-
-
-
-
- True
- 0
-
-
- True
- vertical
-
-
- True
- Duration
- center
-
-
- 0
-
-
-
-
-
-
- True
- Duration:
- True
-
-
- label_item
-
-
-
-
- False
- 2
-
-
-
-
- True
-
-
- Mute
- True
- False
- True
- True
-
-
-
- False
- False
- 0
-
-
-
-
- False
- False
- 3
-
-
-
-
- True
- center
-
-
- True
- True
- True
-
-
-
- True
-
-
- True
- gtk-close
- 3
-
-
- 0
-
-
-
-
- True
- <b>Terminate call</b>
- True
-
-
- 1
-
-
-
-
-
-
- False
- False
- 0
-
-
-
-
- 8
- 4
-
-
-
-
- True
- center
-
-
- True
- True
- True
-
-
-
- True
-
-
- True
- gtk-go-back
- 1
-
-
- 0
-
-
-
-
- True
- Main view
-
-
- 1
-
-
-
-
-
-
- False
- False
- end
- 0
-
-
-
-
- False
- False
- 5
-
-
-
-
-
-
-
-
- True
- In call
- True
- center
-
-
- label_item
-
-
-
-
- 1
-
-
0
@@ -1445,7 +1349,7 @@ Fiber Channel
- 2
+ 1
diff --git a/mediastreamer2 b/mediastreamer2
index 2e18cdfe5..5bcbcae29 160000
--- a/mediastreamer2
+++ b/mediastreamer2
@@ -1 +1 @@
-Subproject commit 2e18cdfe53230763907f3f9b55adeb4c16d396a7
+Subproject commit 5bcbcae29d9cf6d22b4f6880489eafa98e100008