Commit 0267c321 authored by Simon Morlat's avatar Simon Morlat
Browse files

work in progress

parent 80e14f6a
......@@ -21,7 +21,6 @@ liblinphone_la_SOURCES=\
sal_eXosip2_sdp.c \
sal_eXosip2_presence.c \
callbacks.c \
exevents.c sdphandler.c\
misc.c \
address.c \
enum.c enum.h \
......
......@@ -23,28 +23,301 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "linphonecore.h"
#include "private.h"
static void linphone_connect_incoming(LinphoneCore *lc, LinphoneCall *call){
if (lc->vtable.show)
lc->vtable.show(lc);
if (lc->vtable.display_status)
lc->vtable.display_status(lc,_("Connected."));
call->state=LCStateAVRunning;
if (lc->ringstream!=NULL){
ring_stop(lc->ringstream);
lc->ringstream=NULL;
}
linphone_core_start_media_streams(lc,call);
}
static void call_received(SalOp *h){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_root(h));
char *barmesg;
int err;
LinphoneCall *call;
const char *from,*to;
char *tmp;
LinphoneAddress *from_parsed;
/* first check if we can answer successfully to this invite */
if (lc->presence_mode!=LINPHONE_STATUS_ONLINE){
ms_message("Not present !! presence mode : %d\n",lc->presence_mode);
if (lc->presence_mode==LINPHONE_STATUS_BUSY)
sal_call_decline(h,SalReasonBusy,NULL);
else if (lc->presence_mode==LINPHONE_STATUS_AWAY
||lc->presence_mode==LINPHONE_STATUS_BERIGHTBACK
||lc->presence_mode==LINPHONE_STATUS_ONTHEPHONE
||lc->presence_mode==LINPHONE_STATUS_OUTTOLUNCH
||lc->presence_mode==LINPHONE_STATUS_OFFLINE)
sal_call_decline(h,SalReasonTemporarilyUnavailable,NULL);
else if (lc->presence_mode==LINPHONE_STATUS_NOT_DISTURB)
sal_call_decline(h,SalReasonTemporarilyUnavailable,NULL);
else if (lc->alt_contact!=NULL && lc->presence_mode==LINPHONE_STATUS_MOVED)
sal_call_decline(h,SalReasonRedirect,lc->alt_contact);
else
sal_call_decline(h,SalReasonBusy,NULL);
sal_op_release(op);
return;
}
if (lc->call!=NULL){/*busy*/
sal_call_decline(h,SalReasonBusy,NULL);
sal_op_release(op);
return;
}
from=sal_op_get_from(op);
to=sal_op_get_to(op);
call=linphone_call_new_incoming(lc,linphone_address_new(from),linphone_address_new(to),op);
lc->call=call;
sal_call_set_local_media_description(op,call->localdesc);
call->resultdesc=sal_call_get_final_media_description(op);
if (call->resultdesc && sal_media_description_empty(call->resultdesc){
sal_call_decline(op,SalReasonMedia,NULL);
linphone_call_destroy(call);
lc->call=NULL;
return;
}
from_parsed=linphone_address_new(sal_op_get_from(op));
linphone_address_clean(from_parsed);
tmp=linphone_address_as_string(from_parsed);
linphone_address_destroy(from_parsed);
gstate_new_state(lc, GSTATE_CALL_IN_INVITE, tmp);
barmesg=ortp_strdup_printf("%s %s",tmp,_("is contacting you."));
if (lc->vtable.show) lc->vtable.show(lc);
if (lc->vtable.display_status)
lc->vtable.display_status(lc,barmesg);
/* play the ring */
if (lc->sound_conf.ring_sndcard!=NULL){
ms_message("Starting local ring...");
lc->ringstream=ring_start(lc->sound_conf.local_ring,2000,lc->sound_conf.ring_sndcard);
}
linphone_call_set_state(call,LCStateRinging);
sal_call_notify_ringing(op);
if (lc->vtable.inv_recv) lc->vtable.inv_recv(lc,tmp);
ms_free(barmesg);
ms_free(tmp);
}
static void call_ringing(SalOp *h){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_root(h));
LinphoneCall *call=lc->call;
SalMediaDescription *md;
if (call==NULL) return;
if (lc->vtable.display_status)
lc->vtable.display_status(lc,_("Remote ringing."));
md=sal_call_get_final_media_description(h);
if (md==NULL){
if (lc->ringstream!=NULL) return; /*already ringing !*/
if (lc->sound_conf.play_sndcard!=NULL){
ms_message("Remote ringing...");
lc->ringstream=ring_start(lc->sound_conf.remote_ring,2000,lc->sound_conf.play_sndcard);
}
}else{
/*accept early media */
if (lc->audiostream->ticker!=NULL){
/*streams already started */
ms_message("Early media already started.");
return;
}
sal_media_description_ref(md);
call->resultdesc=md;
if (lc->vtable.show) lc->vtable.show(lc);
if (lc->vtable.display_status)
lc->vtable.display_status(lc,_("Early media."));
gstate_new_state(lc, GSTATE_CALL_OUT_CONNECTED, NULL);
if (lc->ringstream!=NULL){
ring_stop(lc->ringstream);
lc->ringstream=NULL;
}
ms_message("Doing early media...");
linphone_core_start_media_streams(lc,call);
}
call->state=LCStateRinging;
}
static void call_accepted(SalOp *h){
static void call_accepted(SalOp *op){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_root(h));
LinphoneCall *call=lc->call;
if (call==NULL){
ms_warning("No call to accept.");
return 0;
}
if (sal_op_get_user_pointer(op)!=lc->call){
ms_warning("call_accepted: ignoring.");
return;
}
if (call->state==LCStateAVRunning){
return 0; /*already accepted*/
}
if (lc->audiostream->ticker!=NULL){
/*case where we accepted early media */
linphone_core_stop_media_streams(lc,call);
linphone_core_init_media_streams(lc,call);
}
if (call->resultdesc)
sal_media_description_unref(call->resultdesc);
call->resultdesc=sal_call_get_final_media_description(op);
if (call->resultdesc && !sal_media_description_empty(call->resultdesc)){
gstate_new_state(lc, GSTATE_CALL_OUT_CONNECTED, NULL);
linphone_connect_incoming(lc,call);
}else{
/*send a bye*/
ms_error("Incompatible SDP offer received in 200Ok, need to abort the call");
linphone_core_terminate_call(lc,NULL);
}
}
static void call_ack(SalOp *h){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_root(h));
LinphoneCall *call=lc->call;
if (call==NULL){
ms_warning("No call to be ACK'd");
return ;
}
if (sal_op_get_user_pointer(op)!=lc->call){
ms_warning("call_ack: ignoring.");
return;
}
if (lc->audiostream->ticker!=NULL){
/*case where we accepted early media */
linphone_core_stop_media_streams(lc,call);
linphone_core_init_media_streams(lc,call);
}
if (call->resultdesc)
sal_media_description_unref(call->resultdesc);
call->resultdesc=sal_call_get_final_media_description(op);
if (call->resultdesc && !sal_media_description_empty(call->resultdesc)){
gstate_new_state(lc, GSTATE_CALL_IN_CONNECTED, NULL);
linphone_connect_incoming(lc,call);
}else{
/*send a bye*/
ms_error("Incompatible SDP response received in ACK, need to abort the call");
linphone_core_terminate_call(lc,NULL);
}
}
static void call_updated(SalOp *){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_root(h));
linphone_core_stop_media_streams(lc,call);
linphone_core_init_media_streams(lc,call);
if (call->resultdesc)
sal_media_description_unref(call->resultdesc);
call->resultdesc=sal_call_get_final_media_description(op);
if (call->resultdesc && !sal_media_description_empty(call->resultdesc)){
linphone_connect_incoming(lc,call);
}
}
static void call_terminated(SalOp *h){
static void call_terminated(SalOp *h, const char *from){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_root(h));
if (sal_op_get_user_pointer(op)!=lc->call){
ms_warning("call_terminated: ignoring.");
return;
}
ms_message("Current call terminated...");
if (lc->ringstream!=NULL) {
ring_stop(lc->ringstream);
lc->ringstream=NULL;
}
linphone_core_stop_media_streams(lc,lc->call);
lc->vtable.show(lc);
lc->vtable.display_status(lc,_("Call terminated."));
gstate_new_state(lc, GSTATE_CALL_END, NULL);
if (lc->vtable.bye_recv!=NULL){
LinphoneAddress *addr=linphone_address_new(from);
char *tmp;
linphone_address_clean(addr);
tmp=linphone_address_as_string(from);
lc->vtable.bye_recv(lc,tmp);
ms_free(tmp);
linphone_address_destroy(addr);
}
linphone_call_destroy(lc->call);
lc->call=NULL;
}
static void call_failure(SalOp *h, SalError error, SalReason reason, const char *details){
static void call_failure(SalOp *op, SalError error, SalReason sr, const char *details){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_root(h));
const char *reason="";
char *msg486=_("User is busy.");
char *msg480=_("User is temporarily unavailable.");
/*char *retrymsg=_("%s. Retry after %i minute(s).");*/
char *msg600=_("User does not want to be disturbed.");
char *msg603=_("Call declined.");
char* tmpmsg=msg486;
int code;
LinphoneCall *call=lc->call;
if (sal_op_get_user_pointer(op)!=lc->call){
ms_warning("call_failure: ignoring.");
return;
}
if (lc->vtable.show) lc->vtable.show(lc);
if (error==SalErrorNoResponse){
if (lc->vtale.display_status)
lc->vtable.display_status(lc,_("No response."));
}else if (error==SalErrorProtocol){
if (lc->vtale.display_status)
lc->vtable.display_status(lc, details ? details : _("Error."));
}else if (error==SalErrorFailure){
switch(sr){
case SalReasonDeclined:
if (lc->vtable.display_status)
lc->vtable.display_status(lc,msg603);
break;
case SalReasonBusy:
if (lc->vtable.display_status)
lc->vtable.display_status(lc,msg486);
break;
case SalReasonRedirect:
if (lc->vtable.display_status)
lc->vtable.display_status(lc,_("Redirected"));
break;
case SalReasonTemporarilyUnavailable:
if (lc->vtable.display_status)
lc->vtable.display_status(lc,msg480);
break;
case SalReasonNotFound:
if (lc->vtable.display_status)
lc->vtable.display_status(lc,msg404);
break;
case SalReasonDoNotDisturb:
if (lc->vtable.display_status)
lc->vtable.display_status(lc,msg600);
break;
case SalReasonMedia:
if (lc->vtable.display_status)
lc->vtable.display_status(lc,_("No common codecs"));
break;
default:
if (lc->vtable.display_status)
lc->vtable.display_status(lc,_("Call failed."));
}
}
if (lc->ringstream!=NULL) {
ring_stop(lc->ringstream);
lc->ringstream=NULL;
}
linphone_core_stop_media_streams(lc);
if (call!=NULL) {
linphone_call_destroy(call);
gstate_new_state(lc, GSTATE_CALL_ERROR, NULL);
lc->call=NULL;
}
}
static void auth_requested(SalOp *h, const char *realm, const char *username){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_root(h));
LinphoneAuthInfo *ai=linphone_core_find_auth_info(lc);
}
static void auth_success(SalOp *h, const char *realm, const char *username){
......
This diff is collapsed.
......@@ -67,7 +67,8 @@ typedef struct _LinphoneCall
SalMediaDescription *localdesc;
SalMediaDescription *resultdesc;
LinphoneCallDir dir;
struct _RtpProfile *profile; /*points to the local_profile or to the remote "guessed" profile*/
struct _RtpProfile *audio_profile;
struct _RtpProfile *video_profile;
struct _LinphoneCallLog *log;
SalOp *op;
char localip[LINPHONE_IPADDR_SIZE]; /* our best guess for local ipaddress for this call */
......@@ -87,7 +88,7 @@ void linphone_call_log_completed(LinphoneCallLog *calllog, LinphoneCall *call);
void linphone_call_log_destroy(LinphoneCallLog *cl);
void linphone_core_init_media_streams(LinphoneCore *lc);
void linphone_core_init_media_streams(LinphoneCore *lc, LinphoneCall *call);
void linphone_auth_info_write_config(struct _LpConfig *config, LinphoneAuthInfo *obj, int pos);
......@@ -112,8 +113,8 @@ bool_t host_has_ipv6_network();
bool_t lp_spawn_command_line_sync(const char *command, char **result,int *command_ret);
static inline int get_min_bandwidth(int dbw, int ubw){
if (dbw<0) return ubw;
if (ubw<0) return dbw;
if (dbw<=0) return ubw;
if (ubw<=0) return dbw;
return MIN(dbw,ubw);
}
......@@ -165,7 +166,7 @@ int linphone_proxy_config_normalize_number(LinphoneProxyConfig *cfg, const char
/*internal use only */
void linphone_core_start_media_streams(LinphoneCore *lc, struct _LinphoneCall *call);
void linphone_core_stop_media_streams(LinphoneCore *lc);
void linphone_core_stop_media_streams(LinphoneCore *lc, struct _LinphoneCall *call);
const char * linphone_core_get_identity(LinphoneCore *lc);
const char * linphone_core_get_route(LinphoneCore *lc);
bool_t linphone_core_interpret_url(LinphoneCore *lc, const char *url, LinphoneAddress **real_parsed_url, char **route);
......
......@@ -28,6 +28,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
SalMediaDescription *sal_media_description_new(){
SalMediaDescription *md=ms_new0(SalMediaDescription,1);
md->refcount=1;
return md;
}
static void sal_media_description_destroy(SalMediaDescription *md){
......@@ -60,6 +61,14 @@ SalStreamDescription *sal_media_description_find_stream(SalMediaDescription *md,
return NULL;
}
bool_t sal_media_description_empty(SalMediaDescription *md){
int i;
for(i=0;i<md->nstreams;++i){
SalStreamDescription *ss=&md->streams[i];
if (ss->port!=0) return FALSE;
}
return TRUE;
}
static void assign_string(char **str, const char *arg){
if (*str){
......
......@@ -62,6 +62,8 @@ void sal_address_destroy(SalAddress *u);
Sal * sal_init();
void sal_uninit(Sal* sal);
void sal_set_user_pointer(Sal *sal, void *user_data);
void *sal_get_user_pointer(const Sal *sal);
typedef enum {
SalTransportDatagram,
......@@ -103,6 +105,7 @@ typedef struct SalMediaDescription{
SalMediaDescription *sal_media_description_new();
void sal_media_description_ref(SalMediaDescription *md);
void sal_media_description_unref(SalMediaDescription *md);
bool_t sal_media_description_empty(SalMediaDescription *md);
SalStreamDescription *sal_media_description_find_stream(SalMediaDescription *md,
SalMediaProto proto, SalStreamType type);
......@@ -121,7 +124,7 @@ typedef struct SalOpBase{
typedef enum SalError{
SalErrorNoResponse,
SalErrorMedia,
SalErrorProtocol,
SalErrorFailure, /* see SalReason for more details */
SalErrorUnknown
} SalError;
......@@ -133,6 +136,7 @@ typedef enum SalReason{
SalReasonTemporarilyUnavailable,
SalReasonNotFound,
SalReasonDoNotDisturb,
SalReasonMedia,
SalReasonForbidden,
SalReasonUnknown
}SalReason;
......@@ -155,7 +159,7 @@ typedef void (*SalOnCallRinging)(SalOp *op);
typedef void (*SalOnCallAccepted)(SalOp *op);
typedef void (*SalOnCallAck)(SalOp *op);
typedef void (*SalOnCallUpdated)(SalOp *op);
typedef void (*SalOnCallTerminated)(SalOp *op);
typedef void (*SalOnCallTerminated)(SalOp *op, const char *from);
typedef void (*SalOnCallFailure)(SalOp *op, SalError error, SalReason reason, const char *details);
typedef void (*SalOnAuthRequested)(SalOp *op, const char *realm, const char *username);
typedef void (*SalOnAuthSuccess)(SalOp *op, const char *realm, const char *username);
......@@ -200,6 +204,7 @@ typedef struct SalAuthInfo{
void sal_set_callbacks(Sal *ctx, const SalCallbacks *cbs);
int sal_listen_port(Sal *ctx, const char *addr, int port, SalTransport tr, int is_secure);
void sal_set_user_agent(Sal *ctx, const char *user_agent);
void sal_masquerade(Sal *ctx, const char *ip);
void sal_use_session_timers(Sal *ctx, int expires);
int sal_iterate(Sal *sal);
......@@ -223,9 +228,12 @@ void *sal_op_get_user_pointer(const SalOp *op);
/*Call API*/
int sal_call_set_local_media_description(SalOp *h, SalMediaDescription *desc);
int sal_call(SalOp *h, const char *from, const char *to);
int sal_call_notify_ringing(SalOp *h);
int sal_call_accept(SalOp*h);
int sal_call_decline(SalOp *h, SalReason reason, const char *redirection /*optional*/);
const SalMediaDescription * sal_call_get_final_media_description(SalOp *h);
SalMediaDescription * sal_call_get_final_media_description(SalOp *h);
int sal_refer(SalOp *h, const char *refer_to);
int sal_call_send_dtmf(SalOp *h, char dtmf);
int sal_call_terminate(SalOp *h);
/*Registration*/
......
......@@ -134,6 +134,18 @@ void sal_uninit(Sal* sal){
ms_free(sal);
}
void sal_set_user_pointer(Sal *sal, void *user_data){
sal->up=user_data;
}
void *sal_get_user_pointer(const Sal *sal){
return sal->up;
}
void sal_masquerade(Sal *ctx, const char *ip){
eXosip_set_option(EXOSIP_OPT_SET_IPV4_FOR_GATEWAY,ip);
}
static void unimplemented_stub(){
ms_warning("Unimplemented SAL callback");
}
......@@ -293,8 +305,16 @@ int sal_call(SalOp *h, const char *from, const char *to){
return 0;
}
int sal_call_notify_ringing(SalOp *h){
eXosip_lock();
eXosip_call_send_answer(h->tid,180,NULL);
eXosip_unlock();
return 0;
}
int sal_call_accept(SalOp * h){
osip_message_t *msg;
const char *contact=sal_op_get_contact(h);
/* sends a 200 OK */
int err=eXosip_call_build_answer(h->tid,200,&msg);
if (err<0 || msg==NULL){
......@@ -304,6 +324,8 @@ int sal_call_accept(SalOp * h){
if (h->base.root->session_expires!=0){
if (h->supports_session_timers) osip_message_set_supported(msg, "timer");
}
if (contact) osip_message_set_contact(msg,contact);
if (h->base.local_media){
/*this is the case where we received an invite without SDP*/
......@@ -320,18 +342,80 @@ int sal_call_accept(SalOp * h){
return 0;
}
const SalMediaDescription * sal_call_get_final_media_description(SalOp *h){
int sal_call_decline(SalOp *h, SalReason reason, const char *redirect){
if (reason==SalReasonBusy){
eXosip_lock();
eXosip_call_send_answer(h->tid,486,NULL);
eXosip_unlock();
}
else if (reason==SalReasonTemporarilyUnavailable){
eXosip_lock();
eXosip_call_send_answer(h->tid,480,NULL);
eXosip_unlock();
}else if (reason==SalReasonDoNotDisturb){
eXosip_lock();
eXosip_call_send_answer(h->tid,600,NULL);
eXosip_unlock();
}else if (reason==SalReasonMedia){
eXosip_lock();
eXosip_call_send_answer(h->tid,415,NULL);
eXosip_unlock();
}else if (redirect!=NULL && reason==SalReasonRedirect){
osip_message_t *msg;
int code;
if (strstr(redirect,"sip:")!=0) code=302;
else code=380;
eXosip_lock();
eXosip_call_build_answer(h->tid,code,&msg);
osip_message_set_contact(msg,redirect);
eXosip_call_send_answer(h->tid,code,msg);
eXosip_unlock();
}else sal_call_terminate(h);
return 0;
}
SalMediaDescription * sal_call_get_final_media_description(SalOp *h){
if (h->base.local_media && h->base.remote_media && !h->result){
sdp_process(h);
}
return h->result;
}
int sal_refer(SalOp *h, const char *refer_to){
osip_message_t *msg=NULL;
int err=0;
eXosip_lock();
eXosip_call_build_refer(h->did,refer_to, &msg);
if (msg) err=eXosip_call_send_request(h->did, msg);
else err=-1;
eXosip_unlock();
return err;
}
int sal_call_send_dtmf(SalOp *h, char dtmf){
osip_message_t *msg=NULL;
char dtmf_body[128];
char clen[10];
eXosip_lock();
eXosip_call_build_info(h->did,&msg);
if (msg){
snprintf(dtmf_body, sizeof(dtmf_body), "Signal=%c\r\nDuration=250\r\n", dtmf);
osip_message_set_body(msg,dtmf_body,strlen(dtmf_body));
osip_message_set_content_type(msg,"application/dtmf-relay");
snprintf(clen,sizeof(clen),"%lu",(unsigned long)strlen(dtmf_body));
osip_message_set_content_length(msg,clen);
eXosip_call_send_request(h->did,msg);
}
eXosip_unlock();
return 0;
}
int sal_call_terminate(SalOp *h){
eXosip_lock();
eXosip_call_terminate(h->cid,h->did);
eXosip_unlock();
eXosip_call_set_reference(h->cid,NULL);
eXosip_unlock();
return 0;
}
......@@ -494,13 +578,17 @@ static void call_accepted(Sal *sal, eXosip_event_t *ev){
static void call_terminated(Sal *sal, eXosip_event_t *ev){
SalOp *op;
char *from;
op=(SalOp*)ev->external_reference;
if (op==NULL){
ms_warning("Call terminated for already closed call ?");
return;
}
osip_from_to_str(ev->request->from,&from);
eXosip_call_set_reference(ev->cid,NULL);
sal->callbacks.call_terminated(op);
op->cid=-1;
sal->callbacks.call_terminated(op,from);
osip_free(from);
}
static void call_released(Sal *sal, eXosip_event_t *ev){
......@@ -510,7 +598,7 @@ static void call_released(Sal *sal, eXosip_event_t *ev){
return;
}
eXosip_call_set_reference(ev->cid,NULL);
sal->callbacks.call_terminated(op);
/*sal->callbacks.call_terminated(op);*/
}
static int get_auth_data(eXosip_event_t *ev, const char **realm, const char **username){
......@@ -600,7 +688,8 @@ static bool_t call_failure(Sal *sal, eXosip_event_t *ev){
sr=SalReasonNotFound;
break;
case 415:
error=SalErrorMedia;
error=SalErrorFailure;
sr=SalReasonMedia;
break;
case 422:
eXosip_default_action(ev);
......@@ -1031,11 +1120,9 @@ int sal_iterate(Sal *sal){
if (process_event(sal,ev))
eXosip_event_free(ev);
}
if (sal->automatic_action==0) {
eXosip_lock();
eXosip_automatic_refresh();
eXosip_unlock();
}
eXosip_lock();
eXosip_automatic_refresh();