From c6c7d662ded5e787f18f6057275d601efc0d0faf Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 18 Oct 2010 17:31:05 +0200 Subject: [PATCH 01/27] update ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 93ef451fd..af119e5c8 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 93ef451fd6da31fd70fd59e6a6ca59cc26a3b287 +Subproject commit af119e5c828e81a822d63af8ffb860764b8f20b4 From b6535cd6deb7d821c52ac31ea534cf5529ab8e5d Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Wed, 20 Oct 2010 16:18:51 +0200 Subject: [PATCH 02/27] remove dependency on CoreServices for exosip build --- m4/exosip.m4 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/m4/exosip.m4 b/m4/exosip.m4 index 725def2bb..c25d8ad96 100644 --- a/m4/exosip.m4 +++ b/m4/exosip.m4 @@ -6,7 +6,7 @@ AC_REQUIRE([LP_CHECK_OSIP2]) case $target_os in *darwin*) - OSIP_LIBS="$OSIP_LIBS -framework CoreFoundation -framework CoreServices " + OSIP_LIBS="$OSIP_LIBS -framework CoreFoundation " ;; esac From e07a927d7e45d6ab50184e670692d1540c5cfc55 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 20 Oct 2010 17:48:14 +0200 Subject: [PATCH 03/27] implemented attended transfer (untested yet) --- console/commands.c | 32 +++++++--- coreapi/callbacks.c | 4 +- coreapi/linphonecall.c | 3 + coreapi/linphonecore.c | 45 +++++++++++--- coreapi/linphonecore.h | 2 + coreapi/private.h | 1 + coreapi/sal.h | 7 ++- coreapi/sal_eXosip2.c | 137 ++++++++++++++++++++++++++++++++--------- coreapi/sal_eXosip2.h | 1 + mediastreamer2 | 2 +- oRTP | 2 +- 11 files changed, 184 insertions(+), 52 deletions(-) diff --git a/console/commands.c b/console/commands.c index d22d4b818..a7aa22f76 100644 --- a/console/commands.c +++ b/console/commands.c @@ -170,6 +170,12 @@ static LPC_COMMAND commands[] = { { "resume", lpc_cmd_resume, "resume a call", "'resume' : resume the unique call\n" "'resume ' : hold off the call with given id\n"}, + { "transfer", lpc_cmd_transfer, + "Transfer a call to a specified destination.", + "'transfer ' : transfers the current active call to the destination sip-uri\n" + "'transfer ': transfers the call with 'id' to the destination sip-uri\n" + "'transfer --to-call ': transfers the call with 'id1' to the destination of call 'id2' (attended transfer)\n" + }, { "mute", lpc_cmd_mute_mic, "Mute microphone and suspend voice transmission."}, #ifdef VIDEO_ENABLED @@ -209,11 +215,6 @@ static LPC_COMMAND commands[] = { "'ipv6 enable' : enable the use of the ipv6 network.\n" "'ipv6 disable' : do not use ipv6 network." }, - { "transfer", lpc_cmd_transfer, - "Transfer a call to a specified destination.", - "'transfer ' : transfers the current active call to the destination sip-uri" - "'transfer ': transfers the call with 'id' to the destination sip-uri" - }, { "nat", lpc_cmd_nat, "Set nat address", "'nat' : show nat settings.\n" "'nat ' : set nat address.\n" @@ -637,10 +638,12 @@ lpc_cmd_transfer(LinphoneCore *lc, char *args) { if (args){ LinphoneCall *call; + LinphoneCall *call2; const char *refer_to=NULL; char arg1[256]={0}; char arg2[266]={0}; - int n=sscanf(args,"%s %s",arg1,arg2); + long id2=0; + int n=sscanf(args,"%s %s %li",arg1,arg2,&id2); if (n==1 || isalpha(*arg1)){ call=linphone_core_get_current_call(lc); if (call==NULL && ms_list_size(linphone_core_get_calls(lc))==1){ @@ -651,13 +654,24 @@ lpc_cmd_transfer(LinphoneCore *lc, char *args) linphonec_out("No active call, please specify a call id among the ones listed by 'calls' command.\n"); return 0; } - }else{ + linphone_core_transfer_call(lc, call, refer_to); + }else if (n==2){ long id=atoi(arg1); refer_to=args+strlen(arg1)+1; call=linphonec_get_call(id); if (call==NULL) return 0; - } - linphone_core_transfer_call(lc, call, refer_to); + linphone_core_transfer_call(lc, call, refer_to); + }else if (n==3){ + long id=atoi(arg1); + call=linphonec_get_call(id); + call2=linphonec_get_call(id2); + if (call==NULL || call2==NULL) return 0; + if (strcmp(arg2,"--to-call")!=0){ + return 0; + } + linphonec_out("Performing attended transfer of call %i to call %i",id,id2); + linphone_core_transfer_call_to_another (lc,call,call2); + }else return 0; }else{ linphonec_out("Transfer command requires at least one argument\n"); return 0; diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index add616d85..9f7cd2658 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -557,10 +557,10 @@ static void refer_received(Sal *sal, SalOp *op, const char *referto){ ms_free(msg); } if (lc->current_call==NULL) linphone_core_start_pending_refered_calls (lc); - sal_refer_accept(op); + sal_call_accept_refer(op); }else if (lc->vtable.refer_received){ lc->vtable.refer_received(lc,referto); - sal_refer_accept(op); + sal_call_accept_refer(op); } } diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 8139bbdb2..1cdc41ffe 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -161,6 +161,9 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr if (linphone_core_get_firewall_policy(call->core)==LinphonePolicyUseStun) linphone_core_run_stun_tests(call->core,call); discover_mtu(lc,linphone_address_get_domain (to)); + if (params->referer){ + sal_call_set_referer (call->op,params->referer->op); + } return call; } diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index b9e7fe518..9abea19a0 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1844,9 +1844,12 @@ void linphone_core_start_pending_refered_calls(LinphoneCore *lc){ for(elem=lc->calls;elem!=NULL;elem=elem->next){ LinphoneCall *call=(LinphoneCall*)elem->data; if (call->refer_pending){ + LinphoneCallParams *cp=linphone_core_create_default_call_parameters(lc); + cp->referer=call; ms_message("Starting new call to refered address %s",call->refer_to); call->refer_pending=FALSE; - linphone_core_invite(lc,call->refer_to); + linphone_core_invite_with_params(lc,call->refer_to,cp); + linphone_call_params_destroy(cp); break; } } @@ -2143,12 +2146,28 @@ int linphone_core_transfer_call(LinphoneCore *lc, LinphoneCall *call, const char } //lc->call=NULL; //Do not do that you will lose the call afterward . . . real_url=linphone_address_as_string (real_parsed_url); - sal_refer(call->op,real_url); + sal_call_refer(call->op,real_url); ms_free(real_url); linphone_address_destroy(real_parsed_url); return 0; } +/** + * Transfer a call to destination of another running call. This is used for "attended transfer" scenarios. + * @param lc linphone core object + * @param call a running call you want to transfer + * @param dest a running call whose remote person will receive the transfer + * + * The transfered call is supposed to be in paused state, so that it is able to accept the transfer immediately. + * The destination call is a call previously established to introduce the transfered person. + * This method will send a transfer request to the transfered person. The phone of the transfered is then + * expected to automatically call to the destination of the transfer. The receiver of the transfer will then automatically + * close the call with us (the 'dest' call). +**/ +int linphone_core_transfer_call_to_another(LinphoneCore *lc, LinphoneCall *call, LinphoneCall *dest){ + return sal_call_refer_with_replaces (call->op,dest->op); +} + bool_t linphone_core_inc_invite_pending(LinphoneCore*lc){ LinphoneCall *call = linphone_core_get_current_call(lc); if(call != NULL) @@ -2198,6 +2217,7 @@ int linphone_core_accept_call(LinphoneCore *lc, LinphoneCall *call) { LinphoneProxyConfig *cfg=NULL; const char *contact=NULL; + SalOp *replaced; if (call==NULL){ //if just one call is present answer the only one ... @@ -2207,16 +2227,27 @@ int linphone_core_accept_call(LinphoneCore *lc, LinphoneCall *call) call = (LinphoneCall*)linphone_core_get_calls(lc)->data; } + if (call->state==LinphoneCallConnected){ + /*call already accepted*/ + return -1; + } + + /* check if this call is supposed to replace an already running one*/ + replaced=sal_call_get_replaces(call->op); + if (replaced){ + LinphoneCall *rc=(LinphoneCall*)sal_op_get_user_pointer (replaced); + if (rc){ + ms_message("Call %p replaces call %p. This last one is going to be terminated automatically.", + call,rc); + linphone_core_terminate_call (lc,rc); + } + } + if (lc->current_call!=NULL && lc->current_call!=call){ ms_warning("Cannot accept this call, there is already one running."); return -1; } - if (call->state==LinphoneCallConnected){ - /*call already accepted*/ - return -1; - } - /*can accept a new call only if others are on hold */ { MSList *elem; diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 1a75f5bad..313907ad9 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -591,6 +591,8 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const int linphone_core_transfer_call(LinphoneCore *lc, LinphoneCall *call, const char *refer_to); +int linphone_core_transfer_call_to_another(LinphoneCore *lc, LinphoneCall *call, LinphoneCall *dest); + bool_t linphone_core_inc_invite_pending(LinphoneCore*lc); bool_t linphone_core_in_call(const LinphoneCore *lc); diff --git a/coreapi/private.h b/coreapi/private.h index 9bee983b6..b41c772dd 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -57,6 +57,7 @@ struct _LinphoneCallParams{ + LinphoneCall *referer; /*in case this call creation is consecutive to an incoming transfer, this points to the original call */ bool_t has_video; bool_t pad[3]; }; diff --git a/coreapi/sal.h b/coreapi/sal.h index 0fcd6e5a8..b0b3c7574 100644 --- a/coreapi/sal.h +++ b/coreapi/sal.h @@ -282,8 +282,11 @@ int sal_call_decline(SalOp *h, SalReason reason, const char *redirection /*optio int sal_call_hold(SalOp *h, bool_t holdon); int sal_call_update(SalOp *h); SalMediaDescription * sal_call_get_final_media_description(SalOp *h); -int sal_refer(SalOp *h, const char *refer_to); -int sal_refer_accept(SalOp *h); +int sal_call_refer(SalOp *h, const char *refer_to); +int sal_call_refer_with_replaces(SalOp *h, SalOp *other_call_h); +int sal_call_accept_refer(SalOp *h); +/*informs this call is consecutive to an incoming refer */ +int sal_call_set_referer(SalOp *h, SalOp *refered_call); /* returns the SalOp of a call that should be replaced by h, if any */ SalOp *sal_call_get_replaces(SalOp *h); int sal_call_send_dtmf(SalOp *h, char dtmf); diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c index c61ec96ab..dfa4744cb 100644 --- a/coreapi/sal_eXosip2.c +++ b/coreapi/sal_eXosip2.c @@ -162,6 +162,7 @@ SalOp * sal_op_new(Sal *sal){ op->reinvite=FALSE; op->call_id=NULL; op->replaces=NULL; + op->referred_by=NULL; op->masquerade_via=FALSE; op->auto_answer_asked=FALSE; return op; @@ -205,6 +206,9 @@ void sal_op_release(SalOp *op){ if (op->replaces){ ms_free(op->replaces); } + if (op->referred_by){ + ms_free(op->referred_by); + } __sal_op_free(op); } @@ -494,6 +498,12 @@ int sal_call(SalOp *h, const char *from, const char *to){ h->sdp_offering=TRUE; set_sdp_from_desc(invite,h->base.local_media); }else h->sdp_offering=FALSE; + if (h->replaces){ + osip_message_set_header(invite,"Replaces",h->replaces); + if (h->referred_by) + osip_message_set_header(invite,"Referred-By",h->referred_by); + } + eXosip_lock(); err=eXosip_call_send_initial_invite(invite); eXosip_unlock(); @@ -610,6 +620,14 @@ SalMediaDescription * sal_call_get_final_media_description(SalOp *h){ return h->result; } +int sal_call_set_referer(SalOp *h, SalOp *refered_call){ + if (refered_call->replaces) + h->replaces=ms_strdup(refered_call->replaces); + if (refered_call->referred_by) + h->referred_by=ms_strdup(refered_call->referred_by); + return 0; +} + int sal_ping(SalOp *op, const char *from, const char *to){ osip_message_t *options=NULL; @@ -628,7 +646,7 @@ int sal_ping(SalOp *op, const char *from, const char *to){ return -1; } -int sal_refer_accept(SalOp *op){ +int sal_call_accept_refer(SalOp *op){ osip_message_t *msg=NULL; int err=0; eXosip_lock(); @@ -648,7 +666,7 @@ int sal_refer_accept(SalOp *op){ return err; } -int sal_refer(SalOp *h, const char *refer_to){ +int sal_call_refer(SalOp *h, const char *refer_to){ osip_message_t *msg=NULL; int err=0; eXosip_lock(); @@ -659,6 +677,24 @@ int sal_refer(SalOp *h, const char *refer_to){ return err; } +int sal_call_refer_with_replaces(SalOp *h, SalOp *other_call_h){ + osip_message_t *msg=NULL; + char referto[256]={0}; + int err=0; + eXosip_lock(); + if (eXosip_call_get_referto(other_call_h->did,referto,sizeof(referto)-1)!=0){ + ms_error("eXosip_call_get_referto() failed for did=%i",other_call_h->did); + eXosip_unlock(); + return -1; + } + eXosip_call_build_refer(h->did,referto, &msg); + osip_message_set_header(msg,"Referred-By",h->base.from); + if (msg) err=eXosip_call_send_request(h->did, msg); + else err=-1; + eXosip_unlock(); + return err; +} + SalOp *sal_call_get_replaces(SalOp *h){ if (h->replaces!=NULL){ int cid; @@ -1240,6 +1276,59 @@ static void process_dtmf_relay(Sal *sal, eXosip_event_t *ev){ } } +static void fill_options_answer(osip_message_t *options){ + osip_message_set_allow(options,"INVITE, ACK, BYE, CANCEL, OPTIONS, MESSAGE, SUBSCRIBE, NOTIFY, INFO"); + osip_message_set_accept(options,"application/sdp"); +} + +static void process_refer(Sal *sal, SalOp *op, eXosip_event_t *ev){ + osip_header_t *h=NULL; + osip_message_t *ans=NULL; + ms_message("Receiving REFER request !"); + osip_message_header_get_byname(ev->request,"Refer-To",0,&h); + + if (h){ + osip_from_t *from=NULL; + char *tmp; + osip_from_init(&from); + + if (osip_from_parse(from,h->hvalue)==0){ + if (op ){ + osip_uri_header_t *uh=NULL; + osip_header_t *referred_by=NULL; + osip_uri_header_get_byname(&from->url->url_headers,(char*)"Replaces",&uh); + if (uh!=NULL && uh->gvalue && uh->gvalue[0]!='\0'){ + ms_message("Found replaces in Refer-To"); + if (op->replaces){ + ms_free(op->replaces); + } + op->replaces=ms_strdup(uh->gvalue); + } + osip_message_header_get_byname(ev->request,"Referred-By",0,&referred_by); + if (referred_by && referred_by->hvalue && referred_by->hvalue[0]!='\0'){ + if (op->referred_by) + ms_free(op->referred_by); + op->referred_by=ms_strdup(referred_by->hvalue); + } + } + osip_uri_header_freelist(&from->url->url_headers); + osip_from_to_str(from,&tmp); + sal->callbacks.refer_received(sal,op,tmp); + osip_free(tmp); + osip_from_free(from); + } + eXosip_lock(); + eXosip_call_build_answer(ev->tid,202,&ans); + if (ans) + eXosip_call_send_answer(ev->tid,202,ans); + eXosip_unlock(); + } + else + { + ms_warning("cannot do anything with the refer without destination\n"); + } +} + static void call_message_new(Sal *sal, eXosip_event_t *ev){ osip_message_t *ans=NULL; if (ev->request){ @@ -1268,8 +1357,7 @@ static void call_message_new(Sal *sal, eXosip_event_t *ev){ eXosip_call_send_answer(ev->tid,200,ans); eXosip_unlock(); } - } - if(MSG_IS_MESSAGE(ev->request)){ + }else if(MSG_IS_MESSAGE(ev->request)){ /* SIP messages could be received into call */ text_received(sal, ev); eXosip_lock(); @@ -1277,27 +1365,12 @@ static void call_message_new(Sal *sal, eXosip_event_t *ev){ if (ans) eXosip_call_send_answer(ev->tid,200,ans); eXosip_unlock(); - } - if(MSG_IS_REFER(ev->request)){ - osip_header_t *h=NULL; + }else if(MSG_IS_REFER(ev->request)){ SalOp *op=find_op(sal,ev); ms_message("Receiving REFER request !"); - osip_message_header_get_byname(ev->request,"Refer-To",0,&h); - eXosip_lock(); - eXosip_call_build_answer(ev->tid,202,&ans); - if (ans) - eXosip_call_send_answer(ev->tid,202,ans); - eXosip_unlock(); - if (h){ - sal->callbacks.refer_received(sal,op,h->hvalue); - } - else - { - ms_warning("cannot do anything with the refer without destination\n"); - } - } - if(MSG_IS_NOTIFY(ev->request)){ + process_refer(sal,op,ev); + }else if(MSG_IS_NOTIFY(ev->request)){ osip_header_t *h=NULL; char *from=NULL; SalOp *op=find_op(sal,ev); @@ -1314,6 +1387,14 @@ static void call_message_new(Sal *sal, eXosip_event_t *ev){ eXosip_call_send_answer(ev->tid,200,ans); eXosip_unlock(); osip_free(from); + }else if (MSG_IS_OPTIONS(ev->request)){ + eXosip_lock(); + eXosip_call_build_answer(ev->tid,200,&ans); + if (ans){ + fill_options_answer(ans); + eXosip_call_send_answer(ev->tid,200,ans); + } + eXosip_unlock(); } }else ms_warning("call_message_new: No request ?"); } @@ -1362,6 +1443,8 @@ static void text_received(Sal *sal, eXosip_event_t *ev){ osip_free(from); } + + static void other_request(Sal *sal, eXosip_event_t *ev){ ms_message("in other_request"); if (ev->request==NULL) return; @@ -1371,8 +1454,7 @@ static void other_request(Sal *sal, eXosip_event_t *ev){ }else if (strcmp(ev->request->sip_method,"OPTIONS")==0){ osip_message_t *options=NULL; eXosip_options_build_answer(ev->tid,200,&options); - osip_message_set_allow(options,"INVITE, ACK, BYE, CANCEL, OPTIONS, MESSAGE, SUBSCRIBE, NOTIFY, INFO"); - osip_message_set_accept(options,"application/sdp"); + fill_options_answer(options); eXosip_options_send_answer(ev->tid,200,options); }else if (strcmp(ev->request->sip_method,"WAKEUP")==0 && comes_from_local_if(ev->request)) { @@ -1382,12 +1464,7 @@ static void other_request(Sal *sal, eXosip_event_t *ev){ }else if (strncmp(ev->request->sip_method, "REFER", 5) == 0){ ms_message("Receiving REFER request !"); if (comes_from_local_if(ev->request)) { - osip_header_t *h=NULL; - osip_message_header_get_byname(ev->request,"Refer-To",0,&h); - eXosip_message_send_answer(ev->tid,200,NULL); - if (h){ - sal->callbacks.refer_received(sal,NULL,h->hvalue); - } + process_refer(sal,NULL,ev); }else ms_warning("Ignored REFER not coming from this local loopback interface."); }else if (strncmp(ev->request->sip_method, "UPDATE", 6) == 0){ inc_update(sal,ev); diff --git a/coreapi/sal_eXosip2.h b/coreapi/sal_eXosip2.h index bfb3d10f2..10c8b46b7 100644 --- a/coreapi/sal_eXosip2.h +++ b/coreapi/sal_eXosip2.h @@ -57,6 +57,7 @@ struct SalOp{ osip_call_id_t *call_id; /*used for out of calls transaction in order to retrieve the operation when receiving a response*/ char *replaces; + char *referred_by; bool_t supports_session_timers; bool_t sdp_offering; bool_t reinvite; diff --git a/mediastreamer2 b/mediastreamer2 index af119e5c8..e3a50ec46 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit af119e5c828e81a822d63af8ffb860764b8f20b4 +Subproject commit e3a50ec460494101e925fa112e97adbc82c45306 diff --git a/oRTP b/oRTP index 461dd13a0..930fac6f5 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 461dd13a0aad2a075a075bf618e68443475f7a24 +Subproject commit 930fac6f59b13cdd6cbb5f370911a65f98bad7de From 1732f679c55a4dd31cc957470b023840b76069d8 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 20 Oct 2010 21:33:44 +0200 Subject: [PATCH 04/27] update ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index e3a50ec46..bf8706f50 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit e3a50ec460494101e925fa112e97adbc82c45306 +Subproject commit bf8706f50f26e17b3ecc1501e70b712ec11d0dc3 From 820eaf86ed98aefbc303132bce2821674b840f3a Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 22 Oct 2010 09:56:47 +0200 Subject: [PATCH 05/27] fix linphone_core_get_local_ip_for(): don't use getifaddrs() when a destination address is supplied --- coreapi/misc.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/coreapi/misc.c b/coreapi/misc.c index ced4f3396..cc5aa5512 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -754,14 +754,10 @@ static int get_local_ip_for_with_connect(int type, const char *dest, char *resul } int linphone_core_get_local_ip_for(int type, const char *dest, char *result){ - if (dest==NULL) { - if (type==AF_INET) - dest="87.98.157.38"; /*a public IP address*/ - else dest="2a00:1450:8002::68"; - } strcpy(result,type==AF_INET ? "127.0.0.1" : "::1"); #ifdef HAVE_GETIFADDRS - { + if (dest==NULL) { + /*we use getifaddrs for lookup of default interface */ int found_ifs; found_ifs=get_local_ip_with_getifaddrs(type,result,LINPHONE_IPADDR_SIZE); @@ -774,5 +770,8 @@ int linphone_core_get_local_ip_for(int type, const char *dest, char *result){ } #endif /*else use connect to find the best local ip address */ + if (type==AF_INET) + dest="87.98.157.38"; /*a public IP address*/ + else dest="2a00:1450:8002::68"; return get_local_ip_for_with_connect(type,dest,result); } From 50b7001d1d28b2dc88e418cd9c93ad49e35714e0 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 22 Oct 2010 14:44:20 +0200 Subject: [PATCH 06/27] refer improvements --- coreapi/callbacks.c | 7 +++++-- coreapi/linphonecall.c | 1 - coreapi/linphonecore.c | 22 ++++++++-------------- coreapi/private.h | 2 +- coreapi/sal_eXosip2_presence.c | 1 + mediastreamer2 | 2 +- 6 files changed, 16 insertions(+), 19 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 9f7cd2658..cc49391d9 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -343,7 +343,6 @@ static void call_updating(SalOp *op){ linphone_call_set_state (call,prevstate,"Connected (streams running)"); } } - if (lc->current_call==NULL) linphone_core_start_pending_refered_calls (lc); } static void call_terminated(SalOp *op, const char *from){ @@ -556,7 +555,11 @@ static void refer_received(Sal *sal, SalOp *op, const char *referto){ lc->vtable.display_status(lc,msg); ms_free(msg); } - if (lc->current_call==NULL) linphone_core_start_pending_refered_calls (lc); + if (call->state!=LinphoneCallPaused){ + ms_message("Automatically pausing current call to accept transfer."); + linphone_core_pause_call(lc,call); + } + linphone_core_start_refered_call(lc,call); sal_call_accept_refer(op); }else if (lc->vtable.refer_received){ lc->vtable.refer_received(lc,referto); diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 1cdc41ffe..4ec373fd7 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -224,7 +224,6 @@ static void linphone_call_set_terminated(LinphoneCall *call){ if (call == lc->current_call){ ms_message("Resetting the current call"); lc->current_call=NULL; - linphone_core_start_pending_refered_calls(lc); } if (linphone_core_del_call(lc,call) != 0){ diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 9abea19a0..438fdaa26 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1839,19 +1839,14 @@ const char * linphone_core_get_route(LinphoneCore *lc){ return route; } -void linphone_core_start_pending_refered_calls(LinphoneCore *lc){ - MSList *elem; - for(elem=lc->calls;elem!=NULL;elem=elem->next){ - LinphoneCall *call=(LinphoneCall*)elem->data; - if (call->refer_pending){ - LinphoneCallParams *cp=linphone_core_create_default_call_parameters(lc); - cp->referer=call; - ms_message("Starting new call to refered address %s",call->refer_to); - call->refer_pending=FALSE; - linphone_core_invite_with_params(lc,call->refer_to,cp); - linphone_call_params_destroy(cp); - break; - } +void linphone_core_start_refered_call(LinphoneCore *lc, LinphoneCall *call){ + if (call->refer_pending){ + LinphoneCallParams *cp=linphone_core_create_default_call_parameters(lc); + cp->referer=call; + ms_message("Starting new call to refered address %s",call->refer_to); + call->refer_pending=FALSE; + linphone_core_invite_with_params(lc,call->refer_to,cp); + linphone_call_params_destroy(cp); } } @@ -2425,7 +2420,6 @@ int linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *the_call) lc->current_call=NULL; if (call->audiostream || call->videostream) linphone_call_stop_media_streams (call); - linphone_core_start_pending_refered_calls(lc); return 0; } diff --git a/coreapi/private.h b/coreapi/private.h index b41c772dd..029405edd 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -197,7 +197,7 @@ void linphone_core_update_progress(LinphoneCore *lc, const char *purpose, float void linphone_core_stop_waiting(LinphoneCore *lc); int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call, LinphoneProxyConfig *dest_proxy); -void linphone_core_start_pending_refered_calls(LinphoneCore *lc); +void linphone_core_start_refered_call(LinphoneCore *lc, LinphoneCall *call); extern SalCallbacks linphone_sal_callbacks; void linphone_proxy_config_set_error(LinphoneProxyConfig *cfg,LinphoneError error); diff --git a/coreapi/sal_eXosip2_presence.c b/coreapi/sal_eXosip2_presence.c index 1e7409f19..675a45117 100644 --- a/coreapi/sal_eXosip2_presence.c +++ b/coreapi/sal_eXosip2_presence.c @@ -627,6 +627,7 @@ int sal_publish(SalOp *op, const char *from, const char *to, SalPresenceStatus p ms_message("Failed to send publish request."); return -1; } + sal_add_other(sal_op_get_sal(op),op,pub); return 0; } diff --git a/mediastreamer2 b/mediastreamer2 index bf8706f50..dcf3eba1a 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit bf8706f50f26e17b3ecc1501e70b712ec11d0dc3 +Subproject commit dcf3eba1afa5615cb01b52b1136d8aa0d224aca2 From 51ab2138098f2223b2bb24378696306cbeed26cb Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Fri, 22 Oct 2010 18:28:17 +0200 Subject: [PATCH 07/27] add messaging and presence java binding (jni listener are still missing) --- coreapi/linphonecore_jni.cc | 103 ++++++++++ .../org/linphone/core/LinphoneAuthInfo.java | 45 +++- .../org/linphone/core/LinphoneChatRoom.java | 39 ++++ .../org/linphone/core/LinphoneCore.java | 21 +- .../linphone/core/LinphoneCoreFactory.java | 13 ++ .../linphone/core/LinphoneCoreListener.java | 23 +++ .../org/linphone/core/LinphoneFriend.java | 122 +++++++++++ .../linphone/core/LinphoneProxyConfig.java | 60 +++++- .../org/linphone/core/OnlineStatus.java | 96 +++++++++ java/common/org/linphone/core/package.html | 194 ++++++++++++++++++ 10 files changed, 701 insertions(+), 15 deletions(-) create mode 100644 java/common/org/linphone/core/LinphoneChatRoom.java create mode 100644 java/common/org/linphone/core/LinphoneFriend.java create mode 100644 java/common/org/linphone/core/OnlineStatus.java create mode 100644 java/common/org/linphone/core/package.html diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index d1351a362..1ba35d6e6 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -456,7 +456,34 @@ extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_getCurrentCall(JNIEnv* ) { return (jlong)linphone_core_get_current_call((LinphoneCore*)lc); } +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_addFriend(JNIEnv* env + ,jobject thiz + ,jlong lc + ,jlong aFriend + ) { + linphone_core_add_friend((LinphoneCore*)lc,(LinphoneFriend*)aFriend); +} +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setPresenceInfo(JNIEnv* env + ,jobject thiz + ,jlong lc + ,jint minute_away + ,jstring jalternative_contact + ,jint status) { + const char* alternative_contact = env->GetStringUTFChars(jalternative_contact, NULL); + linphone_core_set_presence_info((LinphoneCore*)lc,minute_away,alternative_contact,status); + env->ReleaseStringUTFChars(jalternative_contact, alternative_contact); +} +extern "C" long Java_org_linphone_core_LinphoneCoreImpl_createChatRoom(JNIEnv* env + ,jobject thiz + ,jlong lc + ,jstring jto) { + + const char* to = env->GetStringUTFChars(jto, NULL); + LinphoneChatRoom* lResult = linphone_core_create_chat_room((LinphoneCore*)lc,to); + env->ReleaseStringUTFChars(jto, to); + return (long)lResult; +} //ProxyConfig @@ -741,6 +768,82 @@ extern "C" jint Java_org_linphone_core_LinphoneCallImpl_getState( JNIEnv* env return (jint)linphone_call_get_state((LinphoneCall*)ptr); } +//LinphoneFriend +extern "C" long Java_org_linphone_core_LinphoneFriendImpl_newLinphoneFriend(JNIEnv* env + ,jobject thiz + ,jstring jFriendUri) { + LinphoneFriend* lResult; + if (jFriendUri) { + const char* friendUri = env->GetStringUTFChars(jFriendUri, NULL); + lResult= linphone_friend_new_with_addr(friendUri); + env->ReleaseStringUTFChars(jFriendUri, friendUri); + } else { + lResult = linphone_friend_new(); + } + return (long)lResult; +} +extern "C" void Java_org_linphone_core_LinphoneFriendImpl_setAddress(JNIEnv* env + ,jobject thiz + ,jlong ptr + ,jlong linphoneAddress) { + linphone_friend_set_address((LinphoneFriend*)ptr,(LinphoneAddress*)linphoneAddress); +} +extern "C" long Java_org_linphone_core_LinphoneFriendImpl_setAddress(JNIEnv* env + ,jobject thiz + ,jlong ptr) { + return (long)linphone_friend_get_address((LinphoneFriend*)ptr); +} +extern "C" void Java_org_linphone_core_LinphoneFriendImpl_setIncSubscribePolicy(JNIEnv* env + ,jobject thiz + ,jlong ptr + ,jint policy) { + linphone_friend_set_inc_subscribe_policy((LinphoneFriend*)ptr,policy); +} +extern "C" jint Java_org_linphone_core_LinphoneFriendImpl_getIncSubscribePolicy(JNIEnv* env + ,jobject thiz + ,jlong ptr) { + return linphone_friend_get_inc_subscribe_policy((LinphoneFriend*)ptr); +} +extern "C" void Java_org_linphone_core_LinphoneFriendImpl_enableSubscribes(JNIEnv* env + ,jobject thiz + ,jlong ptr + ,jboolean value) { + linphone_friend_enable_subscribes((LinphoneFriend*)ptr,value); +} +extern "C" jboolean Java_org_linphone_core_LinphoneFriendImpl_isSubscribesEnabled(JNIEnv* env + ,jobject thiz + ,jlong ptr) { + return linphone_friend_subscribes_enabled((LinphoneFriend*)ptr); +} +extern "C" jboolean Java_org_linphone_core_LinphoneFriendImpl_getStatus(JNIEnv* env + ,jobject thiz + ,jlong ptr) { + return linphone_friend_get_status((LinphoneFriend*)ptr); +} +extern "C" void Java_org_linphone_core_LinphoneFriendImpl_edit(JNIEnv* env + ,jobject thiz + ,jlong ptr) { + return linphone_friend_edit((LinphoneFriend*)ptr); +} +extern "C" void Java_org_linphone_core_LinphoneFriendImpl_done(JNIEnv* env + ,jobject thiz + ,jlong ptr) { + linphone_friend_done((LinphoneFriend*)ptr); +} +//LinphoneChatRoom +extern "C" long Java_org_linphone_core_LinphoneChatRoomImpl_getPeerAddress(JNIEnv* env + ,jobject thiz + ,jlong ptr) { + return (long) linphone_chat_room_get_peer_address((LinphoneChatRoom*)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); + env->ReleaseStringUTFChars(jmessage, message); +} diff --git a/java/common/org/linphone/core/LinphoneAuthInfo.java b/java/common/org/linphone/core/LinphoneAuthInfo.java index 8ae3aeea5..f679307c5 100644 --- a/java/common/org/linphone/core/LinphoneAuthInfo.java +++ b/java/common/org/linphone/core/LinphoneAuthInfo.java @@ -17,13 +17,52 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ package org.linphone.core; - +/** + * Object holding authentication information. + * Note: + * The object's fields should not be accessed directly. Prefer using the accessor methods. + * In most case, authentication information consists of a username and password. Sometimes, a userid is required by proxy, and realm can be useful to discriminate different SIP domains. + *
+ *Once created and filled, a LinphoneAuthInfo must be added to the LinphoneCore in order to become known and used automatically when needed. + *Use {@link LinphoneCore#addAuthInfo(LinphoneAuthInfo)} for that purpose. + *
+ *The LinphoneCore object can take the initiative to request authentication information when needed to the application + *through the {@link LinphoneCoreListener#authInfoRequested(LinphoneCore, String, String)} listener. + *
+ *The application can respond to this information request later using {@link LinphoneCore#addAuthInfo(LinphoneAuthInfo)}. + *This will unblock all pending authentication transactions and retry them with authentication headers. + * + */ public interface LinphoneAuthInfo { + /** + * + * @return username + */ String getUsername(); - String getPassword(); - String getRealm(); + /** + * Sets the username. + * @param username + */ void setUsername(String username); + /** + * + * @return paasword + */ + String getPassword(); + /** + * sets password + * @param password + */ void setPassword(String password); + /** + * get realm + * @return + */ + String getRealm(); + /** + * set realm + * @param realm + */ void setRealm(String realm); } diff --git a/java/common/org/linphone/core/LinphoneChatRoom.java b/java/common/org/linphone/core/LinphoneChatRoom.java new file mode 100644 index 000000000..a8ef5e215 --- /dev/null +++ b/java/common/org/linphone/core/LinphoneChatRoom.java @@ -0,0 +1,39 @@ +/* +LinphoneChatRoom.java +Copyright (C) 2010 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +package org.linphone.core; +/** + * + * A chat room is the place where text messages are exchanged. +Can be created by linphone_core_create_chat_room(). + * + */ +public interface LinphoneChatRoom { + /** + * get peer address associated to this LinphoneChatRoom + * + * @return LinphoneAddress peer address + */ + LinphoneAddress getPeerAddress(); + /** + * send a message to peer member of this chat room. + * @param message to be sent + */ + void sendMessage(String message); + +} diff --git a/java/common/org/linphone/core/LinphoneCore.java b/java/common/org/linphone/core/LinphoneCore.java index c09ff9814..d74997d52 100644 --- a/java/common/org/linphone/core/LinphoneCore.java +++ b/java/common/org/linphone/core/LinphoneCore.java @@ -23,7 +23,7 @@ import java.util.Vector; public interface LinphoneCore { - /* + /** * linphone core states */ static public class GlobalState { @@ -255,5 +255,24 @@ public interface LinphoneCore { public void enableSpeaker(boolean value); public boolean isSpeakerEnabled(); + /** + * add a friend to the current buddy list, if subscription attribute is set, a SIP SUBSCRIBE message is sent. + * @param lf LinphoenFriend to add + * @throws LinphoneCoreException + */ + void addFriend(LinphoneFriend lf) throws LinphoneCoreException; + /** + * Set my presence status + * @param minute_away how long in away + * @param status sip uri used to redirect call in state LinphoneStatusMoved + */ + void setPresenceInfo(int minute_away,String alternative_contact, OnlineStatus status); + /** + * Create a new chat room for messaging from a sip uri like sip:joe@sip.linphone.org + * @param to destination address for messages + * + * @return {@link LinphoneChatRoom} where messaging can take place. + */ + LinphoneChatRoom createChatRoom(String to); } diff --git a/java/common/org/linphone/core/LinphoneCoreFactory.java b/java/common/org/linphone/core/LinphoneCoreFactory.java index b3e2952fb..c0d09b0a6 100644 --- a/java/common/org/linphone/core/LinphoneCoreFactory.java +++ b/java/common/org/linphone/core/LinphoneCoreFactory.java @@ -62,4 +62,17 @@ abstract public class LinphoneCoreFactory { abstract public void setDebugMode(boolean enable); abstract public void setLogHandler(LinphoneLogHandler handler); + /** + * Create a LinphoneFriend, similar to {@link #createLinphoneFriend()} + {@link LinphoneFriend#setAddress(LinphoneAddress)} + * @param friendUri a buddy address, must be a sip uri like sip:joe@sip.linphone.org + * @return a new LinphoneFriend with address initialized + */ + abstract LinphoneFriend createLinphoneFriend(String friendUri); + /** + * Create a new LinphoneFriend + * @return + */ + abstract LinphoneFriend createLinphoneFriend(); + + } diff --git a/java/common/org/linphone/core/LinphoneCoreListener.java b/java/common/org/linphone/core/LinphoneCoreListener.java index c37e5d7c7..6cb038cdd 100644 --- a/java/common/org/linphone/core/LinphoneCoreListener.java +++ b/java/common/org/linphone/core/LinphoneCoreListener.java @@ -55,5 +55,28 @@ public interface LinphoneCoreListener { * Registration state notification * */ public void registrationState(LinphoneCore lc, LinphoneProxyConfig cfg, LinphoneCore.RegistrationState cstate, String smessage); + /** + * Reports that a new subscription request has been received and wait for a decision. + *Status on this subscription request is notified by changing policy for this friend + *@param lc LinphoneCore + *@param lf LinphoneFriend corresponding to the subscriber + *@param url of the subscriber + * + */ + public void newSubscriptionRequest(LinphoneCore lc, LinphoneFriend lf, String url); + /** + * Report status change for a friend previously added to LinphoneCore. + * @param lc LinphoneCore + * @param lf updated LinphoneFriend + */ + public void notifyPresenceReceived(LinphoneCore lc, LinphoneFriend lf); + /** + * invoked when a new text 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 message + */ + public void textReceived(LinphoneCore lc, LinphoneChatRoom cr,LinphoneAddress from,String message); } diff --git a/java/common/org/linphone/core/LinphoneFriend.java b/java/common/org/linphone/core/LinphoneFriend.java new file mode 100644 index 000000000..f9ba9b758 --- /dev/null +++ b/java/common/org/linphone/core/LinphoneFriend.java @@ -0,0 +1,122 @@ +/* +LinphoneFriend.java +Copyright (C) 2010 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +package org.linphone.core; + +import java.util.Vector; + + + +/** + * Represents a buddy, all presence actions like subscription and status change notification are performed on this object + * + * + */ +public interface LinphoneFriend { + /** + * Enum controlling behavior for incoming subscription request. + * Use by {@link LinphoneFriend#setIncSubscribePolicy()} + * + */ + static class SubscribePolicy { + static private Vector values = new Vector(); + protected final int mValue; + private final String mStringValue; + /** + * Does not automatically accept an incoming subscription request. + * This policy implies that a decision has to be taken for each incoming subscription request notified by {@link LinphoneCoreListener#newSubscriptionRequest(LinphoneCore, LinphoneFriend, String)} + */ + public final static SubscribePolicy SPWait = new SubscribePolicy(0,"SPWait"); + /** + * Rejects incoming subscription request. + */ + public final static SubscribePolicy SPDeny = new SubscribePolicy(1,"SPDeny"); + /** + * Automatically accepts a subscription request. + */ + public final static SubscribePolicy SPAccept = new SubscribePolicy(2,"SPAccept"); + private SubscribePolicy(int value,String stringValue) { + mValue = value; + values.addElement(this); + mStringValue=stringValue; + } + public static SubscribePolicy fromInt(int value) { + + for (int i=0; i Because friend configuration must be consistent, applications MUST call {@link #edit()} before doing any attempts to modify friend configuration (such as address or subscription policy and so on). + *Once the modifications are done, then the application must call {@link #done()} to commit the changes. + */ + void edit(); + /** + * Commits modification made to the friend configuration. + */ + void done(); + /** + * Human readable representation of this friend + * @return + */ + String toString(); + + +} diff --git a/java/common/org/linphone/core/LinphoneProxyConfig.java b/java/common/org/linphone/core/LinphoneProxyConfig.java index 236bded39..729fd249d 100644 --- a/java/common/org/linphone/core/LinphoneProxyConfig.java +++ b/java/common/org/linphone/core/LinphoneProxyConfig.java @@ -17,34 +17,62 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ package org.linphone.core; - +/** + * The LinphoneProxyConfig object represents a proxy configuration to be used by the LinphoneCore object. Its fields must not be used directly in favour of the accessors methods. + * Once created and filled properly the LinphoneProxyConfig can be given to LinphoneCore with {@link LinphoneCore#addProxyConfig(LinphoneProxyConfig)}. This will automatically triggers the registration, if enabled. + *
The proxy configuration are persistent to restarts because they are saved in the configuration file. As a consequence, after {@link LinphoneCoreFactory#createLinphoneCore(LinphoneCoreListener, String, String, Object)} there might already be a default proxy that can be examined with {@link LinphoneCore#getDefaultProxyConfig()} . + * + */ public interface LinphoneProxyConfig { /** - * Unregister proxy config a enable edition + *Starts editing a proxy configuration. + *Because proxy configuration must be consistent, applications MUST call {@link #edit()} before doing any attempts to modify proxy configuration (such as identity, proxy address and so on). + *Once the modifications are done, then the application must call {@link #done()} to commit the changes. */ public void edit(); /** - * Validate proxy config changes. Start registration in case + * Commits modification made to the proxy configuration. */ public void done(); /** - * sip user made by sip:username@domain + * Sets the user identity as a SIP address. + * @param identy This identity is normally formed with display name, username and domain, such as: Alice The REGISTER messages will have from and to set to this identity. */ public void setIdentity(String identity) throws LinphoneCoreException; /** - * Set proxy uri, like sip:linphone.org:5060 + *get the SIP identity that belongs to this proxy configuration. + * + * @return The SIP identity is a SIP address (Display Name ) + */ + public String getIdentity(); + /** + *Sets the proxy address + * Examples of valid sip proxy address are: + *
  • IP address: sip:87.98.157.38 + *
  • IP address with port: sip:87.98.157.38:5062 + *
  • hostnames : sip:sip.example.net * @param proxyUri * @throws LinphoneCoreException */ public void setProxy(String proxyUri) throws LinphoneCoreException; + /** + * get the proxy's SIP address. + * + */ + public String getProxy(); /** * Enable register for this proxy config. * Register message is issued after call to {@link #done()} * @param value * @throws LinphoneCoreException - */ + */ public void enableRegister(boolean value) throws LinphoneCoreException; + /** + * @return true if registration to the proxy is enabled. + */ + public boolean registerEnabled(); + /** * normalize a human readable phone number into a basic string. 888-444-222 becomes 888444222 * @param number @@ -52,7 +80,7 @@ public interface LinphoneProxyConfig { */ public String normalizePhoneNumber(String number); /** - * usefull function to automatically add internationnal prefix to e164 phone numbers + * Useful function to automatically add international prefix to e164 phone numbers * @param prefix */ public void setDialPrefix(String prefix); @@ -64,15 +92,25 @@ public interface LinphoneProxyConfig { public void setDialEscapePlus(boolean value); /** - * rget domain host name or ip + * get domain host name or ip * @return may be null */ public String getDomain(); - public String getIdentity(); - public String getProxy(); - public boolean registerEnabled(); + /** + * + * @return a boolean indicating that the user is successfully registered on the proxy. + */ public boolean isRegistered(); + /** + * Sets a SIP route. When a route is set, all outgoing calls will go to the route's destination if this proxy is the default one (see {@link LinphoneCore#getDefaultProxyConfig()} ). + * @param routeUri ex sip:git.linphone.org + * @throws LinphoneCoreException + */ public void setRoute(String routeUri) throws LinphoneCoreException; + /** + * + * @return the route set for this proxy configuration. + */ public String getRoute(); } diff --git a/java/common/org/linphone/core/OnlineStatus.java b/java/common/org/linphone/core/OnlineStatus.java new file mode 100644 index 000000000..36aca1909 --- /dev/null +++ b/java/common/org/linphone/core/OnlineStatus.java @@ -0,0 +1,96 @@ +/* +OnlineStatus.java +Copyright (C) 2010 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +package org.linphone.core; + +import java.util.Vector; + + +/** + * Enum describing remote friend status + * + */ +public class OnlineStatus { + + static private Vector values = new Vector(); + /** + * Offline + */ + static public OnlineStatus Offline = new OnlineStatus(0,"Offline"); + /** + * Online + */ + static public OnlineStatus Online = new OnlineStatus(1,"Online"); + /** + * Busy + */ + static public OnlineStatus Busy = new OnlineStatus(2,"Busy"); + /** + * Be Right Back + */ + static public OnlineStatus BeRightBack = new OnlineStatus(3,"BeRightBack"); + /** + * Away + */ + static public OnlineStatus Away = new OnlineStatus(4,"Away"); + /** + * On The Phone + */ + static public OnlineStatus OnThePhone = new OnlineStatus(5,"OnThePhone"); + /** + * Out To Lunch + */ + static public OnlineStatus OutToLunch = new OnlineStatus(6,"OutToLunch "); + /** + * Do Not Disturb + */ + static public OnlineStatus DoNotDisturb = new OnlineStatus(7,"DoNotDisturb"); + /** + * Moved in this sate, call can be redirected if an alternate contact address has been set using function {@link LinphoneCore#setPresenceInfo(int, String, OnlineStatus)} + */ + static public OnlineStatus StatusMoved = new OnlineStatus(8,"StatusMoved"); + /** + * Using another messaging service + */ + static public OnlineStatus StatusAltService = new OnlineStatus(9,"StatusAltService"); + /** + * Pending + */ + static public OnlineStatus Pending = new OnlineStatus(10,"Pending"); + + protected final int mValue; + private final String mStringValue; + + private OnlineStatus(int value,String stringValue) { + mValue = value; + values.addElement(this); + mStringValue=stringValue; + } + public static OnlineStatus fromInt(int value) { + + for (int i=0; i + + + + + + +Liblinphone is a high level library for bringing SIP video call functionnality into an application. It aims at making easy the integration of the SIP video calls into any applications. All variants of linphone are directly based on it: + +
  • linphone (GUI interface) +
  • linphonec (console interface) +
    Liblinphone is GPL (see COPYING file). Please understand the licencing details before using it! + +
    For any use of this library beyond the rights granted to you by the GPL license, please contact Belledonne Communications (contact@belledonne-communications.com) + + + + +

    Package Specification

    + +LibLinphone package is organized in submodules. + + + + +

    Related Documentation

    + +For overviews, tutorials, examples, guides, and tool documentation, please see: + + + +

    +Managing proxies +

    +User registration is controled by {@link org.linphone.core.LinphoneProxyConfig } settings. +
    Each {@link org.linphone.core.LinphoneProxyConfig } object can be configured with registration informations +like {@link org.linphone.core.LinphoneProxyConfig#setProxy proxy address } , {@link org.linphone.core.LinphoneProxyConfig#setIdentity user id}, and so on. +
    A created proxy config using {@link org.linphone.core.LinphoneCoreFactory#createProxyConfig }, once configured, must be added to {@link org.linphone.core.LinphoneCore} using function {@link org.linphone.core.LinphoneCore#addProxyConfig }. +
    It is recommended to set a default {@link org.linphone.core.LinphoneProxyConfig proxy config } using function {@link org.linphone.core.LinphoneCore#setDefaultProxyConfig }. Once done, if {@link org.linphone.core.LinphoneProxyConfig a proxy config } has been configured with attribute {@link org.linphone.core.LinphoneProxyConfig#enableRegister enable register } , next call to {@link org.linphone.core.LinphoneCore#iterate } triggers a SIP register. +
    Registration status is reported by {@link org.linphone.core.LinphoneCoreListener#registrationState registration listener}. +
    +
    This pseudo code demonstrates basic registration operations: +
    +
    +
    +	
    +	LinphoneProxyConfig proxy_cfg;
    +	/*create proxy config*/
    +	proxy_cfg = LinphoneCoreFactory.instance().createProxyConfig();
    +	/*parse identity*/
    +	LinphoneAddress from = LinphoneCoreFactory.instance().createAddress("sip:toto@sip.titi.com");
    +	LinphoneAuthInfo info;
    +	if (password!=NULL){
    + 		info=LinphoneCoreFactory.instance().createAuthInfo(from.getUsername(),null,"secret",null,null); /*create authentication structure from identity*/
    +		lc.addAuthInfo(info); /*add authentication info to LinphoneCore*/
    +	}	
    +	// configure proxy entries
    +	proxy_cfg.setIdenty(identity); /*set identity with user name and domain*/
    +	String server_addr = from.getDomain(); /*extract domain address from identity*/
    +	proxy_cfg.setProxy(server_addr); /* we assume domain = proxy server address*/
    +	proxy_cfg.enableRegister(true); /*activate registration for this proxy config*/
    +	
    +	lc.addProxyConfig(proxy_cfg); /*add proxy config to linphone core*/
    +	lc.setDefaultProxyconfig(proxy_cfg); /*set to default proxy*/ 
    +
    +
    +
    + {@link org.linphone.core.LinphoneCoreListener#registrationState Registration state listener} : +
    +
    + void registrationState(LinphoneCore lc, LinphoneProxyConfig cfg, LinphoneCore.RegistrationState cstate, String message){
    +		System.out.println(New registration state ["+cstate+"] for user id ["+cfg.getUserName()+"] at proxy ["+cfg.getProxy()+"]";
    +}
    +
    + + +
    Authentication: +
    Most of the time, registration requires {@link org.linphone.core.LinphoneAuthInfo authentication } to succed. {@link org.linphone.core.LinphoneAuthInfo} info must be either added to {@link org.linphone.core.LinphoneCore } using method {@link org.linphone.core.LinphoneCore#addAuthInfo } before {@link org.linphone.core.LinphoneProxyConfig} is added to Linphone core, or on demand from listener {@link org.linphone.core.LinphoneCoreListener#authInfoRequested(LinphoneCore, String, String)} . +
    +
    Unregistration: +
    Unregistration or any changes to {@link org.linphone.core.LinphoneProxyConfig} must be first started by a call to function {@link org.linphone.core.LinphoneProxyConfig#edit } and validated by function {@link org.linphone.core.LinphoneProxyConfig#done } +
    This pseudo code shows how to unregister a user associated to a{@link org.linphone.core.LinphoneProxyConfig} +
    +
    + 	LinphoneProxyConfig proxy_cfg;
    + 	lc.setDefaultProxyConfig(proxy_cfg); /* get default proxy config*/
    +	proxy_cfg.edit(); /*start editing proxy configuration*/
    +	proxy_cfg.enableRegister(false); /*de-activate registration for this proxy config*/
    +	proxy_cfg.done(); /*initiate REGISTER with expire = 0*/
    +
    + +
    +
    +

    +Managing Buddies and buddy list and presence +

    +
    +Buddies and buddy list +
    Each buddy is represented by a {@link org.linphone.core.LinphoneFriend } object created by function {@link org.linphone.core.LinphoneCoreFactory#createLinphoneFriend()}. +Buddy configuration parameters like {@link org.linphone.core.LinphoneFriend#setAddress(LinphoneAddress) sip uri} or {@link org.linphone.core.LinphoneFriend#setIncSubscribePolicy(LinphoneFriend.SubscribePolicy) status publication} are configurable for each buddy. +
    Here under a typical buddy creation: +
    +
    +
    +	LinphoneFriend my_friend=LinphoneFactory.instance().createFriend("sip:joe@sip.linphone.org"); /*creates friend object for buddy joe*/
    +	my_friend.enableSubscribes(true); /*configure this friend to emit SUBSCRIBE message after being added to LinphoneCore*/
    +	my_friend.setIncSubscribePolicy(LinphoneFriend.SubscribePolicy.Accept); /* accept Incoming subscription request for this friend*/
    +
    +
    +{@link LinphoneFriend friends } status changes are reported by {@link org.linphone.core.LinphoneCoreListener#notifyPresenceReceived(LinphoneCore lc, LinphoneFriend lf)} . +
    +
    + void notifyPresenceReceived(LinphoneCore lc, LinphoneFriend lf){
    +	LinphoneAddress friend_address = lf.getAddress();
    +	System.out.println("New state ["+lf.getStatus()+"] for user id ["+friend_address+"] ");
    +}
    +
    +
    + +
    Once created a buddy can be added to the buddy list using function {@link org.linphone.core.LinphoneCore#addFriend(LinphoneFriend lf) } . Added friends will be notified about {@link org.linphone.core.LinphoneCore#setPresenceInfo(int minute_away,String alternative_contact, OnlineStatus status) local status changes } +
    +Any subsequente modifications to {@link org.linphone.core.LinphoneFriend} must be first started by a call to function to {@link org.linphone.core.LinphoneFriend#edit()} and validated by function {@link org.linphone.core.LinphoneFriend#done()} +
    +
    +	my_friend.edit(); /* start editing friend */
    +	my_friend.enableSubscribes(true); /*disable subscription for this friend*/
    +	my_friend.done(); /*commit changes triggering an UNSUBSCRIBE message*/
    +
    +
    + + Publishing presence status +
    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. +
    +
    +Handling incoming subscription request +
    New incoming subscription requests are process according to{@link org.linphone.core.LinphoneFriend#setIncSubscribePolicy(LinphoneFriend.SubscribePolicy) the incoming subscription policy state} for subscription initiated by {@link org.linphone.core.LinphoneCore#addFriend(LinphoneFriend lf) members of the buddy list. } +
    For incoming request coming from an unknown buddy, the call back {@link org.linphone.core.LinphoneCoreListener#newSubscriptionRequest(LinphoneCore lc, LinphoneFriend lf, String url)} + +

    +Chat room and Messaging +

    + Exchanging text messages +
    Messages are sent using {@link org.linphone.core.LinphoneChatRoom} object. First step is to create a {@link org.linphone.core.LinphoneCore#createChatRoom chat room } +from a peer sip uri. +
    +
    +	LinphoneChatRoom chat_room = lc.createChatRoom("sip:joe@sip.linphone.org");
    +
    + +
    Once created, messages are sent using function {@link org.linphone.core.LinphoneChatRoom#sendMessage } . +
    +
    +	chat_room.sendMessage("Hello world"); /*sending message*/
    +
    + +
    Incoming message are received from {@link org.linphone.core.LinphoneCoreListener#textReceived a listener } +
    +
    +	void textReceived(LinphoneCore lc, LinphoneChatRoom cr,LinphoneAddress from,String message) {
    +		System.out.println("Message ["+message+"] received from ["+from+"] ");
    +	}
    +
    +
    +
    +
    \ No newline at end of file
    
    From 47278cc2179939f8881eecaa3a2a695cb4f396a7 Mon Sep 17 00:00:00 2001
    From: Jehan Monnier 
    Date: Fri, 22 Oct 2010 18:32:44 +0200
    Subject: [PATCH 08/27] fix compilation issue in java binding
    
    ---
     coreapi/linphonecore_jni.cc | 8 ++++----
     1 file changed, 4 insertions(+), 4 deletions(-)
    
    diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc
    index 1ba35d6e6..972f31b7b 100644
    --- a/coreapi/linphonecore_jni.cc
    +++ b/coreapi/linphonecore_jni.cc
    @@ -470,7 +470,7 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setPresenceInfo(JNIEnv*
     																			,jstring jalternative_contact
     																			,jint status) {
     	const char* alternative_contact = env->GetStringUTFChars(jalternative_contact, NULL);
    -	linphone_core_set_presence_info((LinphoneCore*)lc,minute_away,alternative_contact,status);
    +	linphone_core_set_presence_info((LinphoneCore*)lc,minute_away,alternative_contact,(LinphoneOnlineStatus)status);
     	env->ReleaseStringUTFChars(jalternative_contact, alternative_contact);
     }
     
    @@ -787,9 +787,9 @@ extern "C" void Java_org_linphone_core_LinphoneFriendImpl_setAddress(JNIEnv*  en
     																		,jobject  thiz
     																		,jlong ptr
     																		,jlong linphoneAddress) {
    -	linphone_friend_set_address((LinphoneFriend*)ptr,(LinphoneAddress*)linphoneAddress);
    +	linphone_friend_set_addr((LinphoneFriend*)ptr,(LinphoneAddress*)linphoneAddress);
     }
    -extern "C" long Java_org_linphone_core_LinphoneFriendImpl_setAddress(JNIEnv*  env
    +extern "C" long Java_org_linphone_core_LinphoneFriendImpl_getAddress(JNIEnv*  env
     																		,jobject  thiz
     																		,jlong ptr) {
     	return (long)linphone_friend_get_address((LinphoneFriend*)ptr);
    @@ -798,7 +798,7 @@ extern "C" void Java_org_linphone_core_LinphoneFriendImpl_setIncSubscribePolicy(
     																		,jobject  thiz
     																		,jlong ptr
     																		,jint policy) {
    -	linphone_friend_set_inc_subscribe_policy((LinphoneFriend*)ptr,policy);
    +	linphone_friend_set_inc_subscribe_policy((LinphoneFriend*)ptr,(LinphoneSubscribePolicy)policy);
     }
     extern "C" jint Java_org_linphone_core_LinphoneFriendImpl_getIncSubscribePolicy(JNIEnv*  env
     																		,jobject  thiz
    
    From b4797f35e7732e13896045e36af9b1e07425126b Mon Sep 17 00:00:00 2001
    From: Simon Morlat 
    Date: Mon, 25 Oct 2010 10:22:58 +0200
    Subject: [PATCH 09/27] merge presence improvement patch
    
    ---
     coreapi/help/buddy_status.c    |   4 +-
     coreapi/sal_eXosip2_presence.c | 664 ++++++++++++++++-----------------
     2 files changed, 333 insertions(+), 335 deletions(-)
    
    diff --git a/coreapi/help/buddy_status.c b/coreapi/help/buddy_status.c
    index 7ee06a8f5..1032cf17b 100644
    --- a/coreapi/help/buddy_status.c
    +++ b/coreapi/help/buddy_status.c
    @@ -46,13 +46,13 @@ static void stop(int signum){
     /**
      * presence state change notification callback
      */
    -static void notify_presence_recv_updated (struct _LinphoneCore *lc,  LinphoneFriend *friend) {
    +static void notify_presence_recv_updated (LinphoneCore *lc,  LinphoneFriend *friend) {
     	const LinphoneAddress* friend_address = linphone_friend_get_address(friend);
     	printf("New state state [%s] for user id [%s] \n"
     				,linphone_online_status_to_string(linphone_friend_get_status(friend))
     				,linphone_address_as_string (friend_address));
     }
    -static void new_subscription_request (struct _LinphoneCore *lc,  LinphoneFriend *friend, const char* url) {
    +static void new_subscription_request (LinphoneCore *lc,  LinphoneFriend *friend, const char* url) {
     	const LinphoneAddress* friend_address = linphone_friend_get_address(friend);
     	printf(" [%s] wants to see your status, accepting\n"
     				,linphone_address_as_string (friend_address));
    diff --git a/coreapi/sal_eXosip2_presence.c b/coreapi/sal_eXosip2_presence.c
    index 675a45117..154c8d07e 100644
    --- a/coreapi/sal_eXosip2_presence.c
    +++ b/coreapi/sal_eXosip2_presence.c
    @@ -20,6 +20,17 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
     
     #include "sal_eXosip2.h"
     
    +typedef enum {
    +	PIDF = 0,
    +	RFCxxxx = 1,
    +	MSOLDPRES = 2
    +} presence_type_t;
    +
    +/*
    + * REVISIT: this static variable forces every dialog to use the same presence description type depending 
    + * on what is received on a single dialog...
    + */
    +static presence_type_t presence_style = PIDF;
     
     SalOp * sal_find_out_subscribe(Sal *sal, int sid){
     	const MSList *elem;
    @@ -175,268 +186,372 @@ int sal_subscribe_decline(SalOp *op){
     	return 0;
     }
     
    -static void add_presence_body(osip_message_t *notify, SalPresenceStatus online_status)
    -{
    -	char buf[1000];
    -#ifdef SUPPORT_MSN
    -	int atom_id = 1000;
    -#endif
    -	char *contact_info;
    +static void mk_presence_body (const SalPresenceStatus online_status, const char *contact_info,
    +		char *buf, size_t buflen, presence_type_t ptype) {
    +  switch (ptype) {
    +    case RFCxxxx: {
    +	  /* definition from http://msdn.microsoft.com/en-us/library/cc246202%28PROT.10%29.aspx */
    +	  int atom_id = 1000;
     
    -	osip_from_t *from=NULL;
    -	from=osip_message_get_from(notify);
    -	osip_uri_to_str(from->url,&contact_info);
    -
    -#ifdef SUPPORT_MSN
    -
    -  if (online_status==SalPresenceOnline)
    -    {
    -      sprintf(buf, "\n\
    -\n\
    +	  if (online_status==SalPresenceOnline)
    +	  {
    +		  snprintf(buf, buflen, "\n\
    +\n\
     \n\
     \n\
     \n\
    -
    \n\ +
    \n\ \n\ \n\
    \n\ \n\ ", contact_info, atom_id, contact_info); - } - else if (online_status==SalPresenceBusy) - { - sprintf(buf, "\n\ -\n\ + } + else if (online_status == SalPresenceBusy || + online_status == SalPresenceDonotdisturb) + { + snprintf(buf, buflen, "\n\ +\n\ \n\ \n\ \n\ -
    \n\ +
    \n\ \n\ \n\
    \n\ -\n\ -", contact_info, atom_id, contact_info); +\n", contact_info, atom_id, contact_info); - } - else if (online_status==SalPresenceBerightback) - { - sprintf(buf, "\n\ -\n\ + } + else if (online_status==SalPresenceBerightback) + { + snprintf(buf, buflen, "\n\ +\n\ \n\ \n\ \n\ -
    \n\ -\n\ +
    \n\ +\n\ \n\
    \n\ \n\ ", contact_info, atom_id, contact_info); - } - else if (online_status==SalPresenceAway) - { - sprintf(buf, "\n\ -\n\ + } + else if (online_status == SalPresenceAway || + online_status == SalPresenceMoved) + { + snprintf(buf, buflen, "\n\ +\n\ \n\ \n\ \n\ -
    \n\ -\n\ +
    \n\ +\n\ \n\
    \n\ \n\ ", contact_info, atom_id, contact_info); - } - else if (online_status==SalPresenceOnthephone) - { - sprintf(buf, "\n\ -\n\ + } + else if (online_status==SalPresenceOnthephone) + { + snprintf(buf, buflen, "\n\ +\n\ \n\ \n\ \n\ -
    \n\ +
    \n\ \n\ \n\
    \n\ \n\ ", contact_info, atom_id, contact_info); - } - else if (online_status==SalPresenceOuttolunch) - { - sprintf(buf, "\n\ -\n\ + } + else if (online_status==SalPresenceOuttolunch) + { + snprintf(buf, buflen, "\n\ +\n\ \n\ \n\ \n\ -
    \n\ +
    \n\ +\n\ +\n\ +
    \n\ +\n\ +", contact_info, atom_id, contact_info); + + } + else + { + snprintf(buf, buflen, "\n\ +\n\ +\n\ +\n\ +\n\ +
    \n\ +\n\ +\n\ +
    \n\ +
    \n\ +
    ", contact_info, atom_id, contact_info); + } + break; + } + case MSOLDPRES: { + /* Couldn't find schema http://schemas.microsoft.com/2002/09/sip/presence + * so messages format has been taken from Communigate that can send notify + * requests with this schema + */ + int atom_id = 1000; + + if (online_status==SalPresenceOnline) + { + snprintf(buf, buflen, "\n\ +\n\ +\n\ +\n\ +\n\ +
    \n\ +\n\ +\n\ +
    \n\ +
    \n\ +
    ", contact_info, atom_id, contact_info); + + } + else if (online_status == SalPresenceBusy || + online_status == SalPresenceDonotdisturb) + { + snprintf(buf, buflen, "\n\ +\n\ +\n\ +\n\ +\n\ +
    \n\ +\n\ +\n\ +
    \n\ +
    \n
    ", contact_info, atom_id, contact_info); + + } + else if (online_status==SalPresenceBerightback) + { + snprintf(buf, buflen, "\n\ +\n\ +\n\ +\n\ +\n\ +
    \n\ +\n\ +\n\ +
    \n\ +
    \n\ +
    ", contact_info, atom_id, contact_info); + + } + else if (online_status == SalPresenceAway || + online_status == SalPresenceMoved) + { + snprintf(buf, buflen, "\n\ +\n\ +\n\ +\n\ +\n\ +
    \n\ +\n\ +\n\ +
    \n\ +
    \n\ +
    ", contact_info, atom_id, contact_info); + + } + else if (online_status==SalPresenceOnthephone) + { + snprintf(buf, buflen, "\n\ +\n\ +\n\ +\n\ +\n\ +
    \n\ +\n\ +\n\ +
    \n\ +
    \n\ +
    ", contact_info, atom_id, contact_info); + + } + else if (online_status==SalPresenceOuttolunch) + { + snprintf(buf, buflen, "\n\ +\n\ +\n\ +\n\ +\n\ +
    \n\ \n\ \n\
    \n\
    \n\
    ", contact_info, atom_id, contact_info); - } - else - { - sprintf(buf, "\n\ -\n\ + } + else + { + snprintf(buf, buflen, "\n\ +\n\ \n\ \n\ \n\ -
    \n\ -\n\ -\n\ +
    \n\ +\n\ +\n\
    \n\ \n\ ", contact_info, atom_id, contact_info); - } + } + break; + } + default: { /* use pidf+xml as default format, rfc4479, rfc4480, rfc3863 */ - osip_message_set_body(notify, buf, strlen(buf)); - osip_message_set_content_type(notify, "application/xpidf+xml"); -#else + if (online_status==SalPresenceOnline) + { + snprintf(buf, buflen, "\n\ +\n\ +\n\ +open\n\ +%s\n\ +\n\ +", +contact_info, contact_info); + } + else if (online_status == SalPresenceBusy || + online_status == SalPresenceDonotdisturb) + { + snprintf(buf, buflen, "\n\ +\n\ +\n\ +open\n\ +%s\n\ +\n\ +\n\ +\n\ +\n\ +", +contact_info, contact_info); + } + else if (online_status==SalPresenceBerightback) + { + snprintf(buf, buflen, "\n\ +\n\ +\n\ +open\n\ +%s\n\ +\n\ +\n\ +\n\ +\n\ +", +contact_info, contact_info); + } + else if (online_status == SalPresenceAway || + online_status == SalPresenceMoved) + { + snprintf(buf, buflen, "\n\ +\n\ +\n\ +open\n\ +%s\n\ +\n\ +\n\ +\n\ +\n\ +", +contact_info, contact_info); + } + else if (online_status==SalPresenceOnthephone) + { + snprintf(buf, buflen, "\n\ +\n\ +\n\ +open\n\ +%s\n\ +\n\ +\n\ +\n\ +\n\ +", +contact_info, contact_info); + } + else if (online_status==SalPresenceOuttolunch) + { + snprintf(buf, buflen, "\n\ +\n\ +\n\ +open\n\ +%s\n\ +\n\ +\n\ +\n\ +Out to lunch \n\ +\n\ +", +contact_info, contact_info); + } + else + { + snprintf(buf, buflen, "\n\ +\n\ +\n\ +closed\n\ +%s\n\ +\n\ +\n", contact_info, contact_info); + } + break; + } + } // switch - if (online_status==SalPresenceOnline) - { - sprintf(buf, "\n\ -\n\ -\n\ -\n\ -open\n\ -\n\ -%s\n\ -online\n\ -\n\ -", - contact_info, contact_info); - } - else if (online_status==SalPresenceBusy) - { - sprintf(buf, "\n\ -\n\ -\n\ -\n\ -open\n\ -\n\ - busy\n\ -\n\ -\n\ -%s\n\ -busy\n\ -\n\ -", - contact_info, contact_info); - } - else if (online_status==SalPresenceBerightback) - { - sprintf(buf, "\n\ -\n\ -\n\ -\n\ -open\n\ -\n\ - in-transit\n\ -\n\ -\n\ -%s\n\ -be right back\n\ -\n\ -", - contact_info, contact_info); - } - else if (online_status==SalPresenceAway) - { - sprintf(buf, "\n\ -\n\ -\n\ -\n\ -open\n\ -\n\ - away\n\ -\n\ -\n\ -%s\n\ -away\n\ -\n\ -", - contact_info, contact_info); - } - else if (online_status==SalPresenceOnthephone) - { - sprintf(buf, "\n\ -\n\ -\n\ -\n\ -open\n\ -\n\ - on-the-phone\n\ -\n\ -\n\ -%s\n\ -on the phone\n\ -\n\ -", - contact_info, contact_info); - } - else if (online_status==SalPresenceOuttolunch) - { - sprintf(buf, "\n\ -\n\ -\n\ -\n\ -open\n\ -\n\ - meal\n\ -\n\ -\n\ -%s\n\ -out to lunch\n\ -\n\ -", - contact_info, contact_info); - } - else - { - /* */ - sprintf(buf, "\n\ -\n%s", - contact_info, -"\n\ -\n\ -closed\n\ -\n\ - permanent-absence\n\ -\n\ -\n\ -\n\ -\n\n"); - } - osip_message_set_body(notify, buf, strlen(buf)); - osip_message_set_content_type(notify, "application/pidf+xml"); +} + +static void add_presence_body(osip_message_t *notify, SalPresenceStatus online_status) +{ + char buf[1000]; + char *contact_info; + + osip_from_t *from=NULL; + from=osip_message_get_from(notify); + osip_uri_to_str(from->url,&contact_info); + + mk_presence_body (online_status, contact_info, buf, sizeof (buf), presence_style); + + osip_message_set_body(notify, buf, strlen(buf)); + osip_message_set_content_type(notify, + presence_style ? "application/xpidf+xml" : "application/pidf+xml"); -#endif osip_free(contact_info); } @@ -483,137 +598,10 @@ int sal_publish(SalOp *op, const char *from, const char *to, SalPresenceStatus p int i; char buf[1024]; - if (presence_mode==SalPresenceOnline) - { - snprintf(buf, sizeof(buf), "\n\ - \n\ - \n\ - \n\ - open\n\ - \n\ - %s\n\ - online\n\ - \n\ - ", - from, from); - } - else if (presence_mode==SalPresenceBusy - ||presence_mode==SalPresenceDonotdisturb) - { - snprintf(buf, sizeof(buf), "\n\ - \n\ - \n\ - \n\ - open\n\ - \n\ - busy\n\ - \n\ - \n\ - %s\n\ - busy\n\ - \n\ - ", - from, from); - } - else if (presence_mode==SalPresenceBerightback) - { - snprintf(buf, sizeof(buf), "\n\ - \n\ - \n\ - \n\ - open\n\ - \n\ - in-transit\n\ - \n\ - \n\ - %s\n\ - be right back\n\ - \n\ - ", - from,from); - } - else if (presence_mode==SalPresenceAway - ||presence_mode==SalPresenceMoved) - { - snprintf(buf, sizeof(buf), "\n\ - \n\ - \n\ - \n\ - open\n\ - \n\ - away\n\ - \n\ - \n\ - %s\n\ - away\n\ - \n\ - ", - from, from); - } - else if (presence_mode==SalPresenceOnthephone) - { - snprintf(buf, sizeof(buf), "\n\ - \n\ - \n\ - \n\ - open\n\ - \n\ - on-the-phone\n\ - \n\ - \n\ - %s\n\ - on the phone\n\ - \n\ - ", - from, from); - } - else if (presence_mode==SalPresenceOuttolunch) - { - snprintf(buf, sizeof(buf), "\n\ - \n\ - \n\ - \n\ - open\n\ - \n\ - meal\n\ - \n\ - \n\ - %s\n\ - out to lunch\n\ - \n\ - ", - from, from); - } - else{ - /* offline */ - snprintf(buf, sizeof(buf), "\n\ - \n%s", - from, - "\n\ - \n\ - closed\n\ - \n\ - permanent-absence\n\ - \n\ - \n\ - \n\ - \n\n"); - } + mk_presence_body (presence_mode, from, buf, sizeof (buf), presence_style); - i = eXosip_build_publish(&pub,from, to, NULL, "presence", "1800", "application/pidf+xml", buf); + i = eXosip_build_publish(&pub,from, to, NULL, "presence", "300", + presence_style ? "application/xpidf+xml" : "application/pidf+xml", buf); if (i<0){ ms_warning("Failed to build publish request."); return -1; @@ -699,7 +687,8 @@ void sal_exosip_notify_recv(Sal *sal, eXosip_event_t *ev){ }else if (strstr(body->body,"berightback")!=NULL || strstr(body->body,"in-transit")!=NULL ){ estatus=SalPresenceBerightback; - }else if (strstr(body->body,"away")!=NULL){ + }else if (strstr(body->body,"away")!=NULL + || strstr(body->body,"idle")){ estatus=SalPresenceAway; }else if (strstr(body->body,"onthephone")!=NULL || strstr(body->body,"on-the-phone")!=NULL){ @@ -722,6 +711,15 @@ void sal_exosip_notify_recv(Sal *sal, eXosip_event_t *ev){ ms_message("And outgoing subscription terminated by remote."); } sal->callbacks.notify_presence(op,op->sid!=-1 ? SalSubscribeActive : SalSubscribeTerminated, estatus,NULL); + + /* try to detect presence message style used by server, + * and switch our presence messages to servers style */ + if (strstr (body->body, "//IETF//DTD RFCxxxx XPIDF 1.0//EN") != NULL) { + presence_style = RFCxxxx; + } else if (strstr(body->body,"http://schemas.microsoft.com/2002/09/sip/presence")!=NULL) { + presence_style = MSOLDPRES; + } + osip_free(tmp); } From be38c75b70f027feefa1ddbe05670aa7b8e25573 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 25 Oct 2010 11:25:57 +0200 Subject: [PATCH 10/27] don't use ec when streaming from file --- coreapi/linphonecall.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 4ec373fd7..2cd8236f7 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -797,7 +797,7 @@ static void _linphone_call_start_media_streams(LinphoneCall *call, bool_t send_e recfile, playcard, captcard, - send_early_media ? FALSE : linphone_core_echo_cancellation_enabled(lc)); + captcard==NULL ? FALSE : linphone_core_echo_cancellation_enabled(lc)); post_configure_audio_streams(call); if (send_early_media) setup_ring_player(lc,call); audio_stream_set_rtcp_information(call->audiostream, cname, tool); From 7434d5250b64cf82643dd2a4be2fb8d22cba381a Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 25 Oct 2010 12:13:20 +0200 Subject: [PATCH 11/27] update version number --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 5f803f662..fd84dfb58 100644 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,6 @@ dnl Process this file with autoconf to produce a configure script. -AC_INIT([linphone],[3.3.99.7],[linphone-developers@nongnu.org]) +AC_INIT([linphone],[3.3.99.8],[linphone-developers@nongnu.org]) AC_CANONICAL_SYSTEM AC_CONFIG_SRCDIR([coreapi/linphonecore.c]) From 740dbb9041bea18490fcd9c7abb9dac670413a34 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 26 Oct 2010 11:11:02 +0200 Subject: [PATCH 12/27] implements reporting of declined calls --- coreapi/callbacks.c | 12 +++++----- coreapi/linphonecall.c | 12 +++++++++- coreapi/linphonecore.c | 22 ++++++++++++++----- coreapi/linphonecore.h | 50 ++++++++++++++++++++++-------------------- coreapi/misc.c | 16 ++++++++++++++ coreapi/private.h | 6 +++-- coreapi/proxy.c | 6 +++-- 7 files changed, 85 insertions(+), 39 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index cc49391d9..655a5547d 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -444,8 +444,10 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de } linphone_call_stop_media_streams (call); if (sr!=SalReasonDeclined) linphone_call_set_state(call,LinphoneCallError,msg); - else linphone_call_set_state(call,LinphoneCallEnd,"Call declined."); - + else{ + call->reason=LinphoneReasonDeclined; + linphone_call_set_state(call,LinphoneCallEnd,"Call declined."); + } } static void auth_requested(SalOp *h, const char *realm, const char *username){ @@ -485,7 +487,7 @@ static void register_success(SalOp *op, bool_t registered){ char *msg; cfg->registered=registered; - linphone_proxy_config_set_error(cfg,LinphoneErrorNone); + linphone_proxy_config_set_error(cfg,LinphoneReasonNone); linphone_proxy_config_set_state(cfg, registered ? LinphoneRegistrationOk : LinphoneRegistrationCleared , registered ? "Registration sucessful" : "Unregistration done"); if (lc->vtable.display_status){ @@ -514,9 +516,9 @@ static void register_failure(SalOp *op, SalError error, SalReason reason, const ms_free(msg); } if (error== SalErrorFailure && reason == SalReasonForbidden) { - linphone_proxy_config_set_error(cfg, LinphoneErrorBadCredentials); + linphone_proxy_config_set_error(cfg, LinphoneReasonBadCredentials); } else if (error == SalErrorNoResponse) { - linphone_proxy_config_set_error(cfg, LinphoneErrorNoResponse); + linphone_proxy_config_set_error(cfg, LinphoneReasonNoResponse); } linphone_proxy_config_set_state(cfg,LinphoneRegistrationFailed,details); } diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 2cd8236f7..ee2910e35 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -216,7 +216,10 @@ static void linphone_call_set_terminated(LinphoneCall *call){ linphone_core_update_allocated_audio_bandwidth(lc); if (call->state==LinphoneCallEnd){ - status=LinphoneCallSuccess; + if (call->reason==LinphoneReasonDeclined){ + status=LinphoneCallDeclined; + } + else status=LinphoneCallSuccess; } linphone_call_log_completed(call->log,call, status); @@ -384,6 +387,13 @@ LinphoneCallState linphone_call_get_state(const LinphoneCall *call){ return call->state; } +/** + * Returns the reason for a call termination (either error or normal termination) +**/ +LinphoneReason linphone_call_get_reason(const LinphoneCall *call){ + return call->reason; +} + /** * Get the user_pointer in the LinphoneCall * diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 438fdaa26..e6e8d99f2 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -946,6 +946,14 @@ static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vta linphone_core_assign_payload_type(&payload_type_ilbc,113,"mode=30"); linphone_core_assign_payload_type(&payload_type_amr,114,"octet-align=1"); +#if defined(ANDROID) || defined (__IPHONE_OS_VERSION_MIN_REQUIRED) + /*shorten the DNS lookup time and send more retransmissions on mobiles: + - to workaround potential packet losses + - to avoid hanging for 30 seconds when the network doesn't work despite the phone thinks it does. + */ + _linphone_core_configure_resolver(); +#endif + #ifdef ENABLE_NONSTANDARD_GSM { PayloadType *pt; @@ -2332,7 +2340,9 @@ int linphone_core_terminate_call(LinphoneCore *lc, LinphoneCall *the_call) call = the_call; } sal_call_terminate(call->op); - + if (call->state==LinphoneCallIncomingReceived){ + call->reason=LinphoneReasonDeclined; + } /*stop ringing*/ if (lc->ringstream!=NULL) { ring_stop(lc->ringstream); @@ -4011,14 +4021,16 @@ LinphoneCallParams *linphone_core_create_default_call_parameters(LinphoneCore *l return p; } -const char *linphone_error_to_string(LinphoneError err){ +const char *linphone_error_to_string(LinphoneReason err){ switch(err){ - case LinphoneErrorNone: + case LinphoneReasonNone: return "No error"; - case LinphoneErrorNoResponse: + case LinphoneReasonNoResponse: return "No response"; - case LinphoneErrorBadCredentials: + case LinphoneReasonBadCredentials: return "Bad credentials"; + case LinphoneReasonDeclined: + return "Call declined"; } return "unknown error"; } diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 313907ad9..012437f62 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -131,7 +131,8 @@ typedef enum _LinphoneCallDir LinphoneCallDir; typedef enum _LinphoneCallStatus { LinphoneCallSuccess, /**< The call was sucessful*/ LinphoneCallAborted, /**< The call was aborted */ - LinphoneCallMissed /**< The call was missed (unanswered)*/ + LinphoneCallMissed, /**< The call was missed (unanswered)*/ + LinphoneCallDeclined /**< The call was declined, either locally or by remote end*/ } LinphoneCallStatus; /** @@ -182,15 +183,16 @@ void linphone_call_params_destroy(LinphoneCallParams *cp); /** * Enum describing failure reasons. **/ -enum _LinphoneError{ - LinphoneErrorNone, - LinphoneErrorNoResponse, /** + +void _linphone_core_configure_resolver(){ + res_init(); + _res.retrans=1; /*retransmit every second*/ + _res.retry=2; /*only two times per DNS server*/ +} + +#else + +void _linphone_core_configure_resolver(){ +} + +#endif diff --git a/coreapi/private.h b/coreapi/private.h index 029405edd..969c337e9 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -77,6 +77,7 @@ struct _LinphoneCall time_t start_time; /*time at which the call was initiated*/ time_t media_start_time; /*time at which it was accepted, media streams established*/ LinphoneCallState state; + LinphoneReason reason; int refcnt; void * user_pointer; int audio_port; @@ -199,7 +200,7 @@ void linphone_core_stop_waiting(LinphoneCore *lc); int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call, LinphoneProxyConfig *dest_proxy); void linphone_core_start_refered_call(LinphoneCore *lc, LinphoneCall *call); extern SalCallbacks linphone_sal_callbacks; -void linphone_proxy_config_set_error(LinphoneProxyConfig *cfg,LinphoneError error); +void linphone_proxy_config_set_error(LinphoneProxyConfig *cfg, LinphoneReason error); struct _LinphoneProxyConfig { @@ -224,7 +225,7 @@ struct _LinphoneProxyConfig bool_t dial_escape_plus; void* user_data; time_t deletion_date; - LinphoneError error; + LinphoneReason error; }; struct _LinphoneAuthInfo @@ -439,6 +440,7 @@ SalMediaDescription *create_local_media_description(LinphoneCore *lc, LinphoneCall *call, bool_t with_video, bool_t only_one_codec); #define linphone_core_ready(lc) ((lc)->state!=LinphoneGlobalStartup) +void _linphone_core_configure_resolver(); #define HOLD_OFF (0) #define HOLD_ON (1) diff --git a/coreapi/proxy.c b/coreapi/proxy.c index aa901cb8d..b77ad9422 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -841,10 +841,12 @@ LinphoneRegistrationState linphone_proxy_config_get_state(const LinphoneProxyCon } return NULL; } -LinphoneError linphone_proxy_config_get_error(const LinphoneProxyConfig *cfg) { + +LinphoneReason linphone_proxy_config_get_error(const LinphoneProxyConfig *cfg) { return cfg->error; } -void linphone_proxy_config_set_error(LinphoneProxyConfig *cfg,LinphoneError error) { + +void linphone_proxy_config_set_error(LinphoneProxyConfig *cfg,LinphoneReason error) { cfg->error = error; } From 66007b74fb80c2721a9c85be4e9d08bb444f4bbe Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 26 Oct 2010 15:19:07 +0200 Subject: [PATCH 13/27] update ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index dcf3eba1a..21471e316 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit dcf3eba1afa5615cb01b52b1136d8aa0d224aca2 +Subproject commit 21471e316965e7ce61964b18793ec0cadbd37658 From 950ab0eb432aa9938ccedf78a1b2970d0b05ee81 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 28 Oct 2010 11:34:16 +0200 Subject: [PATCH 14/27] configure android resolver with what is accessible in bionic --- coreapi/misc.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/coreapi/misc.c b/coreapi/misc.c index 84ddac599..1dc3b7e70 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -779,10 +779,19 @@ int linphone_core_get_local_ip_for(int type, const char *dest, char *result){ #ifndef WIN32 #include + + + void _linphone_core_configure_resolver(){ +/*bionic declares _res but does not define nor export it !!*/ +#ifdef ANDROID + /*timeout and attempts are the same as retrans and retry, but are android specific names.*/ + setenv("RES_OPTIONS","timeout:1 attempts:2 retrans:1 retry:2",1); +#else res_init(); _res.retrans=1; /*retransmit every second*/ _res.retry=2; /*only two times per DNS server*/ +#endif } #else From 2245cfb429a9182563430a68315907791cd2b45b Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 28 Oct 2010 16:31:35 +0200 Subject: [PATCH 15/27] enable auto-acceptance of "replacing" calls --- coreapi/callbacks.c | 6 +++++- mediastreamer2 | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 655a5547d..d4f5193f3 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -110,7 +110,6 @@ static void call_received(SalOp *h){ linphone_address_clean(from_parsed); tmp=linphone_address_as_string(from_parsed); linphone_address_destroy(from_parsed); - linphone_call_set_state(call,LinphoneCallIncomingReceived,"Incoming call"); barmesg=ortp_strdup_printf("%s %s%s",tmp,_("is contacting you"), (sal_call_autoanswer_asked(h)) ?_(" and asked autoanswer."):_(".")); if (lc->vtable.show) lc->vtable.show(lc); @@ -146,6 +145,11 @@ static void call_received(SalOp *h){ #endif ms_free(barmesg); ms_free(tmp); + + linphone_call_set_state(call,LinphoneCallIncomingReceived,"Incoming call"); + if (sal_call_get_replaces(call->op)!=NULL && lp_config_get_int(lc->config,"sip","auto_answer_replacing_calls",1)){ + linphone_core_accept_call(lc,call); + } } static void call_ringing(SalOp *h){ diff --git a/mediastreamer2 b/mediastreamer2 index 21471e316..ffacf5671 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 21471e316965e7ce61964b18793ec0cadbd37658 +Subproject commit ffacf56718c198cb80a290f7a65975916d8a9b6b From 7276441cf8d80b45680615ddf3e4d3506697ec68 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 28 Oct 2010 17:24:28 +0200 Subject: [PATCH 16/27] update version number --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index fd84dfb58..93f4f1b00 100644 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,6 @@ dnl Process this file with autoconf to produce a configure script. -AC_INIT([linphone],[3.3.99.8],[linphone-developers@nongnu.org]) +AC_INIT([linphone],[3.3.99.9],[linphone-developers@nongnu.org]) AC_CANONICAL_SYSTEM AC_CONFIG_SRCDIR([coreapi/linphonecore.c]) From 92b5747b7cfcff39dd64bffae481d3c00dcee75a Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 1 Nov 2010 11:32:24 +0100 Subject: [PATCH 17/27] propose video window interface --- java/common/org/linphone/core/LinphoneCore.java | 3 +++ java/common/org/linphone/core/VideoWindow.java | 5 +++++ 2 files changed, 8 insertions(+) create mode 100644 java/common/org/linphone/core/VideoWindow.java diff --git a/java/common/org/linphone/core/LinphoneCore.java b/java/common/org/linphone/core/LinphoneCore.java index d74997d52..b001f0a6f 100644 --- a/java/common/org/linphone/core/LinphoneCore.java +++ b/java/common/org/linphone/core/LinphoneCore.java @@ -275,4 +275,7 @@ public interface LinphoneCore { * @return {@link LinphoneChatRoom} where messaging can take place. */ LinphoneChatRoom createChatRoom(String to); + + public void setVideoWindow(VideoWindow w); + public void setPreviewWindow(VideoWindow w); } diff --git a/java/common/org/linphone/core/VideoWindow.java b/java/common/org/linphone/core/VideoWindow.java new file mode 100644 index 000000000..d4a46b931 --- /dev/null +++ b/java/common/org/linphone/core/VideoWindow.java @@ -0,0 +1,5 @@ +package org.linphone.core; + +public interface VideoWindow { + +} From 95bd9f46bf7373e018b58c4c7e914b07a52be8f1 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Thu, 4 Nov 2010 16:44:25 +0100 Subject: [PATCH 18/27] javadoc enhancements --- .../org/linphone/core/LinphoneAddress.java | 16 ++- .../org/linphone/core/LinphoneAuthInfo.java | 9 +- .../org/linphone/core/LinphoneCall.java | 62 +++++++- .../org/linphone/core/LinphoneCallLog.java | 20 ++- .../org/linphone/core/LinphoneCore.java | 132 +++++++++++++++--- .../linphone/core/LinphoneCoreFactory.java | 14 +- .../linphone/core/LinphoneCoreListener.java | 8 +- .../org/linphone/core/LinphoneLogHandler.java | 14 +- 8 files changed, 236 insertions(+), 39 deletions(-) diff --git a/java/common/org/linphone/core/LinphoneAddress.java b/java/common/org/linphone/core/LinphoneAddress.java index 16c688470..b2a2c9380 100644 --- a/java/common/org/linphone/core/LinphoneAddress.java +++ b/java/common/org/linphone/core/LinphoneAddress.java @@ -17,7 +17,16 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ package org.linphone.core; - +/** + * Object that represents a SIP address. + * The LinphoneAddress is an opaque object to represents SIP addresses, ie the content of SIP's 'from' and 'to' headers. + * A SIP address is made of display name, username, domain name, port, and various uri headers (such as tags). + * It looks like 'Alice '. The LinphoneAddress has methods to extract and manipulate all parts of the address. + * When some part of the address (for example the username) is empty, the accessor methods return null. + *
    Can be instanciated using both {@link LinphoneCoreFactory#createLinphoneAddress(String, String, String)} or {@link LinphoneCoreFactory#createLinphoneAddress(String)} + * @author jehanmonnier + * + */ public interface LinphoneAddress { /** * Human display name @@ -58,6 +67,9 @@ public interface LinphoneAddress { */ public String asStringUriOnly(); - /*must return the same thing as asString()*/ + /** + * same as {@link #asString()} + * + * */ public String toString(); } diff --git a/java/common/org/linphone/core/LinphoneAuthInfo.java b/java/common/org/linphone/core/LinphoneAuthInfo.java index f679307c5..6590dafeb 100644 --- a/java/common/org/linphone/core/LinphoneAuthInfo.java +++ b/java/common/org/linphone/core/LinphoneAuthInfo.java @@ -19,9 +19,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. package org.linphone.core; /** * Object holding authentication information. - * Note: - * The object's fields should not be accessed directly. Prefer using the accessor methods. * In most case, authentication information consists of a username and password. Sometimes, a userid is required by proxy, and realm can be useful to discriminate different SIP domains. + *
    This object is instanciated using {@link LinphoneCoreFactory#createAuthInfo(String, String, String)}. *
    *Once created and filled, a LinphoneAuthInfo must be added to the LinphoneCore in order to become known and used automatically when needed. *Use {@link LinphoneCore#addAuthInfo(LinphoneAuthInfo)} for that purpose. @@ -35,7 +34,7 @@ package org.linphone.core; */ public interface LinphoneAuthInfo { /** - * + * get user name * @return username */ String getUsername(); @@ -45,8 +44,8 @@ public interface LinphoneAuthInfo { */ void setUsername(String username); /** - * - * @return paasword + * get password + * @return password */ String getPassword(); /** diff --git a/java/common/org/linphone/core/LinphoneCall.java b/java/common/org/linphone/core/LinphoneCall.java index 03baca9df..65923706c 100644 --- a/java/common/org/linphone/core/LinphoneCall.java +++ b/java/common/org/linphone/core/LinphoneCall.java @@ -20,26 +20,78 @@ package org.linphone.core; import java.util.Vector; - +/** + * Object representing a Call. calls are created using {@link LinphoneCore#invite(LinphoneAddress)} or paased to the application by listener {@link LinphoneCoreListener#callState(LinphoneCore, LinphoneCall, State, String)} + * + */ public interface LinphoneCall { + /** + * Linphone call states + * + */ static class State { static private Vector values = new Vector(); private final int mValue; private final String mStringValue; + /** + * Idle + */ public final static State Idle = new State(0,"Idle"); + /** + * Incoming call received. + */ public final static State IncomingReceived = new State(1,"IncomingReceived"); + /** + * Outgoing call initialiazed. + */ public final static State OutgoingInit = new State(2,"OutgoingInit"); + /** + * Outgoing call in progress. + */ public final static State OutgoingProgress = new State(3,"OutgoingProgress"); + /** + * Outgoing call ringing. + */ public final static State OutgoingRinging = new State(4,"OutgoingRinging"); + /** + * Outgoing call early media + */ public final static State OutgoingEarlyMedia = new State(5,"OutgoingEarlyMedia"); + /** + * Connected + */ public final static State Connected = new State(6,"Connected"); + /** + * Streams running + */ public final static State StreamsRunning = new State(7,"StreamsRunning"); + /** + * Paussing + */ public final static State Pausing = new State(8,"Pausing"); + /** + * Paused + */ public final static State Paused = new State(9,"Paused"); + /** + * Resuming + */ public final static State Resuming = new State(10,"Resuming"); + /** + * Refered + */ public final static State Refered = new State(11,"Refered"); + /** + * Error + */ public final static State Error = new State(12,"Error"); + /** + * Call end + */ public final static State CallEnd = new State(13,"CallEnd"); + /** + * Paused by remote + */ public final static State PausedByRemote = new State(14,"PausedByRemote"); private State(int value,String stringValue) { mValue = value; @@ -69,10 +121,14 @@ public interface LinphoneCall { * **/ public LinphoneAddress getRemoteAddress(); - + /** + * get direction of the call (incoming or outgoing). + * @return CallDirection + */ public CallDirection getDirection(); /** - * Returns the call log associated to this call. + * get the call log associated to this call. + * @Return LinphoneCallLog **/ public LinphoneCallLog getCallLog(); diff --git a/java/common/org/linphone/core/LinphoneCallLog.java b/java/common/org/linphone/core/LinphoneCallLog.java index 08cdb8034..6c4923872 100644 --- a/java/common/org/linphone/core/LinphoneCallLog.java +++ b/java/common/org/linphone/core/LinphoneCallLog.java @@ -17,13 +17,25 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ package org.linphone.core; - +/** + * Call data records object + * + */ public interface LinphoneCallLog { - + /** + * Originator of the call as a LinphoneAddress object. + * @return LinphoneAddress + */ public LinphoneAddress getFrom(); - + /** + * Destination of the call as a LinphoneAddress object. + * @return + */ public LinphoneAddress getTo (); - + /** + * The direction of the call + * @return CallDirection + */ public CallDirection getDirection(); } diff --git a/java/common/org/linphone/core/LinphoneCore.java b/java/common/org/linphone/core/LinphoneCore.java index d74997d52..46a631a7a 100644 --- a/java/common/org/linphone/core/LinphoneCore.java +++ b/java/common/org/linphone/core/LinphoneCore.java @@ -21,17 +21,31 @@ package org.linphone.core; import java.util.Vector; - +/** + * Linphone core main object created by method {@link LinphoneCoreFactory#createLinphoneCore(LinphoneCoreListener, String, String, Object)}. + * + */ public interface LinphoneCore { /** * linphone core states */ static public class GlobalState { static private Vector values = new Vector(); - + /** + * Off + */ static public GlobalState GlobalOff = new GlobalState(0,"GlobalOff"); + /** + * Startup + */ static public GlobalState GlobalStartup = new GlobalState(1,"GlobalStartup"); + /** + * On + */ static public GlobalState GlobalOn = new GlobalState(2,"GlobalOn"); + /** + * Shutdown + */ static public GlobalState GlobalShutdown = new GlobalState(3,"GlobalShutdown"); private final int mValue; @@ -54,12 +68,31 @@ public interface LinphoneCore { return mStringValue; } } + /** + * Describes proxy registration states. + * + */ static public class RegistrationState { static private Vector values = new Vector(); + /** + * None + */ static public RegistrationState RegistrationNone = new RegistrationState(0,"RegistrationNone"); + /** + * In Progress + */ static public RegistrationState RegistrationProgress = new RegistrationState(1,"RegistrationProgress"); + /** + * Ok + */ static public RegistrationState RegistrationOk = new RegistrationState(2,"RegistrationOk"); + /** + * Cleared + */ static public RegistrationState RegistrationCleared = new RegistrationState(3,"RegistrationCleared"); + /** + * Failed + */ static public RegistrationState RegistrationFailed = new RegistrationState(4,"RegistrationFailed"); private final int mValue; private final String mStringValue; @@ -81,8 +114,18 @@ public interface LinphoneCore { return mStringValue; } } + /** + * Signaling transports + * + */ static public class Transport { + /** + * UDP transport + */ public final static Transport udp =new Transport("udp"); + /** + * TCP transport + */ public final static Transport tcp =new Transport("tcp"); private final String mStringValue; @@ -94,15 +137,26 @@ public interface LinphoneCore { } } /** - * clear all added proxy config + * clear all added proxy configs */ public void clearProxyConfigs(); - + /** + * Add a proxy configuration. This will start registration on the proxy, if registration is enabled. + * @param proxyCfg + * @throws LinphoneCoreException + */ public void addProxyConfig(LinphoneProxyConfig proxyCfg) throws LinphoneCoreException; - + /** + * Sets the default proxy. + *
    + * This default proxy must be part of the list of already entered {@link LinphoneProxyConfig}. + * Toggling it as default will make LinphoneCore use the identity associated with the proxy configuration in all incoming and outgoing calls. + * @param proxyCfg + */ public void setDefaultProxyConfig(LinphoneProxyConfig proxyCfg); /** + * get he default proxy configuration, that is the one used to determine the current identity. * @return null if no default proxy config */ public LinphoneProxyConfig getDefaultProxyConfig() ; @@ -111,7 +165,11 @@ public interface LinphoneCore { * clear all the added auth info */ void clearAuthInfos(); - + /** + * Adds authentication information to the LinphoneCore. + *
    This information will be used during all SIP transacations that require authentication. + * @param info + */ void addAuthInfo(LinphoneAuthInfo info); /** @@ -123,13 +181,22 @@ public interface LinphoneCore { public LinphoneAddress interpretUrl(String destination) throws LinphoneCoreException; /** - * Starts a call given a destination. Internally calls interpretUrl() then invite(LinphoneAddress). + * Starts a call given a destination. Internally calls {@link #interpretUrl(String)} then {@link #invite(LinphoneAddress)}. * @param uri */ public LinphoneCall invite(String destination)throws LinphoneCoreException; - + /** + * Initiates an outgoing call given a destination LinphoneAddress + *
    The LinphoneAddress can be constructed directly using linphone_address_new(), or created by linphone_core_interpret_url(). The application doesn't own a reference to the returned LinphoneCall object. Use linphone_call_ref() to safely keep the LinphoneCall pointer valid within your application. + * @param to the destination of the call (sip address). + * @return LinphoneCall + * @throws LinphoneCoreException + */ public LinphoneCall invite(LinphoneAddress to)throws LinphoneCoreException; - + /** + * Terminates a call. + * @param aCall to be terminated + */ public void terminateCall(LinphoneCall aCall); /** * Returns The LinphoneCall the current call if one is in call @@ -152,6 +219,17 @@ public interface LinphoneCore { * @return Returns true if in incoming call is pending, ie waiting for being answered or declined. */ public boolean isInComingInvitePending(); + /** + * Main loop function. It is crucial that your application call it periodically. + * + * #iterate() performs various backgrounds tasks: + *
  • receiving of SIP messages + *
  • handles timers and timeout + *
  • performs registration to proxies + *
  • authentication retries The application MUST call this function from periodically, in its main loop. + *
    Be careful that this function must be call from the same thread as other liblinphone methods. In not the case make sure all liblinphone calls are serialized with a mutex. + + */ public void iterate(); /** * Accept an incoming call. @@ -232,28 +310,46 @@ public interface LinphoneCore { public void stopDtmf(); /** - * + * remove all call logs */ public void clearCallLogs(); - - /*** * get payload type from mime type an clock rate * * return null if not found */ public PayloadType findPayloadType(String mime,int clockRate); - + /** + * not implemented yet + * @param pt + * @param enable + * @throws LinphoneCoreException + */ public void enablePayloadType(PayloadType pt, boolean enable) throws LinphoneCoreException; - + /** + * Enables or disable echo cancellation. + * @param enable + */ public void enableEchoCancellation(boolean enable); - + /** + * get EC status + * @return true if echo cancellation is enabled. + */ public boolean isEchoCancellationEnabled(); - + /** + * not implemented yet + * @param aTransport + */ public void setSignalingTransport(Transport aTransport); - + /** + * not implemented + * @param value + */ public void enableSpeaker(boolean value); - + /** + * not implemented + * @return + */ public boolean isSpeakerEnabled(); /** * add a friend to the current buddy list, if subscription attribute is set, a SIP SUBSCRIBE message is sent. diff --git a/java/common/org/linphone/core/LinphoneCoreFactory.java b/java/common/org/linphone/core/LinphoneCoreFactory.java index c0d09b0a6..4089ca1fb 100644 --- a/java/common/org/linphone/core/LinphoneCoreFactory.java +++ b/java/common/org/linphone/core/LinphoneCoreFactory.java @@ -49,9 +49,19 @@ abstract public class LinphoneCoreFactory { abstract public LinphoneAuthInfo createAuthInfo(String username,String password, String realm); abstract public LinphoneCore createLinphoneCore(LinphoneCoreListener listener, String userConfig,String factoryConfig,Object userdata) throws LinphoneCoreException; - + /** + * Constructs a LinphoneAddress object + * @param username + * @param domain + * @param displayName + * @return + */ abstract public LinphoneAddress createLinphoneAddress(String username,String domain,String displayName); - + /** + * Constructs a LinphoneAddress object by parsing the user supplied address, given as a string. + * @param address should be like sip:joe@sip.linphone.org + * @return + */ abstract public LinphoneAddress createLinphoneAddress(String address); abstract public LinphoneProxyConfig createProxyConfig(String identity, String proxy,String route,boolean enableRegister) throws LinphoneCoreException; diff --git a/java/common/org/linphone/core/LinphoneCoreListener.java b/java/common/org/linphone/core/LinphoneCoreListener.java index 6cb038cdd..daf256662 100644 --- a/java/common/org/linphone/core/LinphoneCoreListener.java +++ b/java/common/org/linphone/core/LinphoneCoreListener.java @@ -19,15 +19,15 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 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 */ public void show(LinphoneCore lc); - /**< Notify calls terminated by far end - * @return */ - public void byeReceived(LinphoneCore lc,String from); /**< Ask the application some authentication information * @return */ public void authInfoRequested(LinphoneCore lc,String realm,String username); diff --git a/java/common/org/linphone/core/LinphoneLogHandler.java b/java/common/org/linphone/core/LinphoneLogHandler.java index d1330a400..9465dccc7 100644 --- a/java/common/org/linphone/core/LinphoneLogHandler.java +++ b/java/common/org/linphone/core/LinphoneLogHandler.java @@ -17,7 +17,11 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ package org.linphone.core; - +/** + * Interface to implement for handling liblinphone log. + *
    use {@link LinphoneCoreFactory#setLogHandler(LinphoneLogHandler)} + * + */ public interface LinphoneLogHandler { public static final int Fatal=1<<4; public static final int Error=1<<3|Fatal; @@ -25,5 +29,13 @@ public interface LinphoneLogHandler { public static final int Info=1<<1|Warn; public static final int Debug=1|Info; + /** + * Method invoked for each traces + * @param loggerName + * @param level + * @param levelString + * @param msg + * @param e + */ public void log(String loggerName, int level, String levelString, String msg, Throwable e); } From 07de5730d771374431f1bc4337d4dfb75712b6e2 Mon Sep 17 00:00:00 2001 From: Guillaume Beraudo Date: Fri, 5 Nov 2010 15:13:50 +0100 Subject: [PATCH 19/27] Ported C tutorials to java. --- .../core/tutorials/TutorialBuddyStatus.java | 185 ++++++++++++++++++ .../core/tutorials/TutorialChatRoom.java | 144 ++++++++++++++ .../core/tutorials/TutorialHelloWorld.java | 157 +++++++++++++++ .../core/tutorials/TutorialNotifier.java | 8 + .../core/tutorials/TutorialRegistration.java | 164 ++++++++++++++++ .../linphone/core/LinphoneCoreFactory.java | 7 +- 6 files changed, 663 insertions(+), 2 deletions(-) create mode 100644 coreapi/help/java/org/linphone/core/tutorials/TutorialBuddyStatus.java create mode 100644 coreapi/help/java/org/linphone/core/tutorials/TutorialChatRoom.java create mode 100644 coreapi/help/java/org/linphone/core/tutorials/TutorialHelloWorld.java create mode 100644 coreapi/help/java/org/linphone/core/tutorials/TutorialNotifier.java create mode 100644 coreapi/help/java/org/linphone/core/tutorials/TutorialRegistration.java diff --git a/coreapi/help/java/org/linphone/core/tutorials/TutorialBuddyStatus.java b/coreapi/help/java/org/linphone/core/tutorials/TutorialBuddyStatus.java new file mode 100644 index 000000000..f85cf88f8 --- /dev/null +++ b/coreapi/help/java/org/linphone/core/tutorials/TutorialBuddyStatus.java @@ -0,0 +1,185 @@ +/* +linphone +Copyright (C) 2010 Belledonne Communications SARL + (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package org.linphone.core.tutorials; + +import org.linphone.core.LinphoneAddress; +import org.linphone.core.LinphoneCall; +import org.linphone.core.LinphoneChatRoom; +import org.linphone.core.LinphoneCore; +import org.linphone.core.LinphoneCoreException; +import org.linphone.core.LinphoneCoreFactory; +import org.linphone.core.LinphoneCoreListener; +import org.linphone.core.LinphoneFriend; +import org.linphone.core.LinphoneProxyConfig; +import org.linphone.core.OnlineStatus; +import org.linphone.core.LinphoneCall.State; +import org.linphone.core.LinphoneCore.GlobalState; +import org.linphone.core.LinphoneCore.RegistrationState; +import org.linphone.core.LinphoneFriend.SubscribePolicy; + +/** + * + * This program is a _very_ simple usage example of liblinphone, + * demonstrating how to initiate SIP subscriptions and receive notifications + * from a sip uri identity passed from the command line. + *
    Argument must be like sip:jehan@sip.linphone.org . + * ex budy_list sip:jehan@sip.linphone.org + *
    Subscription is cleared on SIGINT + * + * Ported from buddy_status.c + * + * @author Guillaume Beraudo + * + */ +public class TutorialBuddyStatus implements LinphoneCoreListener { + + private boolean running; + private TutorialNotifier TutorialNotifier; + + + public TutorialBuddyStatus(TutorialNotifier TutorialNotifier) { + this.TutorialNotifier = TutorialNotifier; + } + + public TutorialBuddyStatus() { + this.TutorialNotifier = new TutorialNotifier(); + } + + + + public void newSubscriptionRequest(LinphoneCore lc, LinphoneFriend lf,String url) { + write("["+lf.getAddress().getUserName()+"] wants to see your status, accepting"); + lf.edit(); + lf.setIncSubscribePolicy(SubscribePolicy.SPAccept); + lf.done(); + try { + lc.addFriend(lf); + } catch (LinphoneCoreException e) { + write("Error while adding friend [" + lf.getAddress().getUserName() + "] to linphone in the callback"); + } + } + + public void notifyPresenceReceived(LinphoneCore lc, LinphoneFriend lf) { + write("New state [" + lf.getStatus() +"] for user id ["+lf.getAddress().getUserName()+"]"); + } + + + public void registrationState(LinphoneCore lc, LinphoneProxyConfig cfg,RegistrationState cstate, String smessage) {} + public void show(LinphoneCore lc) {} + public void byeReceived(LinphoneCore lc, String from) {} + public void authInfoRequested(LinphoneCore lc, String realm, String username) {} + public void displayStatus(LinphoneCore lc, String message) {} + public void displayMessage(LinphoneCore lc, String message) {} + public void displayWarning(LinphoneCore lc, String message) {} + public void globalState(LinphoneCore lc, GlobalState state, String message) {} + public void textReceived(LinphoneCore lc, LinphoneChatRoom cr,LinphoneAddress from, String message) {} + public void callState(LinphoneCore lc, LinphoneCall call, State cstate, String msg) {} + + + + + public static void main(String[] args) { + // Check tutorial was called with the right number of arguments + if (args.length != 1) { + throw new IllegalArgumentException("Bad number of arguments"); + } + + // Create tutorial object + TutorialBuddyStatus tutorial = new TutorialBuddyStatus(); + try { + String userSipAddress = args[1]; + tutorial.launchTutorial(userSipAddress); + } catch (Exception e) { + e.printStackTrace(); + } + } + + + + public void launchTutorial(String sipAddress) throws LinphoneCoreException { + final LinphoneCoreFactory lcFactory = LinphoneCoreFactory.instance(); + + // First instantiate the core Linphone object given only a listener. + // The listener will react to events in Linphone core. + LinphoneCore lc = lcFactory.createLinphoneCore(this); + + + try { + + // Create friend address + LinphoneFriend lf = lcFactory.createLinphoneFriend(sipAddress); + if (lf == null) { + write("Could not create friend; weird SIP address?"); + return; + } + + lf.enableSubscribes(true); + lf.setIncSubscribePolicy(SubscribePolicy.SPAccept); + try { + lc.addFriend(lf); + } catch (LinphoneCoreException e) { + write("Error while adding friend " + lf.getAddress().getUserName() + " to linphone"); + } + + + lc.setPresenceInfo(0, null, OnlineStatus.Online); + + + // main loop for receiving notifications and doing background linphonecore work + running = true; + while (running) { + lc.iterate(); + try{ + Thread.sleep(50); + } catch(InterruptedException ie) { + write("Interrupted!\nAborting"); + return; + } + } + + + lc.setPresenceInfo(0, null, OnlineStatus.Offline); + lc.iterate(); + + lf.edit(); + lf.enableSubscribes(false); + lf.done(); + lc.iterate(); + + + } finally { + write("Shutting down..."); + // You need to destroy the LinphoneCore object when no longer used + lc.destroy(); + write("Exited"); + } + } + + + public void stopMainLoop() { + running=false; + } + + + private void write(String s) { + TutorialNotifier.notify(s); + } + +} diff --git a/coreapi/help/java/org/linphone/core/tutorials/TutorialChatRoom.java b/coreapi/help/java/org/linphone/core/tutorials/TutorialChatRoom.java new file mode 100644 index 000000000..ff6787439 --- /dev/null +++ b/coreapi/help/java/org/linphone/core/tutorials/TutorialChatRoom.java @@ -0,0 +1,144 @@ +/* +linphone +Copyright (C) 2010 Belledonne Communications SARL + (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package org.linphone.core.tutorials; + +import org.linphone.core.LinphoneAddress; +import org.linphone.core.LinphoneCall; +import org.linphone.core.LinphoneChatRoom; +import org.linphone.core.LinphoneCore; +import org.linphone.core.LinphoneCoreException; +import org.linphone.core.LinphoneCoreFactory; +import org.linphone.core.LinphoneCoreListener; +import org.linphone.core.LinphoneFriend; +import org.linphone.core.LinphoneProxyConfig; +import org.linphone.core.LinphoneCall.State; +import org.linphone.core.LinphoneCore.GlobalState; +import org.linphone.core.LinphoneCore.RegistrationState; + + +/** + * This program is a _very_ simple usage example of liblinphone. + * It demonstrates how to send/receive SIP MESSAGE from a sip uri identity + * passed from the command line. + * + * Argument must be like sip:jehan@sip.linphone.org . + * + * ex chatroom sip:jehan@sip.linphone.org + * just takes a sip-uri as first argument and attempts to call it. + * + * Ported from chatroom.c + * + * @author Guillaume Beraudo + * + */ +public class TutorialChatRoom implements LinphoneCoreListener { + private boolean running; + private TutorialNotifier TutorialNotifier; + + + public TutorialChatRoom(TutorialNotifier TutorialNotifier) { + this.TutorialNotifier = TutorialNotifier; + } + + public TutorialChatRoom() { + this.TutorialNotifier = new TutorialNotifier(); + } + + + + public void show(LinphoneCore lc) {} + public void byeReceived(LinphoneCore lc, String from) {} + public void authInfoRequested(LinphoneCore lc, String realm, String username) {} + public void displayStatus(LinphoneCore lc, String message) {} + public void displayMessage(LinphoneCore lc, String message) {} + public void displayWarning(LinphoneCore lc, String message) {} + public void globalState(LinphoneCore lc, GlobalState state, String message) {} + public void registrationState(LinphoneCore lc, LinphoneProxyConfig cfg,RegistrationState cstate, String smessage) {} + public void newSubscriptionRequest(LinphoneCore lc, LinphoneFriend lf,String url) {} + public void notifyPresenceReceived(LinphoneCore lc, LinphoneFriend lf) {} + public void callState(LinphoneCore lc, LinphoneCall call, State cstate, String msg){} + + + + public void textReceived(LinphoneCore lc, LinphoneChatRoom cr,LinphoneAddress from, String message) { + write("Message ["+message+"] received from ["+from.asString()+"]"); + } + + + + public static void main(String[] args) { + // Check tutorial was called with the right number of arguments + if (args.length != 1) { + throw new IllegalArgumentException("Bad number of arguments"); + } + + // Create tutorial object + TutorialChatRoom tutorial = new TutorialChatRoom(); + try { + String destinationSipAddress = args[1]; + tutorial.launchTutorial(destinationSipAddress); + } catch (Exception e) { + e.printStackTrace(); + } + } + + + + public void launchTutorial(String destinationSipAddress) throws LinphoneCoreException { + + // First instantiate the core Linphone object given only a listener. + // The listener will react to events in Linphone core. + LinphoneCore lc = LinphoneCoreFactory.instance().createLinphoneCore(this); + + try { + LinphoneChatRoom chatRoom = lc.createChatRoom(destinationSipAddress); + chatRoom.sendMessage("Hello world"); + + // main loop for receiving notifications and doing background linphonecore work + running = true; + while (running) { + lc.iterate(); + try{ + Thread.sleep(50); + } catch(InterruptedException ie) { + write("Interrupted!\nAborting"); + return; + } + } + + } finally { + write("Shutting down..."); + // You need to destroy the LinphoneCore object when no longer used + lc.destroy(); + write("Exited"); + } + } + + + public void stopMainLoop() { + running=false; + } + + + private void write(String s) { + TutorialNotifier.notify(s); + } + +} diff --git a/coreapi/help/java/org/linphone/core/tutorials/TutorialHelloWorld.java b/coreapi/help/java/org/linphone/core/tutorials/TutorialHelloWorld.java new file mode 100644 index 000000000..e116c3523 --- /dev/null +++ b/coreapi/help/java/org/linphone/core/tutorials/TutorialHelloWorld.java @@ -0,0 +1,157 @@ +/* +linphone +Copyright (C) 2010 Belledonne Communications SARL + (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package org.linphone.core.tutorials; + +import org.linphone.core.LinphoneAddress; +import org.linphone.core.LinphoneCall; +import org.linphone.core.LinphoneChatRoom; +import org.linphone.core.LinphoneCore; +import org.linphone.core.LinphoneCoreException; +import org.linphone.core.LinphoneCoreFactory; +import org.linphone.core.LinphoneCoreListener; +import org.linphone.core.LinphoneFriend; +import org.linphone.core.LinphoneProxyConfig; +import org.linphone.core.LinphoneCall.State; +import org.linphone.core.LinphoneCore.GlobalState; +import org.linphone.core.LinphoneCore.RegistrationState; + + +/** + * This program is a _very_ simple usage example of liblinphone. + * It just takes a sip-uri as first argument and attempts to call it. + * + * Ported from helloworld.c + * + * @author Guillaume Beraudo + * + */ +public class TutorialHelloWorld implements LinphoneCoreListener { + private boolean running; + private TutorialNotifier TutorialNotifier; + + + public TutorialHelloWorld(TutorialNotifier TutorialNotifier) { + this.TutorialNotifier = TutorialNotifier; + } + + public TutorialHelloWorld() { + this.TutorialNotifier = new TutorialNotifier(); + } + + + + public void show(LinphoneCore lc) {} + public void byeReceived(LinphoneCore lc, String from) {} + public void authInfoRequested(LinphoneCore lc, String realm, String username) {} + public void displayStatus(LinphoneCore lc, String message) {} + public void displayMessage(LinphoneCore lc, String message) {} + public void displayWarning(LinphoneCore lc, String message) {} + public void globalState(LinphoneCore lc, GlobalState state, String message) {} + public void registrationState(LinphoneCore lc, LinphoneProxyConfig cfg,RegistrationState cstate, String smessage) {} + public void newSubscriptionRequest(LinphoneCore lc, LinphoneFriend lf,String url) {} + public void notifyPresenceReceived(LinphoneCore lc, LinphoneFriend lf) {} + public void textReceived(LinphoneCore lc, LinphoneChatRoom cr,LinphoneAddress from, String message) {} + + /* + * Call state notification listener + */ + public void callState(LinphoneCore lc, LinphoneCall call, State cstate, String msg){ + write("State: " + msg); + + if (State.CallEnd.equals(cstate)) + running = false; + } + + + public static void main(String[] args) { + // Check tutorial was called with the right number of arguments + if (args.length != 1) { + throw new IllegalArgumentException("Bad number of arguments"); + } + + // Create tutorial object + TutorialHelloWorld helloWorld = new TutorialHelloWorld(); + try { + String destinationSipAddress = args[1]; + helloWorld.launchTutorial(destinationSipAddress); + } catch (Exception e) { + e.printStackTrace(); + } + } + + + + public void launchTutorial(String destinationSipAddress) throws LinphoneCoreException { + + // First instantiate the core Linphone object given only a listener. + // The listener will react to events in Linphone core. + LinphoneCore lc = LinphoneCoreFactory.instance().createLinphoneCore(this); + + + + try { + // Send the INVITE message to destination SIP address + LinphoneCall call = lc.invite(destinationSipAddress); + if (call == null) { + write("Could not place call to " + destinationSipAddress); + write("Aborting"); + return; + } + write("Call to " + destinationSipAddress + " is in progress..."); + + + + // main loop for receiving notifications and doing background linphonecore work + running = true; + while (running) { + lc.iterate(); + try{ + Thread.sleep(50); + } catch(InterruptedException ie) { + write("Interrupted!\nAborting"); + return; + } + } + + + + if (!State.CallEnd.equals(call.getState())) { + write("Terminating the call"); + lc.terminateCall(call); + } + } finally { + write("Shutting down..."); + // You need to destroy the LinphoneCore object when no longer used + lc.destroy(); + write("Exited"); + } + } + + + public void stopMainLoop() { + running=false; + } + + + private void write(String s) { + TutorialNotifier.notify(s); + } + +} diff --git a/coreapi/help/java/org/linphone/core/tutorials/TutorialNotifier.java b/coreapi/help/java/org/linphone/core/tutorials/TutorialNotifier.java new file mode 100644 index 000000000..c8138214c --- /dev/null +++ b/coreapi/help/java/org/linphone/core/tutorials/TutorialNotifier.java @@ -0,0 +1,8 @@ +package org.linphone.core.tutorials; + +public class TutorialNotifier { + + public void notify(String s) { + System.out.println(s); + } +} diff --git a/coreapi/help/java/org/linphone/core/tutorials/TutorialRegistration.java b/coreapi/help/java/org/linphone/core/tutorials/TutorialRegistration.java new file mode 100644 index 000000000..0f72594f8 --- /dev/null +++ b/coreapi/help/java/org/linphone/core/tutorials/TutorialRegistration.java @@ -0,0 +1,164 @@ +/* +linphone +Copyright (C) 2010 Belledonne Communications SARL + (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package org.linphone.core.tutorials; + +import org.linphone.core.LinphoneAddress; +import org.linphone.core.LinphoneCall; +import org.linphone.core.LinphoneChatRoom; +import org.linphone.core.LinphoneCore; +import org.linphone.core.LinphoneCoreException; +import org.linphone.core.LinphoneCoreFactory; +import org.linphone.core.LinphoneCoreListener; +import org.linphone.core.LinphoneFriend; +import org.linphone.core.LinphoneProxyConfig; +import org.linphone.core.LinphoneCall.State; +import org.linphone.core.LinphoneCore.GlobalState; +import org.linphone.core.LinphoneCore.RegistrationState; + + +/** + * This program is a _very_ simple usage example of liblinphone. + * Demonstrating how to initiate a SIP registration from a sip uri identity + * passed from the command line. + * + * First argument must be like sip:jehan@sip.linphone.org, second must be password. + *
    + * ex registration sip:jehan@sip.linphone.org secret + * + * Ported from registration.c + * + * @author Guillaume Beraudo + * + */ +public class TutorialRegistration implements LinphoneCoreListener { + private boolean running; + private TutorialNotifier TutorialNotifier; + + + public TutorialRegistration(TutorialNotifier TutorialNotifier) { + this.TutorialNotifier = TutorialNotifier; + } + + public TutorialRegistration() { + this.TutorialNotifier = new TutorialNotifier(); + } + + + /* + * Registration state notification listener + */ + public void registrationState(LinphoneCore lc, LinphoneProxyConfig cfg,RegistrationState cstate, String smessage) { + write(cfg.getIdentity() + " : "+smessage+"\n"); + + if (RegistrationState.RegistrationOk.equals(cstate)) + running = false; + } + + public void show(LinphoneCore lc) {} + public void byeReceived(LinphoneCore lc, String from) {} + public void authInfoRequested(LinphoneCore lc, String realm, String username) {} + public void displayStatus(LinphoneCore lc, String message) {} + public void displayMessage(LinphoneCore lc, String message) {} + public void displayWarning(LinphoneCore lc, String message) {} + public void globalState(LinphoneCore lc, GlobalState state, String message) {} + public void newSubscriptionRequest(LinphoneCore lc, LinphoneFriend lf,String url) {} + public void notifyPresenceReceived(LinphoneCore lc, LinphoneFriend lf) {} + public void textReceived(LinphoneCore lc, LinphoneChatRoom cr,LinphoneAddress from, String message) {} + public void callState(LinphoneCore lc, LinphoneCall call, State cstate, String msg) {} + + + public static void main(String[] args) { + // Check tutorial was called with the right number of arguments + if (args.length != 2) { + throw new IllegalArgumentException("Bad number of arguments"); + } + + // Create tutorial object + TutorialRegistration tutorial = new TutorialRegistration(); + try { + String userSipAddress = args[1]; + String userSipPassword = args[2]; + tutorial.launchTutorial(userSipAddress, userSipPassword); + } catch (Exception e) { + e.printStackTrace(); + } + } + + + + public void launchTutorial(String sipAddress, String password) throws LinphoneCoreException { + final LinphoneCoreFactory lcFactory = LinphoneCoreFactory.instance(); + + // First instantiate the core Linphone object given only a listener. + // The listener will react to events in Linphone core. + LinphoneCore lc = lcFactory.createLinphoneCore(this); + + + try { + + LinphoneAddress address = lcFactory.createLinphoneAddress(sipAddress); + String username = address.getUserName(); + String domain = address.getDomain(); + + if (password != null) { + lc.addAuthInfo(lcFactory.createAuthInfo(username, password, null)); + } + + LinphoneProxyConfig proxyCfg = lcFactory.createProxyConfig(sipAddress, domain, null, true); + lc.addProxyConfig(proxyCfg); + lc.setDefaultProxyConfig(proxyCfg); + + + + + // main loop for receiving notifications and doing background linphonecore work + running = true; + while (running) { + lc.iterate(); + try{ + Thread.sleep(50); + } catch(InterruptedException ie) { + write("Interrupted!\nAborting"); + return; + } + } + + + + + } finally { + write("Shutting down..."); + // You need to destroy the LinphoneCore object when no longer used + lc.destroy(); + write("Exited"); + } + } + + + public void stopMainLoop() { + running=false; + } + + + private void write(String s) { + TutorialNotifier.notify(s); + } + +} diff --git a/java/common/org/linphone/core/LinphoneCoreFactory.java b/java/common/org/linphone/core/LinphoneCoreFactory.java index c0d09b0a6..51193ddc1 100644 --- a/java/common/org/linphone/core/LinphoneCoreFactory.java +++ b/java/common/org/linphone/core/LinphoneCoreFactory.java @@ -21,6 +21,7 @@ package org.linphone.core; + abstract public class LinphoneCoreFactory { private static String factoryName = "org.linphone.core.LinphoneCoreFactoryImpl"; @@ -49,6 +50,8 @@ abstract public class LinphoneCoreFactory { abstract public LinphoneAuthInfo createAuthInfo(String username,String password, String realm); abstract public LinphoneCore createLinphoneCore(LinphoneCoreListener listener, String userConfig,String factoryConfig,Object userdata) throws LinphoneCoreException; + abstract public LinphoneCore createLinphoneCore(LinphoneCoreListener listener) throws LinphoneCoreException; + abstract public LinphoneAddress createLinphoneAddress(String username,String domain,String displayName); @@ -67,12 +70,12 @@ abstract public class LinphoneCoreFactory { * @param friendUri a buddy address, must be a sip uri like sip:joe@sip.linphone.org * @return a new LinphoneFriend with address initialized */ - abstract LinphoneFriend createLinphoneFriend(String friendUri); + abstract public LinphoneFriend createLinphoneFriend(String friendUri); /** * Create a new LinphoneFriend * @return */ - abstract LinphoneFriend createLinphoneFriend(); + abstract public LinphoneFriend createLinphoneFriend(); } From 54f2db354657a20bdd1203a3eedfd332bf0431db Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Fri, 5 Nov 2010 16:03:19 +0100 Subject: [PATCH 20/27] add presence and messaging jni for callbacks --- coreapi/linphonecore_jni.cc | 71 +++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 972f31b7b..bdcef3c44 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -79,6 +79,9 @@ public: vTable.global_state_changed = globalStateChange; vTable.registration_state_changed = registrationStateChange; vTable.call_state_changed = callStateChange; + vTable.text_received = text_received; + vTable.new_subscription_request = new_subscription_request; + vTable.notify_presence_recv = notify_presence_recv; listernerClass = (jclass)env->NewGlobalRef(env->GetObjectClass( alistener)); /*displayStatus(LinphoneCore lc,String message);*/ @@ -96,12 +99,27 @@ public: callStateClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneCall$State")); callStateFromIntId = env->GetStaticMethodID(callStateClass,"fromInt","(I)Lorg/linphone/core/LinphoneCall$State;"); + /*void newSubscriptionRequest(LinphoneCore lc, LinphoneFriend lf, String url)*/ + newSubscriptionRequestId = env->GetMethodID(listernerClass,"newSubscriptionRequest","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneFriend;Ljava/lang/String;)V"); + + /*void notifyPresenceReceived(LinphoneCore lc, LinphoneFriend lf);*/ + notifyPresenceReceivedId = env->GetMethodID(listernerClass,"notifyPresenceReceived","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneFriend)V"); + + /*void textReceived(LinphoneCore lc, LinphoneChatRoom cr,LinphoneAddress from,String message);*/ + textReceivedId = env->GetMethodID(listernerClass,"textReceived","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCore/LinphoneChatRoom;Lorg/linphone/core/LinphoneFriend;Ljava/lang/String;)V"); + proxyClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneProxyConfigImpl")); proxyCtrId = env->GetMethodID(proxyClass,"", "(J)V"); callClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneCallImpl")); callCtrId = env->GetMethodID(callClass,"", "(J)V"); + chatRoomClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneChatRoomImpl")); + chatRoomCtrId = env->GetMethodID(chatRoomClass,"", "(J)V"); + + friendClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneFriendImpl"));; + friendCtrId =env->GetMethodID(friendClass,"", "(J)V"); + } ~LinphoneCoreData() { @@ -116,6 +134,8 @@ public: env->DeleteGlobalRef(callStateClass); env->DeleteGlobalRef(proxyClass); env->DeleteGlobalRef(callClass); + env->DeleteGlobalRef(chatRoomClass); + env->DeleteGlobalRef(friendClass); } jobject core; @@ -124,6 +144,9 @@ public: jclass listernerClass; jmethodID displayStatusId; + jmethodID newSubscriptionRequestId; + jmethodID notifyPresenceReceivedId; + jmethodID textReceivedId; jclass globalStateClass; jmethodID globalStateId; @@ -143,6 +166,12 @@ public: jclass callClass; jmethodID callCtrId; + jclass chatRoomClass; + jmethodID chatRoomCtrId; + + jclass friendClass; + jmethodID friendCtrId; + LinphoneCoreVTable vTable; static void showInterfaceCb(LinphoneCore *lc) { @@ -211,6 +240,48 @@ public: ,env->CallStaticObjectMethod(lcData->callStateClass,lcData->callStateFromIntId,(jint)state), message ? env->NewStringUTF(message) : NULL); } + static void notify_presence_recv (LinphoneCore *lc, LinphoneFriend *my_friend) { + 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->notifyPresenceReceivedId + ,lcData->core + ,env->NewObject(lcData->friendClass,lcData->friendCtrId,(jlong)my_friend)); + } + static void new_subscription_request (LinphoneCore *lc, LinphoneFriend *my_friend, const char* url) { + 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->newSubscriptionRequestId + ,lcData->core + ,env->NewObject(lcData->friendClass,lcData->friendCtrId,(jlong)my_friend) + ,url ? env->NewStringUTF(url) : NULL); + } + static void text_received(LinphoneCore *lc, LinphoneChatRoom *room, const LinphoneAddress *from, const char *message) { + 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->textReceivedId + ,lcData->core + ,env->NewObject(lcData->chatRoomClass,lcData->chatRoomCtrId,(jlong)room) + ,env->NewObject(lcData->friendClass,lcData->friendCtrId,(jlong)from) + ,message ? env->NewStringUTF(message) : NULL); + } }; From f2f81ad287f99da85ecc1f4abefed47d1148392e Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Fri, 5 Nov 2010 16:28:03 +0100 Subject: [PATCH 21/27] fix wrong jni prototypes --- coreapi/linphonecore_jni.cc | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index bdcef3c44..d22edef61 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -103,10 +103,10 @@ public: newSubscriptionRequestId = env->GetMethodID(listernerClass,"newSubscriptionRequest","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneFriend;Ljava/lang/String;)V"); /*void notifyPresenceReceived(LinphoneCore lc, LinphoneFriend lf);*/ - notifyPresenceReceivedId = env->GetMethodID(listernerClass,"notifyPresenceReceived","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneFriend)V"); + notifyPresenceReceivedId = env->GetMethodID(listernerClass,"notifyPresenceReceived","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneFriend;)V"); /*void textReceived(LinphoneCore lc, LinphoneChatRoom cr,LinphoneAddress from,String message);*/ - textReceivedId = env->GetMethodID(listernerClass,"textReceived","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCore/LinphoneChatRoom;Lorg/linphone/core/LinphoneFriend;Ljava/lang/String;)V"); + textReceivedId = env->GetMethodID(listernerClass,"textReceived","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneChatRoom;Lorg/linphone/core/LinphoneAddress;Ljava/lang/String;)V"); proxyClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneProxyConfigImpl")); proxyCtrId = env->GetMethodID(proxyClass,"", "(J)V"); @@ -120,6 +120,9 @@ public: friendClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneFriendImpl"));; friendCtrId =env->GetMethodID(friendClass,"", "(J)V"); + addressClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneAddressImpl")); + addressCtrId =env->GetMethodID(addressClass,"", "(J)V"); + } ~LinphoneCoreData() { @@ -172,6 +175,9 @@ public: jclass friendClass; jmethodID friendCtrId; + jclass addressClass; + jmethodID addressCtrId; + LinphoneCoreVTable vTable; static void showInterfaceCb(LinphoneCore *lc) { @@ -279,7 +285,7 @@ public: ,lcData->textReceivedId ,lcData->core ,env->NewObject(lcData->chatRoomClass,lcData->chatRoomCtrId,(jlong)room) - ,env->NewObject(lcData->friendClass,lcData->friendCtrId,(jlong)from) + ,env->NewObject(lcData->addressClass,lcData->addressCtrId,(jlong)from) ,message ? env->NewStringUTF(message) : NULL); } From 7db8fc8c965d7c482bec62d84c8030469f2fdef3 Mon Sep 17 00:00:00 2001 From: Guillaume Beraudo Date: Fri, 5 Nov 2010 17:29:11 +0100 Subject: [PATCH 22/27] Added some comments. --- .../core/tutorials/TutorialBuddyStatus.java | 33 ++++++++++++------- .../core/tutorials/TutorialChatRoom.java | 7 ++-- .../core/tutorials/TutorialHelloWorld.java | 3 +- .../core/tutorials/TutorialNotifier.java | 25 ++++++++++++++ .../core/tutorials/TutorialRegistration.java | 16 ++++++--- 5 files changed, 63 insertions(+), 21 deletions(-) diff --git a/coreapi/help/java/org/linphone/core/tutorials/TutorialBuddyStatus.java b/coreapi/help/java/org/linphone/core/tutorials/TutorialBuddyStatus.java index f85cf88f8..25dae37d7 100644 --- a/coreapi/help/java/org/linphone/core/tutorials/TutorialBuddyStatus.java +++ b/coreapi/help/java/org/linphone/core/tutorials/TutorialBuddyStatus.java @@ -1,7 +1,6 @@ /* -linphone +TutorialBuddyStatus Copyright (C) 2010 Belledonne Communications SARL - (simon.morlat@linphone.org) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -66,10 +65,11 @@ public class TutorialBuddyStatus implements LinphoneCoreListener { public void newSubscriptionRequest(LinphoneCore lc, LinphoneFriend lf,String url) { write("["+lf.getAddress().getUserName()+"] wants to see your status, accepting"); - lf.edit(); - lf.setIncSubscribePolicy(SubscribePolicy.SPAccept); - lf.done(); + lf.edit(); // start editing friend + lf.setIncSubscribePolicy(SubscribePolicy.SPAccept); // accept incoming subscription request for this friend + lf.done(); // commit change try { + // add this new friend to the buddy list lc.addFriend(lf); } catch (LinphoneCoreException e) { write("Error while adding friend [" + lf.getAddress().getUserName() + "] to linphone in the callback"); @@ -104,6 +104,7 @@ public class TutorialBuddyStatus implements LinphoneCoreListener { // Create tutorial object TutorialBuddyStatus tutorial = new TutorialBuddyStatus(); try { + // takes sip uri identity from the command line arguments String userSipAddress = args[1]; tutorial.launchTutorial(userSipAddress); } catch (Exception e) { @@ -123,29 +124,34 @@ public class TutorialBuddyStatus implements LinphoneCoreListener { try { - // Create friend address + // Create friend object from string address LinphoneFriend lf = lcFactory.createLinphoneFriend(sipAddress); if (lf == null) { write("Could not create friend; weird SIP address?"); return; } + // configure this friend to emit SUBSCRIBE message after being added to LinphoneCore lf.enableSubscribes(true); + + // accept incoming subscription request for this friend lf.setIncSubscribePolicy(SubscribePolicy.SPAccept); try { + // add my friend to the buddy list, initiate SUBSCRIBE message lc.addFriend(lf); } catch (LinphoneCoreException e) { write("Error while adding friend " + lf.getAddress().getUserName() + " to linphone"); + return; } - + // set my status to online lc.setPresenceInfo(0, null, OnlineStatus.Online); // main loop for receiving notifications and doing background linphonecore work running = true; while (running) { - lc.iterate(); + lc.iterate(); // first iterate initiates subscription try{ Thread.sleep(50); } catch(InterruptedException ie) { @@ -155,13 +161,16 @@ public class TutorialBuddyStatus implements LinphoneCoreListener { } + // change my presence status to offline lc.setPresenceInfo(0, null, OnlineStatus.Offline); + // just to make sure new status is initiate message is issued lc.iterate(); - lf.edit(); - lf.enableSubscribes(false); - lf.done(); - lc.iterate(); + + lf.edit(); // start editing friend + lf.enableSubscribes(false); // disable subscription for this friend + lf.done(); // commit changes triggering an UNSUBSCRIBE message + lc.iterate(); // just to make sure unsubscribe message is issued } finally { diff --git a/coreapi/help/java/org/linphone/core/tutorials/TutorialChatRoom.java b/coreapi/help/java/org/linphone/core/tutorials/TutorialChatRoom.java index ff6787439..8b8fd341b 100644 --- a/coreapi/help/java/org/linphone/core/tutorials/TutorialChatRoom.java +++ b/coreapi/help/java/org/linphone/core/tutorials/TutorialChatRoom.java @@ -1,7 +1,6 @@ /* -linphone +TutorialChatRoom.java Copyright (C) 2010 Belledonne Communications SARL - (simon.morlat@linphone.org) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -85,6 +84,7 @@ public class TutorialChatRoom implements LinphoneCoreListener { public static void main(String[] args) { // Check tutorial was called with the right number of arguments + // Takes the sip uri identity from the command line arguments if (args.length != 1) { throw new IllegalArgumentException("Bad number of arguments"); } @@ -108,7 +108,10 @@ public class TutorialChatRoom implements LinphoneCoreListener { LinphoneCore lc = LinphoneCoreFactory.instance().createLinphoneCore(this); try { + // Next step is to create a chat room LinphoneChatRoom chatRoom = lc.createChatRoom(destinationSipAddress); + + // Send message chatRoom.sendMessage("Hello world"); // main loop for receiving notifications and doing background linphonecore work diff --git a/coreapi/help/java/org/linphone/core/tutorials/TutorialHelloWorld.java b/coreapi/help/java/org/linphone/core/tutorials/TutorialHelloWorld.java index e116c3523..12451c940 100644 --- a/coreapi/help/java/org/linphone/core/tutorials/TutorialHelloWorld.java +++ b/coreapi/help/java/org/linphone/core/tutorials/TutorialHelloWorld.java @@ -1,7 +1,6 @@ /* -linphone +TutorialHelloWorld.java Copyright (C) 2010 Belledonne Communications SARL - (simon.morlat@linphone.org) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/coreapi/help/java/org/linphone/core/tutorials/TutorialNotifier.java b/coreapi/help/java/org/linphone/core/tutorials/TutorialNotifier.java index c8138214c..62a540267 100644 --- a/coreapi/help/java/org/linphone/core/tutorials/TutorialNotifier.java +++ b/coreapi/help/java/org/linphone/core/tutorials/TutorialNotifier.java @@ -1,5 +1,30 @@ +/* +TutorialNotifier.java +Copyright (C) 2010 Belledonne Communications SARL + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ package org.linphone.core.tutorials; +/** + * Notify to the standard output. + * Subclass to define another text output. + * + * @author Guillaume Beraudo + * + */ public class TutorialNotifier { public void notify(String s) { diff --git a/coreapi/help/java/org/linphone/core/tutorials/TutorialRegistration.java b/coreapi/help/java/org/linphone/core/tutorials/TutorialRegistration.java index 0f72594f8..08e3c4ea3 100644 --- a/coreapi/help/java/org/linphone/core/tutorials/TutorialRegistration.java +++ b/coreapi/help/java/org/linphone/core/tutorials/TutorialRegistration.java @@ -1,7 +1,6 @@ /* -linphone +TutorialRegistration.java Copyright (C) 2010 Belledonne Communications SARL - (simon.morlat@linphone.org) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -93,7 +92,9 @@ public class TutorialRegistration implements LinphoneCoreListener { // Create tutorial object TutorialRegistration tutorial = new TutorialRegistration(); try { + // takes sip uri identity from the command line arguments String userSipAddress = args[1]; + // takes password from the command line arguments String userSipPassword = args[2]; tutorial.launchTutorial(userSipAddress, userSipPassword); } catch (Exception e) { @@ -113,16 +114,20 @@ public class TutorialRegistration implements LinphoneCoreListener { try { + // Parse identity LinphoneAddress address = lcFactory.createLinphoneAddress(sipAddress); String username = address.getUserName(); String domain = address.getDomain(); + if (password != null) { + // create authentication structure from identity and add to linphone lc.addAuthInfo(lcFactory.createAuthInfo(username, password, null)); } - + + // create proxy config LinphoneProxyConfig proxyCfg = lcFactory.createProxyConfig(sipAddress, domain, null, true); - lc.addProxyConfig(proxyCfg); + lc.addProxyConfig(proxyCfg); // add it to linphone lc.setDefaultProxyConfig(proxyCfg); @@ -131,7 +136,7 @@ public class TutorialRegistration implements LinphoneCoreListener { // main loop for receiving notifications and doing background linphonecore work running = true; while (running) { - lc.iterate(); + lc.iterate(); // first iterate initiates registration try{ Thread.sleep(50); } catch(InterruptedException ie) { @@ -141,6 +146,7 @@ public class TutorialRegistration implements LinphoneCoreListener { } + // Automatic unregistration on exit } finally { From 57a2bde8a22d52a8aa8d3bffeb18c8ebe88a4b5c Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Fri, 12 Nov 2010 09:03:10 +0100 Subject: [PATCH 23/27] implement enable video call java binding --- coreapi/linphonecore_jni.cc | 14 ++++++++++++ .../org/linphone/core/LinphoneCore.java | 22 +++++++++++++++++-- .../common/org/linphone/core/VideoWindow.java | 5 ----- mediastreamer2 | 2 +- 4 files changed, 35 insertions(+), 8 deletions(-) delete mode 100644 java/common/org/linphone/core/VideoWindow.java diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index d22edef61..cf2a99c06 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -562,6 +562,20 @@ extern "C" long Java_org_linphone_core_LinphoneCoreImpl_createChatRoom(JNIEnv* return (long)lResult; } +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_enableVideo(JNIEnv* env + ,jobject thiz + ,jlong lc + ,jboolean vcap_enabled + ,jboolean display_enabled) { + linphone_core_enable_video((LinphoneCore*)lc, vcap_enabled,display_enabled); + +} +extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_isVideoEnabled(JNIEnv* env + ,jobject thiz + ,jlong lc) { + return linphone_core_video_enabled((LinphoneCore*)lc); +} + //ProxyConfig extern "C" jlong Java_org_linphone_core_LinphoneProxyConfigImpl_newLinphoneProxyConfig(JNIEnv* env,jobject thiz) { diff --git a/java/common/org/linphone/core/LinphoneCore.java b/java/common/org/linphone/core/LinphoneCore.java index 655f95f4d..e9471201d 100644 --- a/java/common/org/linphone/core/LinphoneCore.java +++ b/java/common/org/linphone/core/LinphoneCore.java @@ -372,6 +372,24 @@ public interface LinphoneCore { */ LinphoneChatRoom createChatRoom(String to); - public void setVideoWindow(VideoWindow w); - public void setPreviewWindow(VideoWindow w); + public void setVideoWindow(Object w); + public void setPreviewWindow(Object w); + /** + * Enables video globally. + * + * + * This function does not have any effect during calls. It just indicates #LinphoneCore to + * initiate future calls with video or not. The two boolean parameters indicate in which + * direction video is enabled. Setting both to false disables video entirely. + * + * @param vcap_enabled indicates whether video capture is enabled + * @param display_enabled indicates whether video display should be shown + * + **/ + void enableVideo(boolean vcap_enabled, boolean display_enabled); + /** + * Returns TRUE if video is enabled, FALSE otherwise. + * + ***/ + boolean isVideoEnabled(); } diff --git a/java/common/org/linphone/core/VideoWindow.java b/java/common/org/linphone/core/VideoWindow.java deleted file mode 100644 index d4a46b931..000000000 --- a/java/common/org/linphone/core/VideoWindow.java +++ /dev/null @@ -1,5 +0,0 @@ -package org.linphone.core; - -public interface VideoWindow { - -} diff --git a/mediastreamer2 b/mediastreamer2 index ffacf5671..e59157a44 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit ffacf56718c198cb80a290f7a65975916d8a9b6b +Subproject commit e59157a44a7b6aa1f1fa756325047e98c2be3786 From f86a75c0e1a7906efe725eada21c609d104c6c92 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Fri, 12 Nov 2010 10:10:26 +0100 Subject: [PATCH 24/27] fix java linphone core creation without configuration file --- coreapi/linphonecore_jni.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index cf2a99c06..e0a7f3e7e 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -298,8 +298,8 @@ extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_newLinphoneCore(JNIEnv* ,jstring jfactoryConfig ,jobject juserdata){ - const char* userConfig = env->GetStringUTFChars(juserConfig, NULL); - const char* factoryConfig = env->GetStringUTFChars(jfactoryConfig, NULL); + const char* userConfig = juserConfig?env->GetStringUTFChars(juserConfig, NULL):NULL; + const char* factoryConfig = jfactoryConfig?env->GetStringUTFChars(jfactoryConfig, NULL):NULL; LinphoneCoreData* ldata = new LinphoneCoreData(env,thiz,jlistener,juserdata); #ifdef ANDROID ms_andsnd_set_jvm(jvm); @@ -317,8 +317,8 @@ extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_newLinphoneCore(JNIEnv* //clear existing proxy config linphone_core_clear_proxy_config((LinphoneCore*) nativePtr); - env->ReleaseStringUTFChars(juserConfig, userConfig); - env->ReleaseStringUTFChars(jfactoryConfig, factoryConfig); + if (userConfig) env->ReleaseStringUTFChars(juserConfig, userConfig); + if (factoryConfig) env->ReleaseStringUTFChars(jfactoryConfig, factoryConfig); return nativePtr; } extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_delete(JNIEnv* env From 08d2ce9ea48555cdf18c55be7293ecae26c208b0 Mon Sep 17 00:00:00 2001 From: Guillaume Beraudo Date: Fri, 12 Nov 2010 10:27:59 +0100 Subject: [PATCH 25/27] Set jvm into Android mediastreamer filter code, when VIDEO is enabled. --- coreapi/linphonecore_jni.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index d22edef61..821eee5d1 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -24,6 +24,8 @@ extern "C" void libmsilbc_init(); #endif /*ANDROID*/ extern "C" void ms_andsnd_set_jvm(JavaVM *jvm) ; +extern "C" void ms_andvid_set_jvm(JavaVM *jvm) ; + static JavaVM *jvm=0; #ifdef ANDROID @@ -45,6 +47,9 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *ajvm, void *reserved) { #ifdef ANDROID ms_andsnd_set_jvm(ajvm); + #ifdef VIDEO_ENABLED + ms_andvid_set_jvm(ajvm); + #endif /*VIDEO_ENABLED*/ #endif /*ANDROID*/ jvm=ajvm; return JNI_VERSION_1_2; From efb8785585bbaf3cf0836a869ba48c03041fad74 Mon Sep 17 00:00:00 2001 From: Guillaume Beraudo Date: Fri, 12 Nov 2010 14:10:05 +0100 Subject: [PATCH 26/27] Added stub for setWindowVideoId --- coreapi/linphonecore_jni.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index b339327e0..43ce05449 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -943,3 +943,8 @@ extern "C" void Java_org_linphone_core_LinphoneChatRoomImpl_sendMessage(JNIEnv* } +// FIXME stubb function +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setVideoWindowId(JNIEnv* env + ,jobject thiz + ,jobject obj) { +} \ No newline at end of file From 56fc713be72527f1559e6bc52b1aad5e219e0be9 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 12 Nov 2010 19:40:15 +0100 Subject: [PATCH 27/27] android display works --- build/android/Android.mk | 2 +- coreapi/linphonecore.c | 7 +++++++ coreapi/linphonecore_jni.cc | 9 +++++++++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/build/android/Android.mk b/build/android/Android.mk index c0e8df8a2..6b9dc85c1 100755 --- a/build/android/Android.mk +++ b/build/android/Android.mk @@ -70,7 +70,7 @@ LOCAL_C_INCLUDES += \ $(LOCAL_PATH)/../../externals/exosip/include \ $(LOCAL_PATH)/../../externals/osip/include -LOCAL_LDLIBS += -llog +LOCAL_LDLIBS += -llog -ldl LOCAL_STATIC_LIBRARIES := \ libmediastreamer2 \ diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index e6e8d99f2..6ceb9b127 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3333,7 +3333,13 @@ unsigned long linphone_core_get_native_video_window_id(const LinphoneCore *lc){ * If not set the core will create its own window. **/ void linphone_core_set_native_video_window_id(LinphoneCore *lc, unsigned long id){ +#ifdef VIDEO_ENABLED + LinphoneCall *call=linphone_core_get_current_call(lc); lc->video_window_id=id; + if (call!=NULL && call->videostream){ + video_stream_set_native_window_id(call->videostream,id); + } +#endif } /** @@ -4034,3 +4040,4 @@ const char *linphone_error_to_string(LinphoneReason err){ } return "unknown error"; } + diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index b339327e0..029cb30bc 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -943,3 +943,12 @@ extern "C" void Java_org_linphone_core_LinphoneChatRoomImpl_sendMessage(JNIEnv* } +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setVideoWindowId(JNIEnv* env + ,jobject thiz + ,jlong lc + ,jobject obj) { + linphone_core_set_native_video_window_id((LinphoneCore*)lc,(unsigned long)obj); + ms_message("linphone_core_set_native_video_window_id() called !!!!!!!"); +} + +