lc->call=call;
sal_call_set_local_media_description(h,call->localdesc);
call->resultdesc=sal_call_get_final_media_description(h);
+ if (call->resultdesc)
+ sal_media_description_ref(call->resultdesc);
if (call->resultdesc && sal_media_description_empty(call->resultdesc)){
sal_call_decline(h,SalReasonMedia,NULL);
linphone_call_destroy(call);
}
linphone_call_set_state(call,LCStateRinging);
sal_call_notify_ringing(h);
-
+ linphone_core_init_media_streams(lc,lc->call);
if (lc->vtable.inv_recv) lc->vtable.inv_recv(lc,tmp);
ms_free(barmesg);
ms_free(tmp);
}
ms_message("Doing early media...");
linphone_core_start_media_streams(lc,call);
+ call->media_pending=TRUE;
}
call->state=LCStateRinging;
}
if (call->resultdesc)
sal_media_description_unref(call->resultdesc);
call->resultdesc=sal_call_get_final_media_description(op);
+ if (call->resultdesc){
+ sal_media_description_ref(call->resultdesc);
+ call->media_pending=FALSE;
+ }
if (call->resultdesc && !sal_media_description_empty(call->resultdesc)){
gstate_new_state(lc, GSTATE_CALL_OUT_CONNECTED, NULL);
linphone_connect_incoming(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);
+ if (call->media_pending){
+ 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_ref(call->resultdesc);
+ 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);
+ }
+ call->media_pending=FALSE;
}
}
LinphoneCall *call=ms_new0(LinphoneCall,1);
call->dir=LinphoneCallOutgoing;
call->op=sal_op_new(lc->sal);
- sal_op_set_user_pointer(call->op,lc->call);
+ sal_op_set_user_pointer(call->op,call);
call->core=lc;
linphone_core_get_local_ip(lc,linphone_address_get_domain(to),call->localip);
call->localdesc=create_local_media_description (lc,call->localip,
return TRUE;
}
+static const char *codec_pref_order[]={
+ "speex",
+ "gsm",
+ "pcmu",
+ "pcma",
+ "H264",
+ "MP4V-ES",
+ "theora",
+ "H263-1998",
+ "H263",
+ NULL,
+};
+
+static int find_codec_rank(const char *mime){
+ int i;
+ for(i=0;codec_pref_order[i]!=NULL;++i){
+ if (strcasecmp(codec_pref_order[i],mime)==0)
+ break;
+ }
+ return i;
+}
+
+static int codec_compare(const PayloadType *a, const PayloadType *b){
+ int ra,rb;
+ ra=find_codec_rank(a->mime_type);
+ rb=find_codec_rank(b->mime_type);
+ if (ra==rb) return 0;
+ if (ra>rb) return 1;
+ if (ra<rb) return -1;
+}
+
static MSList *add_missing_codecs(SalStreamType mtype, MSList *l){
int i;
for(i=0;i<127;++i){
payload_type_set_flag(pt,PAYLOAD_TYPE_ENABLED);
ms_message("Adding new codec %s/%i with fmtp %s",
pt->mime_type,pt->clock_rate,pt->recv_fmtp ? pt->recv_fmtp : "");
- if (strcasecmp(pt->mime_type,"speex")==0 ||
- strcasecmp(pt->mime_type,"MP4V-ES")==0 ||
- strcasecmp(pt->mime_type,"H264")==0)
- l=ms_list_prepend(l,pt);
- else l=ms_list_append(l,pt);
+ l=ms_list_insert_sorted(l,pt,(int (*)(const void *, const void *))codec_compare);
}
}
}
int err=0;
char *route=NULL;
const char *from=NULL;
- const char *contact=NULL;
+ char *contact=NULL;
LinphoneProxyConfig *proxy=NULL;
LinphoneAddress *parsed_url2=NULL;
LinphoneAddress *real_parsed_url=NULL;
except when the user choosed to override the ipaddress */
if (linphone_core_get_firewall_policy(lc)!=LINPHONE_POLICY_USE_NAT_ADDRESS)
contact=get_fixed_contact(lc,call->localip,dest_proxy);
- if (contact)
+ if (contact){
sal_op_set_contact(call->op, contact);
+ ms_free(contact);
+ }
lc->call=call;
linphone_core_init_media_streams(lc,lc->call);
if (!lc->sip_conf.sdp_200_ack){
+ call->media_pending=TRUE;
sal_call_set_local_media_description(call->op,call->localdesc);
}
err=sal_call(call->op,from,real_url);
lc->call=NULL;
}else gstate_new_state(lc, GSTATE_CALL_OUT_INVITE, url);
- goto end;
- end:
- if (real_url!=NULL) ms_free(real_url);
- if (route!=NULL) ms_free(route);
+ if (real_url!=NULL) ms_free(real_url);
+ if (route!=NULL) ms_free(route);
return (err<0) ? -1 : 0;
}
}
}
-static RtpProfile *make_profile(LinphoneCore *lc, SalStreamDescription *desc, int *used_pt){
+static RtpProfile *make_profile(LinphoneCore *lc, const SalStreamDescription *desc, int *used_pt){
int bw;
- MSList *elem;
+ const MSList *elem;
RtpProfile *prof=rtp_profile_new("Call profile");
bool_t first=TRUE;
if (desc->type==SalAudio){
cname=linphone_address_as_string_uri_only(me);
{
- SalStreamDescription *stream=sal_media_description_find_stream(call->resultdesc,
+ const SalStreamDescription *stream=sal_media_description_find_stream(call->resultdesc,
SalProtoRtpAvp,SalAudio);
if (stream){
call->audio_profile=make_profile(lc,stream,&used_pt);
}
#ifdef VIDEO_ENABLED
{
- SalStreamDescription *stream=sal_media_description_find_stream(call->resultdesc,
+ const SalStreamDescription *stream=sal_media_description_find_stream(call->resultdesc,
SalProtoRtpAvp,SalVideo);
/* shutdown preview */
if (lc->previewstream!=NULL) {
}
#endif
if (call->audio_profile){
+ rtp_profile_clear_all(call->audio_profile);
rtp_profile_destroy(call->audio_profile);
call->audio_profile=NULL;
}
if (call->video_profile){
+ rtp_profile_clear_all(call->video_profile);
rtp_profile_destroy(call->video_profile);
call->video_profile=NULL;
}
if (call->resultdesc){
sal_media_description_ref(call->resultdesc);
linphone_core_start_media_streams(lc, call);
- }
+ }else call->media_pending=TRUE;
ms_message("call answered.");
return 0;
}
}
}
+ ms_list_for_each(config->proxies,(void (*)(void*)) linphone_proxy_config_destroy);
+ ms_list_free(config->proxies);
+ config->proxies=NULL;
+
linphone_proxy_config_write_to_config_file(lc->config,NULL,i); /*mark the end */
for(elem=lc->auth_info,i=0;elem!=NULL;elem=ms_list_next(elem),i++){
linphone_auth_info_write_config(lc->config,ai,i);
}
linphone_auth_info_write_config(lc->config,NULL,i); /* mark the end */
+ ms_list_for_each(lc->auth_info,(void (*)(void*))linphone_auth_info_destroy);
+ ms_list_free(lc->auth_info);
+ lc->auth_info=NULL;
sal_uninit(lc->sal);
lc->sal=NULL;
}
}
static bool_t only_telephone_event(const MSList *l){
- for(;l!=NULL;l=l->next){
- PayloadType *p=(PayloadType*)l->data;
- if (strcasecmp(p->mime_type,"telephone-event")!=0){
- return FALSE;
- }
+ PayloadType *p=(PayloadType*)l->data;
+ if (strcasecmp(p->mime_type,"telephone-event")!=0){
+ return FALSE;
}
return TRUE;
}
static void initiate_outgoing(const SalStreamDescription *local_offer,
const SalStreamDescription *remote_answer,
SalStreamDescription *result){
- result->payloads=match_payloads(local_offer->payloads,remote_answer->payloads);
+ if (remote_answer->port!=0)
+ result->payloads=match_payloads(local_offer->payloads,remote_answer->payloads);
if (result->payloads && !only_telephone_event(result->payloads)){
+ strcpy(result->addr,remote_answer->addr);
result->port=remote_answer->port;
result->bandwidth=remote_answer->bandwidth;
result->ptime=remote_answer->ptime;
+ result->proto=local_offer->proto;
+ result->type=local_offer->type;
}else{
result->port=0;
}
SalStreamDescription *result){
result->payloads=match_payloads(local_cap->payloads,remote_offer->payloads);
if (result->payloads && !only_telephone_event(result->payloads)){
+ strcpy(result->addr,local_cap->addr);
result->port=local_cap->port;
result->bandwidth=local_cap->bandwidth;
result->ptime=local_cap->ptime;
+ result->proto=local_cap->proto;
+ result->type=local_cap->type;
}else{
result->port=0;
}
int offer_answer_initiate_outgoing(const SalMediaDescription *local_offer,
const SalMediaDescription *remote_answer,
SalMediaDescription *result){
- int i;
- for(i=0;i<local_offer->nstreams;++i){
- initiate_outgoing(&local_offer->streams[i],&remote_answer->streams[i],&result->streams[i]);
+ int i,j;
+ const SalStreamDescription *ls,*rs;
+ for(i=0,j=0;i<local_offer->nstreams;++i){
+ ms_message("Processing for stream %i",i);
+ ls=&local_offer->streams[i];
+ rs=sal_media_description_find_stream(remote_answer,ls->proto,ls->type);
+ if (rs) {
+ initiate_outgoing(ls,rs,&result->streams[j]);
+ ++j;
+ }
+ else ms_warning("No matching stream for %i",i);
}
- result->nstreams=local_offer->nstreams;
+ result->nstreams=j;
strcpy(result->addr,remote_answer->addr);
return 0;
}
int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities,
const SalMediaDescription *remote_offer,
SalMediaDescription *result){
- int i;
- for(i=0;i<local_capabilities->nstreams;++i){
- initiate_incoming(&local_capabilities->streams[i],&remote_offer->streams[i],&result->streams[i]);
+ int i,j;
+ const SalStreamDescription *ls,*rs;
+
+ for(i=0,j=0;i<remote_offer->nstreams;++i){
+ rs=&remote_offer->streams[i];
+ ms_message("Processing for stream %i",i);
+ ls=sal_media_description_find_stream(local_capabilities,rs->proto,rs->type);
+ if (ls){
+ initiate_incoming(ls,rs,&result->streams[j]);
+ ++j;
+ }
}
- result->nstreams=local_capabilities->nstreams;
+ result->nstreams=j;
strcpy(result->addr,local_capabilities->addr);
return 0;
}
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*/
LCState state;
+ bool_t media_pending;
} LinphoneCall;
LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to);
for(i=0;i<SAL_MEDIA_DESCRIPTION_MAX_STREAMS;i++){
ms_list_for_each(md->streams[i].payloads,(void (*)(void *))payload_type_destroy);
ms_list_free(md->streams[i].payloads);
+ md->streams[i].payloads=NULL;
}
ms_free(md);
}
}
}
-SalStreamDescription *sal_media_description_find_stream(SalMediaDescription *md,
+const SalStreamDescription *sal_media_description_find_stream(const SalMediaDescription *md,
SalMediaProto proto, SalStreamType type){
int i;
for(i=0;i<md->nstreams;++i){
- SalStreamDescription *ss=&md->streams[i];
+ const SalStreamDescription *ss=&md->streams[i];
if (ss->proto==proto && ss->type==type) return ss;
}
return NULL;
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,
+const SalStreamDescription *sal_media_description_find_stream(const SalMediaDescription *md,
SalMediaProto proto, SalStreamType type);
/*this structure must be at the first byte of the SalOp structure defined by implementors*/
SalOp *op=ms_new(SalOp,1);
__sal_op_init(op,sal);
op->cid=op->did=op->tid=op->rid=op->nid=op->sid=-1;
+ op->result=NULL;
op->supports_session_timers=FALSE;
op->sdp_offering=TRUE;
op->pending_auth=NULL;
sal_remove_register(op->base.root,op->rid);
}
if (op->cid!=-1){
+ ms_message("Cleaning cid %i",op->cid);
eXosip_call_set_reference(op->cid,NULL);
}
if (op->pending_auth){
sal_remove_pending_auth(op->base.root,op);
}
+ if (op->result)
+ sal_media_description_unref(op->result);
__sal_op_free(op);
}
}
static void sdp_process(SalOp *h){
+ ms_message("Doing SDP offer/answer process");
if (h->result){
sal_media_description_unref(h->result);
}
ms_error("Could not create call.");
return -1;
}
- if (h->base.contact)
+ if (h->base.contact){
+ osip_list_special_free(&invite->contacts,(void (*)(void*))osip_contact_free);
osip_message_set_contact(invite,h->base.contact);
+ }
if (h->base.root->session_expires!=0){
osip_message_set_header(invite, "Session-expires", "200");
osip_message_set_supported(invite, "timer");
eXosip_unlock();
eXosip_clear_authentication_info();
eXosip_event_free(h->pending_auth);
+ sal_remove_pending_auth(sal_op_get_sal(h),h);
h->pending_auth=NULL;
}
}
char *tmp;
sdp_message_t *sdp=eXosip_get_sdp_info(ev->request);
if (sdp){
+ op->sdp_offering=FALSE;
op->base.remote_media=sal_media_description_new();
sdp_to_media_description(sdp,op->base.remote_media);
sdp_message_free(sdp);
static void call_released(Sal *sal, eXosip_event_t *ev){
SalOp *op;
+ char *from;
op=(SalOp*)ev->external_reference;
if (op==NULL){
return;
}
- eXosip_call_set_reference(ev->cid,NULL);
- /*sal->callbacks.call_terminated(op);*/
+ op->cid=-1;
+ if (op->did==-1)
+ sal->callbacks.call_failure(op,SalErrorNoResponse,SalReasonUnknown,NULL);
}
static int get_auth_data(eXosip_event_t *ev, const char **realm, const char **username){
}
break;
default:
- ms_message("Unhandled exosip event !");
+ ms_message("Unhandled exosip event ! %i");
break;
}
return TRUE;
addr = sdp_message_c_addr_get (msg, i, 0);
if (addr != NULL)
strncpy(stream->addr,addr,sizeof(stream->addr));
+ if (port)
+ stream->port=atoi(port);
+
stream->ptime=_sdp_message_get_a_ptime(msg,i);
if (strcasecmp("audio", mtype) == 0){
stream->type=SalAudio;
/* get the fmtp, if any */
fmtp=sdp_message_a_attr_value_get_with_pt(msg, i, ptn,"fmtp");
payload_type_set_send_fmtp(pt,fmtp);
+ stream->payloads=ms_list_append(stream->payloads,pt);
+ ms_message("Found payload %s/%i fmtp=%s",pt->mime_type,pt->clock_rate,
+ pt->send_fmtp ? pt->send_fmtp : "");
}
}
+ desc->nstreams=i;
return 0;
}
-Subproject commit 8dae09b11ee8a0fe29674944b207b5e06fb0f4ed
+Subproject commit ae7dfdcaea6d5fe6d4f44a6247b4ca506799e379