• John Koleszar's avatar
    Y4M input support for 4:2:2, 4:4:4, 4:4:4:4 · 8dd8287e
    John Koleszar authored
    Adds a new experiment CONFIG_NON420 that allows other chroma subsamplings
    to be passed to the codec. This commit allows the data to be passed from
    a y4m input file through vpxenc to the codec, where they're currently
    rejected. Later commits will finish support for this inside the codec.
    
    Change-Id: Ib3aac604d8cad9e24cef395fa1067f16ba7e8e43
    8dd8287e
exevents.c 36.61 KiB
/*
linphone
Copyright (C) 2000  Simon MORLAT (simon.morlat@free.fr)
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.
#include "exevents.h"
#include "linphonecore.h"
#include "private.h"
#include "mediastreamer2/mediastream.h"
#include <eXosip2/eXosip.h>
#include <osipparser2/osip_message.h>
#include <osipparser2/osip_parser.h>
static int linphone_answer_sdp(LinphoneCore *lc, eXosip_event_t *ev, sdp_message_t *sdp);
static bool_t linphone_call_matches_event(LinphoneCall *call, eXosip_event_t *ev){
	return call->cid==ev->cid;
static void linphone_call_proceeding(LinphoneCore *lc, eXosip_event_t *ev){
	if (lc->call==NULL || (lc->call->cid!=-1 && !linphone_call_matches_event(lc->call,ev)) ) {
		ms_warning("This call has been canceled: call=%p, call->cid=%i, ev->cid=%i",
			lc->call,lc->call->cid,ev->cid);
		eXosip_lock();
		eXosip_call_terminate(ev->cid,ev->did);
		eXosip_unlock();
		return;
	lc->call->cid=ev->cid;
	lc->call->did=ev->did;
	lc->call->tid=ev->tid;
static void linphone_connect_incoming(LinphoneCore *lc){
	lc->vtable.show(lc);
	lc->vtable.display_status(lc,_("Connected."));
	lc->call->state=LCStateAVRunning;
	if (lc->ringstream!=NULL){
		ring_stop(lc->ringstream);
		lc->ringstream=NULL;
	if (lc->audiostream->ticker!=NULL){
		/*case where we accepted early media */
		linphone_core_stop_media_streams(lc);
		linphone_core_init_media_streams(lc);
	linphone_core_start_media_streams(lc,lc->call);
int linphone_call_accepted(LinphoneCore *lc, eXosip_event_t *ev)
	LinphoneCall *call=lc->call;
	sdp_message_t *sdp;
	const char *sdpanswer=NULL;
	osip_message_t *msg=NULL;
	int err;
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
if (call==NULL){ ms_warning("No call to accept."); return 0; } linphone_call_proceeding(lc,ev); if (!linphone_call_matches_event(lc->call,ev)) return 0; call->auth_pending=FALSE; if (call->state==LCStateAVRunning){ return 0; /*already accepted*/ } linphone_call_init_media_params(call); sdp=eXosip_get_sdp_info(ev->response); if (!lc->sip_conf.sdp_200_ack){ err=0; sdp_context_read_answer(call->sdpctx,sdp); }else{ /*we receive a 200OK with an sdp offer*/ err=linphone_answer_sdp(lc,ev,sdp); if (err==0) sdpanswer=call->sdpctx->answerstr; } if (err==0){ gstate_new_state(lc, GSTATE_CALL_OUT_CONNECTED, NULL); linphone_connect_incoming(lc); } /*send the ack once streams are started*/ eXosip_call_build_ack(ev->did,&msg); if (sdpanswer!=NULL) linphone_set_sdp(msg,sdpanswer); eXosip_call_send_ack(ev->did,msg); if (err!=0){ /*send a bye*/ ms_error("Incompatible SDP offer received in 200Ok, need to abort the call"); linphone_core_terminate_call(lc,NULL); } sdp_message_free(sdp); return 0; } int linphone_call_terminated(LinphoneCore *lc, eXosip_event_t *ev) { /*stop ringing if necessary*/ if (lc->call!=NULL){ if (lc->call->cid!=ev->cid){ /* this is not current call */ ms_message("call %i terminated, this was not current call.",ev->cid); return 0; } } ms_message("Current call terminated..."); if (lc->ringstream!=NULL) { ring_stop(lc->ringstream); lc->ringstream=NULL; } linphone_core_stop_media_streams(lc); 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){ char *from; osip_from_to_str(ev->request->from,&from); lc->vtable.bye_recv(lc,from); osip_free(from); } if (lc->call!=NULL){ linphone_call_destroy(lc->call); lc->call=NULL; } return 0; }
141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
int linphone_call_released(LinphoneCore *lc, int cid){ LinphoneCall *call=lc->call; if (call!=NULL && call->cid==cid){ linphone_call_destroy(lc->call); lc->call=NULL; lc->vtable.display_status(lc,_("Could not reach destination.")); gstate_new_state(lc, GSTATE_CALL_ERROR, NULL); } return 0; } int linphone_call_failure(LinphoneCore *lc, eXosip_event_t *ev) { const char *reason=""; char *msg486=_("User is busy."); char *msg480=_("User is temporarily unavailable."); char *msg487=_("Request Cancelled."); /*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 (call){ /*check that the faillure is related to this call, not an old one*/ if (!linphone_call_matches_event(call,ev)) { ms_warning("Failure reported for an old call."); return 0; } } if (ev->response){ code=osip_message_get_status_code(ev->response); reason=osip_message_get_reason_phrase(ev->response); }else code=-110; lc->vtable.show(lc); switch(code) { case 401: case 407: if (lc->call!=NULL) linphone_process_authentication(lc,ev); return 0; break; case 400: lc->vtable.display_status(lc,_("Bad request")); break; case 404: lc->vtable.display_status(lc,_("User cannot be found at given address.")); break; case 415: lc->vtable.display_status(lc,_("Remote user cannot support any of proposed codecs.")); break; case 422: /*ignore: eXosip_automatic_action will do the job of retrying with a greater Session-Expires*/ return 0; break; case 480: tmpmsg=msg480; case 486: /* msg_header_getbyname(msg,"retry-after",0,&retry); if (retry!=NULL) { umsg=g_malloc(strlen(tmpmsg)+strlen(retrymsg)+13);
211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
sprintf(umsg,retrymsg,tmpmsg,atoi(retry->hvalue)/60); lc->vtable.display_message(lc,umsg); ms_free(umsg); }*/ lc->vtable.display_message(lc,tmpmsg); break; case 487: lc->vtable.display_status(lc,msg487); break; case 600: lc->vtable.display_message(lc,msg600); break; case 603: lc->vtable.display_status(lc,msg603); break; case -110: /* time out, call leg is lost */ lc->vtable.display_status(lc,_("Timeout.")); break; case -111: lc->vtable.display_status(lc,_("Remote host was found but refused connection.")); break; default: if (code>0) { lc->vtable.display_status(lc,reason); } else ms_warning("failure_cb unknown code=%i\n",code); } 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; } return 0; } extern sdp_handler_t linphone_sdphandler; static int linphone_answer_sdp(LinphoneCore *lc, eXosip_event_t *ev, sdp_message_t *sdp){ int status=200; sdp_context_t *ctx=NULL; ctx=lc->call->sdpctx; /* get the result of the negociation */ sdp_context_get_answer(ctx,sdp); status=sdp_context_get_status(ctx); if (status==200){ linphone_core_init_media_streams(lc); return 0; }else{ if (status==-1) status=415; } return -1; } int linphone_inc_new_call(LinphoneCore *lc, eXosip_event_t *ev) { sdp_message_t *sdp=NULL; osip_from_t *from_url=ev->request->from; char *barmesg; char *from; char *to; int err;
281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
osip_from_to_str(ev->request->from,&from); osip_to_to_str(ev->request->to,&to); /* 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); eXosip_lock(); if (lc->presence_mode==LINPHONE_STATUS_BUSY) eXosip_call_send_answer(ev->tid,486,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) eXosip_call_send_answer(ev->tid,480,NULL); else if (lc->presence_mode==LINPHONE_STATUS_NOT_DISTURB) eXosip_call_send_answer(ev->tid,480,NULL); else if (lc->alt_contact!=NULL && lc->presence_mode==LINPHONE_STATUS_MOVED) { osip_message_t *msg; eXosip_call_build_answer(ev->tid,302,&msg); osip_message_set_contact(msg,lc->alt_contact); eXosip_call_send_answer(ev->tid,302,msg); } else if (lc->alt_contact!=NULL && lc->presence_mode==LINPHONE_STATUS_ALT_SERVICE) { osip_message_t *msg; eXosip_call_build_answer(ev->tid,380,&msg); osip_message_set_contact(msg,lc->alt_contact); eXosip_call_send_answer(ev->tid,380,msg); } else eXosip_call_send_answer(ev->tid,486,NULL); eXosip_unlock(); goto end; } if (lc->call!=NULL){/*busy*/ eXosip_lock(); eXosip_call_send_answer(ev->tid,486,NULL); eXosip_unlock(); goto end; } lc->call=linphone_call_new_incoming(lc,linphone_address_new(from),linphone_address_new(to),ev); sdp=eXosip_get_sdp_info(ev->request); if (sdp==NULL){ ms_message("No sdp body in invite, 200-ack scheme"); err=0; }else{ err=linphone_answer_sdp(lc,ev,sdp); } if (!err){ char *tmp; if (from_2char_without_params(from_url,&tmp)!=0){ tmp=ms_strdup("Unknown user"); } gstate_new_state(lc, GSTATE_CALL_IN_INVITE, tmp); barmesg=ortp_strdup_printf("%s %s",tmp,_("is contacting you.")); lc->vtable.show(lc); 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(lc->call,LCStateRinging); eXosip_lock(); eXosip_call_send_answer(ev->tid,180,NULL);
351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
eXosip_unlock(); lc->vtable.inv_recv(lc,tmp); ms_free(barmesg); osip_free(tmp); }else{ ms_error("Error during sdp negociation. "); eXosip_lock(); eXosip_call_send_answer(ev->tid,415,NULL); eXosip_unlock(); linphone_call_destroy(lc->call); lc->call=NULL; } end: osip_free(from); osip_free(to); if (sdp) sdp_message_free(sdp); return 0; } void linphone_handle_ack(LinphoneCore *lc, eXosip_event_t *ev){ sdp_message_t *sdp=eXosip_get_sdp_info(ev->ack); if (sdp){ sdp_context_read_answer(lc->call->sdpctx,sdp); linphone_connect_incoming(lc); sdp_message_free(sdp); } } void linphone_handle_reinvite(LinphoneCore *lc, eXosip_event_t *ev){ sdp_message_t *sdp=eXosip_get_sdp_info(ev->request); sdp_context_t *ctx; LinphoneCall *call=lc->call; char *answer; int status; if (sdp==NULL){ ms_warning("No sdp in reinvite !"); eXosip_lock(); eXosip_call_send_answer(ev->tid,603,NULL); eXosip_unlock(); return; } ctx=call->sdpctx; /* get the result of the negociation */ linphone_call_init_media_params(call); answer=sdp_context_get_answer(ctx,sdp); status=sdp_context_get_status(ctx); if (status==200){ osip_message_t *msg=NULL; linphone_core_stop_media_streams(lc); linphone_core_init_media_streams(lc); eXosip_lock(); if (eXosip_call_build_answer(ev->tid,200,&msg)<0){ ms_warning("Reinvite for closed call ?"); eXosip_unlock(); linphone_core_stop_media_streams(lc); sdp_message_free(sdp); return ; } answer=call->sdpctx->answerstr; /* takes the sdp already computed*/ linphone_set_sdp(msg,answer); eXosip_call_send_answer(ev->tid,200,msg); eXosip_unlock(); linphone_core_start_media_streams(lc,call); }else{ eXosip_lock(); eXosip_call_send_answer(ev->tid,status,NULL); eXosip_unlock(); } sdp_message_free(sdp);
421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
} void linphone_do_automatic_redirect(LinphoneCore *lc, const char *contact){ char *msg=ortp_strdup_printf(_("Redirected to %s..."),contact); lc->vtable.display_status(lc,msg); ms_free(msg); if (lc->call!=NULL) linphone_call_destroy(lc->call); lc->call=NULL; linphone_core_invite(lc,contact); } void linphone_call_redirected(LinphoneCore *lc, eXosip_event_t *ev){ int code=osip_message_get_status_code(ev->response); char *contact=NULL; osip_contact_t *ct; osip_message_get_contact(ev->response,0,&ct); if (ct) osip_contact_to_str(ct,&contact); switch(code){ case 380: lc->vtable.display_url(lc,_("User is not reachable at the moment but he invites you\nto contact him using the following alternate resource:"),contact); if (lc->call!=NULL) linphone_call_destroy(lc->call); lc->call=NULL; break; case 302: linphone_do_automatic_redirect(lc,contact); break; } if (contact) osip_free(contact); } /* these are the SdpHandler callbacks: we are called in to be aware of the content of the SDP messages exchanged */ int linphone_set_audio_offer(sdp_context_t *ctx) { LinphoneCall *call=(LinphoneCall*)sdp_context_get_user_pointer(ctx); LinphoneCore *lc=call->core; PayloadType *codec; MSList *elem; sdp_payload_t payload; elem=lc->codecs_conf.audio_codecs; while(elem!=NULL){ codec=(PayloadType*) elem->data; if (linphone_core_check_payload_type_usability(lc,codec) && payload_type_enabled(codec)){ sdp_payload_init(&payload); payload.a_rtpmap=ortp_strdup_printf("%s/%i/1",codec->mime_type,codec->clock_rate); payload.pt=rtp_profile_get_payload_number_from_rtpmap(lc->local_profile,payload.a_rtpmap); payload.localport=call->audio_params.natd_port > 0 ? call->audio_params.natd_port : lc->rtp_conf.audio_rtp_port; if (strcasecmp(codec->mime_type,"iLBC")==0){ /* prefer the 30 ms mode */ payload.a_fmtp="ptime=30"; } sdp_context_add_audio_payload(ctx,&payload); ms_free(payload.a_rtpmap); } elem=ms_list_next(elem); } /* add telephone-event payload*/ sdp_payload_init(&payload); payload.pt=rtp_profile_get_payload_number_from_mime(lc->local_profile,"telephone-event"); payload.a_rtpmap="telephone-event/8000"; payload.a_fmtp="0-11"; if (lc->dw_audio_bw>0) payload.b_as_bandwidth=lc->dw_audio_bw; sdp_context_add_audio_payload(ctx,&payload); return 0; }
491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
static int find_payload_type_number(RtpProfile *prof, PayloadType *pt){ int candidate=-1,i; PayloadType *it; for(i=0;i<127;++i){ it=rtp_profile_get_payload(prof,i); if (it!=NULL && strcasecmp(pt->mime_type,it->mime_type)==0 && (pt->clock_rate==it->clock_rate || pt->clock_rate<=0) ){ if ( (pt->recv_fmtp && it->recv_fmtp && strcasecmp(pt->recv_fmtp,it->recv_fmtp)==0) || (pt->recv_fmtp==NULL && it->recv_fmtp==NULL) ){ /*exact match*/ return i; }else candidate=i; } } if (candidate==-1) ms_fatal("Should not happen."); return candidate; } static int find_payload_type_number_best_match(RtpProfile *prof, const char *rtpmap, const char *fmtp){ int localpt=rtp_profile_get_payload_number_from_rtpmap(prof,rtpmap); PayloadType *pt; char value[10]; if (localpt<0) return -1; pt=rtp_profile_get_payload(prof,localpt); if (strcasecmp(pt->mime_type,"H264")==0){ /*hack for H264: need to answer with same packetization-mode*/ PayloadType tmp; memset(&tmp,0,sizeof(tmp)); tmp.mime_type="H264"; tmp.clock_rate=pt->clock_rate; if (fmtp && fmtp_get_value(fmtp,"packetization-mode",value,sizeof(value))){ tmp.recv_fmtp=(atoi(value)==1) ? "packetization-mode=1" : NULL; } localpt=find_payload_type_number(prof,&tmp); } return localpt; } int linphone_set_video_offer(sdp_context_t *ctx) { LinphoneCall *call=(LinphoneCall*)sdp_context_get_user_pointer(ctx); LinphoneCore *lc=call->core; PayloadType *codec; MSList *elem; bool_t firsttime=TRUE; if (!linphone_core_video_enabled(lc)) return -1; for(elem=lc->codecs_conf.video_codecs;elem!=NULL;elem=ms_list_next(elem)){ codec=(PayloadType*) elem->data; if (linphone_core_check_payload_type_usability(lc,codec) && payload_type_enabled(codec)){ sdp_payload_t payload; sdp_payload_init(&payload); payload.line=1; payload.a_rtpmap=ortp_strdup_printf("%s/%i",codec->mime_type,codec->clock_rate); payload.localport=call->video_params.natd_port>0 ? call->video_params.natd_port : lc->rtp_conf.video_rtp_port; payload.pt=find_payload_type_number(lc->local_profile,codec); payload.a_fmtp=codec->recv_fmtp; if(firsttime){ firsttime=FALSE; if (lc->dw_video_bw>0) payload.b_as_bandwidth=lc->dw_video_bw; } sdp_context_add_video_payload(ctx,&payload); ms_free(payload.a_rtpmap); } } return 0;
561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630
} typedef enum { Unsupported, Supported, SupportedAndValid /* valid= the presence of this codec is enough to make a call */ }SupportLevel; SupportLevel linphone_payload_is_supported(LinphoneCore *lc, sdp_payload_t *payload,RtpProfile *local_profile,RtpProfile *dialog_profile, bool_t answering, PayloadType **local_payload_type) { int localpt; SupportLevel ret; if (payload->a_rtpmap!=NULL){ localpt=find_payload_type_number_best_match(local_profile,payload->a_rtpmap,payload->a_fmtp); }else{ localpt=payload->pt; ms_warning("payload has no rtpmap."); } if (localpt>=0 && localpt <128 ){ /* this payload is understood, but does the user want to use it ?? */ PayloadType *rtppayload; rtppayload=rtp_profile_get_payload(local_profile,localpt); if (rtppayload==NULL) { ms_warning("strange error !!"); return Unsupported; } *local_payload_type=rtppayload; if (strcmp(rtppayload->mime_type,"telephone-event")!=0){ if (answering && !linphone_core_check_payload_type_usability(lc,rtppayload) ){ ms_warning("payload %s is not usable",rtppayload->mime_type); return Unsupported; } if ( !payload_type_enabled(rtppayload)) { ms_warning("payload %s is not enabled.",rtppayload->mime_type); return Unsupported; } ret=SupportedAndValid; }else ret=Supported; if (dialog_profile!=NULL){ int dbw,ubw; /* this payload is supported in our local rtp profile, so add it to the dialog rtp profile */ rtppayload=payload_type_clone(rtppayload); if (rtp_profile_get_payload(dialog_profile,payload->pt)!=NULL){ ms_error("Payload %s type already entered, should not happen !",rtppayload->mime_type); } rtp_profile_set_payload(dialog_profile,payload->pt,rtppayload); /* add to the rtp payload type some other parameters (bandwidth) */ if (rtppayload->type==PAYLOAD_VIDEO){ dbw=lc->dw_video_bw; ubw=lc->up_video_bw; }else{ dbw=lc->dw_audio_bw; ubw=lc->up_audio_bw; } if (payload->b_as_bandwidth!=0){ ms_message("Remote bandwidth constraint: %i",payload->b_as_bandwidth); /*obey to remote bandwidth constraint AND our own upbandwidth constraint*/ rtppayload->normal_bitrate=1000*get_min_bandwidth( payload->b_as_bandwidth, ubw); }else{ /*limit to upload bandwidth if exist, else no limit*/ if (ubw>0) rtppayload->normal_bitrate=1000*ubw; else { if (rtppayload->type!=PAYLOAD_VIDEO){ rtppayload->normal_bitrate=-1; /*allow speex to use maximum bitrate*/ } } }
631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700
if (payload->a_fmtp!=NULL){ payload_type_set_send_fmtp(rtppayload,payload->a_fmtp); } payload->a_fmtp=rtppayload->recv_fmtp; if (payload->a_ptime>0){ char tmp[30]; snprintf(tmp,sizeof(tmp),"ptime=%i",payload->a_ptime); payload_type_append_send_fmtp(rtppayload,tmp); ms_message("%s attribute added to fmtp",tmp); } } return ret; } return Unsupported; } int linphone_accept_audio_offer(sdp_context_t *ctx,sdp_payload_t *payload) { RtpProfile *remote_profile; StreamParams *params; SupportLevel supported; LinphoneCall *call=(LinphoneCall*)sdp_context_get_user_pointer(ctx); LinphoneCore *lc=call->core; PayloadType *lpt=NULL; params=&call->audio_params; remote_profile=call->profile; /* see if this codec is supported in our local rtp profile*/ supported=linphone_payload_is_supported(lc,payload,lc->local_profile,remote_profile,TRUE,&lpt); if (supported==Unsupported) { ms_message("Refusing audio codec %i (%s)",payload->pt,payload->a_rtpmap); return -1; } if (lc->sip_conf.only_one_codec && params->initialized){ ms_message("Only one codec has to be accepted."); return -1; } if (supported==SupportedAndValid) { if (params->initialized==0){ /* this is the first codec we accept, it is going to be used*/ params->localport=lc->rtp_conf.audio_rtp_port; payload->localport=params->natd_port>0 ? params->natd_port : lc->rtp_conf.audio_rtp_port; params->line=payload->line; params->pt=payload->pt; /* remember the first payload accepted */ if (payload->relay_host!=NULL){ strncpy(params->remoteaddr,payload->relay_host,sizeof(params->remoteaddr)-1); params->remoteport=payload->relay_port; params->remotertcpport=payload->relay_port; params->relay_session_id=payload->relay_session_id; }else{ strncpy(params->remoteaddr,payload->c_addr,sizeof(params->remoteaddr)-1); params->remoteport=payload->remoteport; params->remotertcpport=payload->remoteport+1; } params->initialized=1; /* we can now update the allocated bandwidth for audio, and then video*/ linphone_core_update_allocated_audio_bandwidth_in_call(lc,lpt); /* give our download bandwidth constraint*/ payload->b_as_bandwidth=(lc->dw_audio_bw>0) ? lc->dw_audio_bw : 0; }else{ /* refuse all other audio lines*/ if(params->line!=payload->line) { ms_message("Only one audio line can be accepted."); #if !defined(_WIN32_WCE) abort(); #endif /*_WIN32_WCE*/ return -1; } }
701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770
} return 0; } int linphone_accept_video_offer(sdp_context_t *ctx,sdp_payload_t *payload) { LinphoneCall *call=(LinphoneCall*)sdp_context_get_user_pointer(ctx); LinphoneCore *lc=call->core; RtpProfile *remote_profile; StreamParams *params; SupportLevel supported; PayloadType *lpt=NULL; if (!linphone_core_video_enabled(lc)) return -1; if (payload->remoteport==0) { ms_message("Video stream refused by remote."); return 0; } params=&call->video_params; remote_profile=call->profile; /* see if this codec is supported in our local rtp profile*/ supported=linphone_payload_is_supported(lc,payload,lc->local_profile,remote_profile,TRUE,&lpt); if (supported==Unsupported) { ms_message("Refusing video codec %i (%s)",payload->pt,payload->a_rtpmap); return -1; } if (lc->sip_conf.only_one_codec && params->initialized){ return -1; } if (supported==SupportedAndValid){ if (params->initialized==0){ /* this is the first codec we may accept*/ params->localport=lc->rtp_conf.video_rtp_port; payload->localport=params->natd_port>0 ? params->natd_port : lc->rtp_conf.video_rtp_port; params->line=payload->line; params->pt=payload->pt; /* remember the first payload accepted */ if (payload->relay_host!=NULL){ strncpy(params->remoteaddr,payload->relay_host,sizeof(params->remoteaddr)-1); params->remoteport=payload->relay_port; params->remotertcpport=payload->relay_port; params->relay_session_id=payload->relay_session_id; }else{ strncpy(params->remoteaddr,payload->c_addr,sizeof(params->remoteaddr)-1); params->remoteport=payload->remoteport; params->remotertcpport=params->remoteport+1; } params->initialized=1; payload->b_as_bandwidth=(lc->dw_video_bw>0) ? lc->dw_video_bw : 0; }else{ /* refuse all other video lines*/ if(params->line!=payload->line) return -1; } } return 0; } int linphone_read_audio_answer(sdp_context_t *ctx,sdp_payload_t *payload) { LinphoneCall *call=(LinphoneCall*)sdp_context_get_user_pointer(ctx); LinphoneCore *lc=call->core; StreamParams *params; SupportLevel supported; PayloadType *lpt=NULL; /* paranoid check: see if this codec is supported in our local rtp profile*/ supported=linphone_payload_is_supported(lc, payload,lc->local_profile,call->profile,FALSE,&lpt); if (supported==Unsupported) { ms_warning("This remote sip phone did not answer properly to my sdp offer: rtpmap=%s",payload->a_rtpmap);
771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840
return 0; } if (supported==SupportedAndValid){ params=&call->audio_params; if (params->initialized==0){ /* this is the first codec we accept, this is the one that is going to be used (at least for sending data.*/ params->localport=lc->rtp_conf.audio_rtp_port; params->line=payload->line; params->pt=payload->pt; /* remember the first payload accepted */ if (payload->relay_host!=NULL){ strncpy(params->remoteaddr,payload->relay_host,sizeof(params->remoteaddr)-1); params->remoteport=payload->relay_port; params->remotertcpport=payload->relay_port; params->relay_session_id=payload->relay_session_id; }else{ strncpy(params->remoteaddr,payload->c_addr,sizeof(params->remoteaddr)-1); params->remoteport=payload->remoteport; params->remotertcpport=payload->remoteport+1; } params->initialized=1; /* we can now update the allocated bandwidth for audio, and then video*/ linphone_core_update_allocated_audio_bandwidth_in_call(lc,lpt); } } return 0; } int linphone_read_video_answer(sdp_context_t *ctx,sdp_payload_t *payload) { LinphoneCall *call=(LinphoneCall*)sdp_context_get_user_pointer(ctx); LinphoneCore *lc=call->core; StreamParams *params; SupportLevel supported; PayloadType *lpt=NULL; /* paranoid check: see if this codec is supported in our local rtp profile*/ supported=linphone_payload_is_supported(lc, payload,lc->local_profile,call->profile,FALSE,&lpt); if (supported==Unsupported) { ms_warning("This remote sip phone did not answer properly to my sdp offer: rtpmap=%s",payload->a_rtpmap); return 0; } if (supported==SupportedAndValid){ params=&call->video_params; if (params->initialized==0){ /* this is the first codec we may accept*/ params->localport=lc->rtp_conf.video_rtp_port; params->line=payload->line; params->pt=payload->pt; /* remember the first payload accepted */ if (payload->relay_host!=NULL){ strncpy(params->remoteaddr,payload->relay_host,sizeof(params->remoteaddr)-1); params->remoteport=payload->relay_port; params->remotertcpport=payload->relay_port; params->relay_session_id=payload->relay_session_id; }else{ strncpy(params->remoteaddr,payload->c_addr,sizeof(params->remoteaddr)-1); params->remoteport=payload->remoteport; params->remotertcpport=payload->remoteport+1; } params->initialized=1; } } return 0; } void linphone_call_ringing(LinphoneCore *lc, eXosip_event_t *ev){ sdp_message_t *sdp=eXosip_get_sdp_info(ev->response); LinphoneCall *call=lc->call; lc->vtable.display_status(lc,_("Remote ringing."));
841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910
linphone_call_proceeding(lc,ev); if (call==NULL) return; if (sdp==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 */ StreamParams *audio_params; if (call==NULL){ ms_error("No call ?"); goto end; } if (lc->audiostream->ticker!=NULL){ /*streams already started */ ms_message("Early media already started."); goto end; } audio_params=&call->audio_params; sdp_context_read_answer(lc->call->sdpctx,sdp); lc->vtable.show(lc); 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; goto end; end: sdp_message_free(sdp); } static void linphone_process_media_control_xml(LinphoneCore *lc, eXosip_event_t *ev){ osip_body_t *body=NULL; osip_message_get_body(ev->request,0,&body); if (body && body->body!=NULL && strstr(body->body,"picture_fast_update")){ osip_message_t *ans=NULL; ms_message("Receiving VFU request !"); #ifdef VIDEO_ENABLED if (lc->videostream) video_stream_send_vfu(lc->videostream); #endif eXosip_call_build_answer(ev->tid,200,&ans); if (ans) eXosip_call_send_answer(ev->tid,200,ans); } } static void linphone_process_dtmf_relay(LinphoneCore *lc, eXosip_event_t *ev){ osip_body_t *body=NULL; osip_message_get_body(ev->request,0,&body); if (body && body->body!=NULL){ osip_message_t *ans=NULL; const char *name=strstr(body->body,"Signal"); if (name==NULL) name=strstr(body->body,"signal"); if (name==NULL) { ms_warning("Could not extract the dtmf name from the SIP INFO."); }else{ char tmp[2]; name+=strlen("signal"); if (sscanf(name," = %1s",tmp)==1){ ms_message("Receiving dtmf %s via SIP INFO.",tmp);
911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980
if (lc->vtable.dtmf_received != NULL) lc->vtable.dtmf_received(lc, tmp[0]); } } eXosip_call_build_answer(ev->tid,200,&ans); if (ans) eXosip_call_send_answer(ev->tid,200,ans); } } void linphone_call_message_new(LinphoneCore *lc, eXosip_event_t *ev){ osip_message_t *ans=NULL; if (ev->request){ if (MSG_IS_INFO(ev->request)){ osip_content_type_t *ct; ct=osip_message_get_content_type(ev->request); if (ct && ct->subtype){ if (strcmp(ct->subtype,"media_control+xml")==0) linphone_process_media_control_xml(lc,ev); else if (strcmp(ct->subtype,"dtmf-relay")==0) linphone_process_dtmf_relay(lc,ev); else { ms_message("Unhandled SIP INFO."); /*send an "Not implemented" answer*/ eXosip_call_build_answer(ev->tid,501,&ans); if (ans) eXosip_call_send_answer(ev->tid,501,ans); } }else{ /*empty SIP INFO, probably to test we are alive. Send an empty answer*/ eXosip_call_build_answer(ev->tid,200,&ans); if (ans) eXosip_call_send_answer(ev->tid,200,ans); } } }else ms_warning("linphone_call_message_new: No request ?"); } void linphone_registration_faillure(LinphoneCore *lc, eXosip_event_t *ev){ int status_code=0; char *msg; const char *reason=NULL; osip_uri_t *requri=osip_message_get_uri(ev->request); char *ru; LinphoneProxyConfig *cfg; if (ev->response){ status_code=osip_message_get_status_code(ev->response); reason=osip_message_get_reason_phrase(ev->response); } switch(status_code){ case 401: case 407: linphone_process_authentication(lc,ev); break; default: cfg=linphone_core_get_proxy_config_from_rid(lc,ev->rid); /* if contact is up to date, process the failure, otherwise resend a new register with updated contact first, just in case the faillure is due to incorrect contact */ if (linphone_proxy_config_register_again_with_updated_contact(cfg,ev->request,ev->response)) return; /*we are retrying with an updated contact*/ if (status_code==403) linphone_proxy_config_process_authentication_failure(lc,ev); osip_uri_to_str(requri,&ru); msg=ortp_strdup_printf(_("Registration on %s failed: %s"),ru,(reason!=NULL) ? reason : _("no response timeout")); lc->vtable.display_status(lc,msg); gstate_new_state(lc, GSTATE_REG_FAILED, msg); ms_free(msg); osip_free(ru); }
981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050
} void linphone_registration_success(LinphoneCore *lc,eXosip_event_t *ev){ LinphoneProxyConfig *cfg; osip_uri_t *requri=osip_message_get_uri(ev->request); char *msg; char *ru; osip_header_t *h=NULL; cfg=linphone_core_get_proxy_config_from_rid(lc,ev->rid); ms_return_if_fail(cfg!=NULL); gstate_new_state(lc, GSTATE_REG_OK, NULL); osip_message_get_expires(ev->request,0,&h); if (h!=NULL && atoi(h->hvalue)!=0){ cfg->registered=TRUE; linphone_proxy_config_register_again_with_updated_contact(cfg,ev->request,ev->response); }else cfg->registered=FALSE; osip_uri_to_str(requri,&ru); if (cfg->registered) msg=ms_strdup_printf(_("Registration on %s successful."),ru); else msg=ms_strdup_printf(_("Unregistration on %s done."),ru); lc->vtable.display_status(lc,msg); ms_free(msg); osip_free(ru); } static bool_t comes_from_local_if(osip_message_t *msg){ osip_via_t *via=NULL; osip_message_get_via(msg,0,&via); if (via){ const char *host; host=osip_via_get_host(via); if (strcmp(host,"127.0.0.1")==0 || strcmp(host,"::1")==0){ osip_generic_param_t *param=NULL; osip_via_param_get_byname(via,"received",&param); if (param==NULL) return TRUE; if (param->gvalue && (strcmp(param->gvalue,"127.0.0.1")==0 || strcmp(param->gvalue,"::1")==0)){ return TRUE; } } } return FALSE; } static void linphone_inc_update(LinphoneCore *lc, eXosip_event_t *ev){ osip_message_t *msg=NULL; ms_message("Processing incoming UPDATE"); eXosip_lock(); eXosip_message_build_answer(ev->tid,200,&msg); if (msg!=NULL) eXosip_message_send_answer(ev->tid,200,msg); eXosip_unlock(); } static void linphone_other_request(LinphoneCore *lc, eXosip_event_t *ev){ ms_message("in linphone_other_request"); if (ev->request==NULL) return; if (strcmp(ev->request->sip_method,"MESSAGE")==0){ linphone_core_text_received(lc,ev); eXosip_message_send_answer(ev->tid,200,NULL); }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"); eXosip_options_send_answer(ev->tid,200,options); }else if (strcmp(ev->request->sip_method,"WAKEUP")==0 && comes_from_local_if(ev->request)) {
1051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120
eXosip_message_send_answer(ev->tid,200,NULL); ms_message("Receiving WAKEUP request !"); if (lc->vtable.show) lc->vtable.show(lc); }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){ if (lc->vtable.refer_received) lc->vtable.refer_received(lc,h->hvalue); } }else ms_warning("Ignored REFER not coming from this local loopback interface."); }else if (strncmp(ev->request->sip_method, "UPDATE", 6) == 0){ linphone_inc_update(lc,ev); }else { char *tmp=NULL; size_t msglen=0; osip_message_to_str(ev->request,&tmp,&msglen); if (tmp){ ms_message("Unsupported request received:\n%s",tmp); osip_free(tmp); } /*answer with a 501 Not implemented*/ eXosip_message_send_answer(ev->tid,501,NULL); } } void linphone_core_process_event(LinphoneCore *lc,eXosip_event_t *ev) { switch(ev->type){ case EXOSIP_CALL_ANSWERED: ms_message("CALL_ANSWERED\n"); linphone_call_accepted(lc,ev); linphone_authentication_ok(lc,ev); break; case EXOSIP_CALL_CLOSED: case EXOSIP_CALL_CANCELLED: ms_message("CALL_CLOSED or CANCELLED\n"); linphone_call_terminated(lc,ev); break; case EXOSIP_CALL_TIMEOUT: case EXOSIP_CALL_NOANSWER: ms_message("CALL_TIMEOUT or NOANSWER\n"); linphone_call_failure(lc,ev); break; case EXOSIP_CALL_REQUESTFAILURE: case EXOSIP_CALL_GLOBALFAILURE: case EXOSIP_CALL_SERVERFAILURE: ms_message("CALL_REQUESTFAILURE or GLOBALFAILURE or SERVERFAILURE\n"); linphone_call_failure(lc,ev); break; case EXOSIP_CALL_INVITE: ms_message("CALL_NEW\n"); /* CALL_NEW is used twice in qos mode : * when you receive invite (textinfo = "With QoS" or "Without QoS") * and when you receive update (textinfo = "New Call") */ linphone_inc_new_call(lc,ev); break; case EXOSIP_CALL_REINVITE: linphone_handle_reinvite(lc,ev); break; case EXOSIP_CALL_ACK: ms_message("CALL_ACK"); linphone_handle_ack(lc,ev); break; case EXOSIP_CALL_REDIRECTED:
1121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187
ms_message("CALL_REDIRECTED"); linphone_call_redirected(lc,ev); break; case EXOSIP_CALL_PROCEEDING: ms_message("CALL_PROCEEDING"); linphone_call_proceeding(lc,ev); break; case EXOSIP_CALL_RINGING: ms_message("CALL_RINGING"); linphone_call_ringing(lc,ev); break; case EXOSIP_CALL_MESSAGE_NEW: ms_message("EXOSIP_CALL_MESSAGE_NEW"); linphone_call_message_new(lc,ev); break; case EXOSIP_CALL_MESSAGE_REQUESTFAILURE: if (ev->did<0 && ev->response && (ev->response->status_code==407 || ev->response->status_code==401)){ eXosip_default_action(ev); } break; case EXOSIP_IN_SUBSCRIPTION_NEW: ms_message("CALL_SUBSCRIPTION_NEW or UPDATE"); linphone_subscription_new(lc,ev); break; case EXOSIP_SUBSCRIPTION_UPDATE: break; case EXOSIP_SUBSCRIPTION_NOTIFY: ms_message("CALL_SUBSCRIPTION_NOTIFY"); linphone_notify_recv(lc,ev); break; case EXOSIP_SUBSCRIPTION_ANSWERED: ms_message("EXOSIP_SUBSCRIPTION_ANSWERED, ev->sid=%i\n",ev->sid); linphone_subscription_answered(lc,ev); break; case EXOSIP_SUBSCRIPTION_CLOSED: ms_message("EXOSIP_SUBSCRIPTION_CLOSED\n"); linphone_subscription_closed(lc,ev); break; case EXOSIP_CALL_RELEASED: ms_message("CALL_RELEASED\n"); linphone_call_released(lc, ev->cid); break; case EXOSIP_REGISTRATION_FAILURE: ms_message("REGISTRATION_FAILURE\n"); linphone_registration_faillure(lc,ev); break; case EXOSIP_REGISTRATION_SUCCESS: linphone_authentication_ok(lc,ev); linphone_registration_success(lc,ev); break; case EXOSIP_MESSAGE_NEW: linphone_other_request(lc,ev); break; case EXOSIP_MESSAGE_REQUESTFAILURE: if (ev->response && (ev->response->status_code == 407 || ev->response->status_code == 401)){ /*the user is expected to have registered to the proxy, thus password is known*/ eXosip_default_action(ev); } break; default: ms_message("Unhandled exosip event !"); break; } eXosip_event_free(ev); }