示例#1
0
static void notify_refer(SalOp *op, SalReferStatus status){
	LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
	LinphoneCall *call=(LinphoneCall*) sal_op_get_user_pointer(op);
	LinphoneCallState cstate;
	if (call==NULL) {
		ms_warning("Receiving notify_refer for unknown call.");
		return ;
	}
	switch(status){
		case SalReferTrying:
			cstate=LinphoneCallOutgoingProgress;
		break;
		case SalReferSuccess:
			cstate=LinphoneCallConnected;
		break;
		case SalReferFailed:
			cstate=LinphoneCallError;
		break;
		default:
			cstate=LinphoneCallError;
	}
	linphone_call_set_transfer_state(call, cstate);
	if (cstate==LinphoneCallConnected){
		/*automatically terminate the call as the transfer is complete.*/
		linphone_core_terminate_call(lc,call);
	}
}
示例#2
0
/**
 * Returns the call object this call is replacing, if any.
 * Call replacement can occur during call transfers.
 * By default, the core automatically terminates the replaced call and accept the new one.
 * This function allows the application to know whether a new incoming call is a one that replaces another one.
**/
LinphoneCall *linphone_call_get_replaced_call(LinphoneCall *call){
	SalOp *op=sal_call_get_replaces(call->op);
	if (op){
		return (LinphoneCall*)sal_op_get_user_pointer(op);
	}
	return NULL;
}
示例#3
0
static void notify(SalOp *op, const char *from, const char *msg){
	LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
	LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer (op);
	ms_message("get a %s notify from %s",msg,from);
	if(lc->vtable.notify_recv)
		lc->vtable.notify_recv(lc,call,from,msg);
}
示例#4
0
static void call_ack(SalOp *op){
	LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
	LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
	if (call==NULL){
		ms_warning("No call to be ACK'd");
		return ;
	}
	if (call->media_pending){
		SalMediaDescription *md=sal_call_get_final_media_description(op);
		if (md && !sal_media_description_empty(md)){
			if (call->state==LinphoneCallStreamsRunning){
				/*media was running before, the remote as acceted a call modification (that is
					a reinvite made by us. We must notify the application this reinvite was accepted*/
				linphone_call_set_state(call, LinphoneCallUpdated, "Call updated");
			}
			linphone_core_update_streams (lc,call,md);
			linphone_call_set_state (call,LinphoneCallStreamsRunning,"Connected (streams running)");
		}else{
			/*send a bye*/
			ms_error("Incompatible SDP response received in ACK, need to abort the call");
			linphone_core_abort_call(lc,call,"No codec intersection");
			return;
		}
	}
}
示例#5
0
static void text_delivery_update(SalOp *op, SalTextDeliveryStatus status, SalReason reason){
	LinphoneChatMessage *chat_msg=(LinphoneChatMessage* )sal_op_get_user_pointer(op);
	const MSList* calls;

	if (chat_msg == NULL) {
		// Do not handle delivery status for isComposing messages.
		return;
	}
	calls = linphone_core_get_calls(chat_msg->chat_room->lc);

	chat_msg->state=chatStatusSal2Linphone(status);
	chat_msg->reason=reason;
	linphone_chat_message_store_state(chat_msg);
	if (chat_msg && chat_msg->cb) {
		ms_message("Notifying text delivery with status %i",chat_msg->state);
		chat_msg->cb(chat_msg
			,chat_msg->state
			,chat_msg->cb_ud);
	}
	if (status != SalTextDeliveryInProgress) { /*don't release op if progress*/
		linphone_chat_message_destroy(chat_msg);

		if (!ms_list_find_custom((MSList*)calls, (MSCompareFunc) op_equals, op)) {
			/*op was only create for messaging purpose, destroying*/
			sal_op_release(op);
		}
	}
}
示例#6
0
/* this callback is called when an incoming re-INVITE modifies the session*/
static void call_updating(SalOp *op){
	LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
	LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
	SalMediaDescription *rmd=sal_call_get_remote_media_description(op);

	if (rmd==NULL){
		/* case of a reINVITE without SDP */
		call_accept_update(lc,call);
		call->expect_media_in_ack=TRUE;
		return;
	}

	switch(call->state){
		case LinphoneCallPausedByRemote:
			if (sal_media_description_has_dir(rmd,SalStreamSendRecv) || sal_media_description_has_dir(rmd,SalStreamRecvOnly)){
				call_resumed(lc,call);
			}else call_paused_by_remote(lc,call);
		break;
		case LinphoneCallStreamsRunning:
		case LinphoneCallConnected:
			if (sal_media_description_has_dir(rmd,SalStreamSendOnly) || sal_media_description_has_dir(rmd,SalStreamInactive)){
				call_paused_by_remote(lc,call);
			}else{
				call_updated_by_remote(lc,call);
			}
		break;
		default:
			call_accept_update(lc,call);
	}
}
示例#7
0
static void refer_received(Sal *sal, SalOp *op, const char *referto){
	LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal);
	LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
	if (call){
		if (call->refer_to!=NULL){
			ms_free(call->refer_to);
		}
		call->refer_to=ms_strdup(referto);
		call->refer_pending=TRUE;
		linphone_call_set_state(call,LinphoneCallRefered,"Refered");
		if (lc->vtable.display_status){
			char *msg=ms_strdup_printf(_("We are transferred to %s"),referto);
			lc->vtable.display_status(lc,msg);
			ms_free(msg);
		}
		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);
		sal_call_accept_refer(op);
	}
}
示例#8
0
/* this callback is called when an incoming re-INVITE modifies the session*/
static void call_updating(SalOp *op){
	LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
	LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
	LinphoneCallState prevstate=LinphoneCallIdle;
	SalMediaDescription *md;
	
	md=sal_call_get_final_media_description(op);
	
	if (md && !sal_media_description_empty(md))
	{
		if (sal_media_description_has_dir(call->localdesc,SalStreamSendRecv)){
			ms_message("Our local status is SalStreamSendRecv");
			if (sal_media_description_has_dir (md,SalStreamRecvOnly) || sal_media_description_has_dir(md,SalStreamInactive)){
				/* we are being paused */
				if(lc->vtable.display_status)
					lc->vtable.display_status(lc,_("We are being paused..."));
				linphone_call_set_state (call,LinphoneCallPausedByRemote,"Call paused by remote");
			}else if (!sal_media_description_has_dir(call->resultdesc,SalStreamSendRecv) && sal_media_description_has_dir(md,SalStreamSendRecv)){
				if(lc->vtable.display_status)
					lc->vtable.display_status(lc,_("We have been resumed..."));
				linphone_call_set_state (call,LinphoneCallStreamsRunning,"Connected (streams running)");
				lc->current_call=call;
			}else{
				prevstate=call->state;
				linphone_call_set_state(call, LinphoneCallUpdatedByRemote,"Call updated by remote");
			}
		}
		/*accept the modification (sends a 200Ok)*/
		sal_call_accept(op);
		linphone_core_update_streams (lc,call,md);
		if (prevstate!=LinphoneCallIdle){
			linphone_call_set_state (call,prevstate,"Connected (streams running)");
		}
	}
}
示例#9
0
void linphone_core_notify_info_message(LinphoneCore* lc,SalOp *op, const SalBody *body){
	LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
	if (call){
		LinphoneInfoMessage *info=ms_new0(LinphoneInfoMessage,1);
		info->headers=sal_custom_header_clone(sal_op_get_recv_custom_header(op));
		if (body) info->content=linphone_content_from_sal_body(body);
		linphone_core_notify_info_received(lc,call,info);
		linphone_info_message_destroy(info);
	}
}
示例#10
0
static void on_expire(SalOp *op){
	LinphoneEvent *lev=(LinphoneEvent*)sal_op_get_user_pointer(op);
	
	if (lev==NULL) return;
	
	if (linphone_event_get_publish_state(lev)==LinphonePublishOk){
		linphone_event_set_publish_state(lev,LinphonePublishExpiring);
	}else if (linphone_event_get_subscription_state(lev)==LinphoneSubscriptionActive){
		linphone_event_set_state(lev,LinphoneSubscriptionExpiring);
	}
}
示例#11
0
static void vfu_request(SalOp *op){
#ifdef VIDEO_ENABLED
	LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer (op);
	if (call==NULL){
		ms_warning("VFU request but no call !");
		return ;
	}
	if (call->videostream)
		video_stream_send_vfu(call->videostream);
#endif
}
示例#12
0
static void subscribe_received(SalOp *op, const char *eventname, const SalBody *body){
	LinphoneEvent *lev=(LinphoneEvent*)sal_op_get_user_pointer(op);
	LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
	
	if (lev==NULL) {
		lev=linphone_event_new_with_op(lc,op,LinphoneSubscriptionIncoming,eventname);
		linphone_event_set_state(lev,LinphoneSubscriptionIncomingReceived);
	}else{
		/*subscribe refresh, unhandled*/
	}
	
}
示例#13
0
static void ping_reply(SalOp *op){
	LinphoneCall *call=(LinphoneCall*) sal_op_get_user_pointer(op);
	ms_message("ping reply !");
	if (call){
		if (call->state==LinphoneCallOutgoingInit){
			linphone_core_start_invite(call->core,call,NULL);
		}
	}
	else
	{
		ms_warning("ping reply without call attached...");
	}
}
示例#14
0
static void subscribe_response(SalOp *op, SalSubscribeStatus status, SalError error, SalReason reason){
	LinphoneEvent *lev=(LinphoneEvent*)sal_op_get_user_pointer(op);
	
	if (lev==NULL) return;
	
	if (status==SalSubscribeActive){
		linphone_event_set_state(lev,LinphoneSubscriptionActive);
	}else if (status==SalSubscribePending){
		linphone_event_set_state(lev,LinphoneSubscriptionPending);
	}else{
		linphone_event_set_reason(lev, linphone_reason_from_sal(reason));
		linphone_event_set_state(lev,LinphoneSubscriptionError);
	}
}
示例#15
0
static void on_publish_response(SalOp* op, SalError err, SalReason reason){
	LinphoneEvent *lev=(LinphoneEvent*)sal_op_get_user_pointer(op);
	
	if (lev==NULL) return;
	if (err==SalErrorNone){
		if (!lev->terminating)
			linphone_event_set_publish_state(lev,LinphonePublishOk);
		else 
			linphone_event_set_publish_state(lev,LinphonePublishCleared);
		
	}else{
		linphone_event_set_reason(lev,linphone_reason_from_sal(reason));
		linphone_event_set_publish_state(lev,LinphonePublishError);
	}
}
示例#16
0
static void notify(SalOp *op, SalSubscribeStatus st, const char *eventname, const SalBody *body){
	LinphoneEvent *lev=(LinphoneEvent*)sal_op_get_user_pointer(op);
	LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
	LinphoneContent content;
	
	if (lev==NULL) {
		/*out of subscribe notify */
		lev=linphone_event_new_with_op(lc,op,LinphoneSubscriptionOutgoing,eventname);
	}
	if (lc->vtable.notify_received){
		const LinphoneContent *ct=linphone_content_from_sal_body(&content,body);
		if (ct) lc->vtable.notify_received(lc,lev,eventname,ct);
	}
	if (st!=SalSubscribeNone){
		linphone_event_set_state(lev,linphone_subscription_state_from_sal(st));
	}
}
示例#17
0
static void register_success(SalOp *op, bool_t registered){
	LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
	LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)sal_op_get_user_pointer(op);
	char *msg;
	
	cfg->registered=registered;
	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){
		if (cfg->registered) msg=ms_strdup_printf(_("Registration on %s successful."),sal_op_get_proxy(op));
		else msg=ms_strdup_printf(_("Unregistration on %s done."),sal_op_get_proxy(op));
		lc->vtable.display_status(lc,msg);
		ms_free(msg);
	}
	
}
示例#18
0
static void call_ringing(SalOp *h){
	LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h));
	LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(h);
	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 && lc->dmfs_playing_start_time!=0){
			ring_stop(lc->ringstream);
			lc->ringstream=NULL;
			lc->dmfs_playing_start_time=0;
		}
		if (lc->ringstream!=NULL) return;	/*already ringing !*/
		if (lc->sound_conf.play_sndcard!=NULL){
			MSSndCard *ringcard=lc->sound_conf.lsd_card ? lc->sound_conf.lsd_card : lc->sound_conf.play_sndcard;
			lc->ringstream=ring_start(lc->sound_conf.remote_ring,2000,ringcard);
		}
		ms_message("Remote ringing...");
		if (lc->vtable.display_status) 
			lc->vtable.display_status(lc,_("Remote ringing..."));
		linphone_call_set_state(call,LinphoneCallOutgoingRinging,"Remote ringing");
	}else{
		/*accept early media */
		if (call->audiostream && call->audiostream->ticker!=NULL){
			/*streams already started */
			ms_message("Early media already started.");
			return;
		}
		if (lc->vtable.show) lc->vtable.show(lc);
		if (lc->vtable.display_status) 
			lc->vtable.display_status(lc,_("Early media."));
		linphone_call_set_state(call,LinphoneCallOutgoingEarlyMedia,"Early media");
		if (lc->ringstream!=NULL){
			ring_stop(lc->ringstream);
			lc->ringstream=NULL;
		}
		ms_message("Doing early media...");
		linphone_core_update_streams (lc,call,md);
	}
}
示例#19
0
static void call_ringing(SalOp *h){
	LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h));
	LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(h);
	SalMediaDescription *md;
	
	if (call==NULL) return;
	
	/*set privacy*/
	call->current_params.privacy=(LinphonePrivacyMask)sal_op_get_privacy(call->op);

	if (lc->vtable.display_status)
		lc->vtable.display_status(lc,_("Remote ringing."));
	
	md=sal_call_get_final_media_description(h);
	if (md==NULL){
		linphone_core_stop_dtmf_stream(lc);
		if (lc->ringstream!=NULL) return;/*already ringing !*/
		if (lc->sound_conf.play_sndcard!=NULL){
			MSSndCard *ringcard=lc->sound_conf.lsd_card ? lc->sound_conf.lsd_card : lc->sound_conf.play_sndcard;
			if (call->localdesc->streams[0].max_rate>0) ms_snd_card_set_preferred_sample_rate(ringcard, call->localdesc->streams[0].max_rate);
			/*we release sound before playing ringback tone*/
			if (call->audiostream)
				audio_stream_unprepare_sound(call->audiostream);
			lc->ringstream=ring_start(lc->sound_conf.remote_ring,2000,ringcard);
		}
		ms_message("Remote ringing...");
		if (lc->vtable.display_status) 
			lc->vtable.display_status(lc,_("Remote ringing..."));
		linphone_call_set_state(call,LinphoneCallOutgoingRinging,"Remote ringing");
	}else{
		/*accept early media */
		if (call->audiostream && audio_stream_started(call->audiostream)){
			/*streams already started */
			ms_message("Early media already started.");
			return;
		}
		if (lc->vtable.show) lc->vtable.show(lc);
		if (lc->vtable.display_status) 
			lc->vtable.display_status(lc,_("Early media."));
		linphone_call_set_state(call,LinphoneCallOutgoingEarlyMedia,"Early media");
		linphone_core_stop_ringing(lc);
		ms_message("Doing early media...");
		linphone_core_update_streams(lc,call,md);
	}
}
示例#20
0
static void call_ack(SalOp *op){
	LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
	LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
	if (call==NULL){
		ms_warning("No call to be ACK'd");
		return ;
	}
	if (call->expect_media_in_ack){
		SalMediaDescription *md=sal_call_get_final_media_description(op);
		if (md && !sal_media_description_empty(md)){
			linphone_core_update_streams(lc,call,md);
			linphone_call_set_state (call,LinphoneCallStreamsRunning,"Connected (streams running)");
		}else{
			/*send a bye*/
			ms_error("Incompatible SDP response received in ACK, need to abort the call");
			linphone_core_abort_call(lc,call,"No codec intersection");
			return;
		}
	}
}
示例#21
0
static void call_terminated(SalOp *op, const char *from){
	LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
	LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);

	if (call==NULL) return;
	
	switch(linphone_call_get_state(call)){
		case LinphoneCallEnd:
		case LinphoneCallError:
			ms_warning("call_terminated: ignoring.");
			return;
		break;
		case LinphoneCallIncomingReceived:
		case LinphoneCallIncomingEarlyMedia:
			call->reason=LinphoneReasonNotAnswered;
		break;
		default:
		break;
	}
	ms_message("Current call terminated...");
	if (call->refer_pending){
		linphone_core_start_refered_call(lc,call,NULL);
	}
	//we stop the call only if we have this current call or if we are in call
	if (lc->ringstream!=NULL && ( (ms_list_size(lc->calls)  == 1) || linphone_core_in_call(lc) )) {
		linphone_core_stop_ringing(lc);
	}
	linphone_call_stop_media_streams(call);
	if (lc->vtable.show!=NULL)
		lc->vtable.show(lc);
	if (lc->vtable.display_status!=NULL)
		lc->vtable.display_status(lc,_("Call terminated."));

#ifdef BUILD_UPNP
	linphone_call_delete_upnp_session(call);
#endif //BUILD_UPNP

	linphone_call_set_state(call, LinphoneCallEnd,"Call ended");
}
示例#22
0
static void register_failure(SalOp *op, SalError error, SalReason reason, const char *details){
	LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
	LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)sal_op_get_user_pointer(op);

	if (cfg==NULL){
		ms_warning("Registration failed for unknown proxy config.");
		return ;
	}
	if (details==NULL)
		details=_("no response timeout");
	
	if (lc->vtable.display_status) {
		char *msg=ortp_strdup_printf(_("Registration on %s failed: %s"),sal_op_get_proxy(op),details  );
		lc->vtable.display_status(lc,msg);
		ms_free(msg);
	}
	if (error== SalErrorFailure && reason == SalReasonForbidden) {
		linphone_proxy_config_set_error(cfg, LinphoneReasonBadCredentials);
	} else if (error == SalErrorNoResponse) {
		linphone_proxy_config_set_error(cfg, LinphoneReasonNoResponse);
	}
	linphone_proxy_config_set_state(cfg,LinphoneRegistrationFailed,details);
}
示例#23
0
static void register_failure(SalOp *op, SalError error, SalReason reason, const char *details){
	LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
	LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)sal_op_get_user_pointer(op);

	if (cfg==NULL){
		ms_warning("Registration failed for unknown proxy config.");
		return ;
	}
	if (cfg->deletion_date!=0){
		ms_message("Registration failed for removed proxy config, ignored");
		return;
	}
	if (details==NULL)
		details=_("no response timeout");
	
	if (lc->vtable.display_status) {
		char *msg=ortp_strdup_printf(_("Registration on %s failed: %s"),sal_op_get_proxy(op),details  );
		lc->vtable.display_status(lc,msg);
		ms_free(msg);
	}

	linphone_proxy_config_set_error(cfg,linphone_reason_from_sal(reason));

	if (error== SalErrorFailure
			&& reason == SalReasonServiceUnavailable
			&& linphone_proxy_config_get_state(cfg) == LinphoneRegistrationOk) {
		linphone_proxy_config_set_state(cfg,LinphoneRegistrationProgress,_("Service unavailable, retrying"));
	} else {
		linphone_proxy_config_set_state(cfg,LinphoneRegistrationFailed,details);
	}
	if (cfg->publish_op){
		/*prevent publish to be sent now until registration gets successful*/
		sal_op_release(cfg->publish_op);
		cfg->publish_op=NULL;
		cfg->send_publish=cfg->publish;
	}
}
示例#24
0
static void call_terminated(SalOp *op, const char *from){
	LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
	LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);

	if (call==NULL) return;
	
	if (linphone_call_get_state(call)==LinphoneCallEnd || linphone_call_get_state(call)==LinphoneCallError){
		ms_warning("call_terminated: ignoring.");
		return;
	}
	ms_message("Current call terminated...");
	//we stop the call only if we have this current call or if we are in call
	if (lc->ringstream!=NULL && ( (ms_list_size(lc->calls)  == 1) || linphone_core_in_call(lc) )) {
		ring_stop(lc->ringstream);
		lc->ringstream=NULL;
	}
	linphone_call_stop_media_streams(call);
	if (lc->vtable.show!=NULL)
		lc->vtable.show(lc);
	if (lc->vtable.display_status!=NULL)
		lc->vtable.display_status(lc,_("Call terminated."));

	linphone_call_set_state(call, LinphoneCallEnd,"Call ended");
}
示例#25
0
static void subscribe_closed(SalOp *op){
	LinphoneEvent *lev=(LinphoneEvent*)sal_op_get_user_pointer(op);
	
	linphone_event_set_state(lev,LinphoneSubscriptionTerminated);
}
示例#26
0
static void dtmf_received(SalOp *op, char dtmf){
	LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
	LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
	if (lc->vtable.dtmf_received != NULL)
		lc->vtable.dtmf_received(lc, call, dtmf);
}
示例#27
0
static void call_released(SalOp *op){
	LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
	if (call!=NULL){
		linphone_call_set_state(call,LinphoneCallReleased,"Call released");
	}else ms_error("call_released() for already destroyed call ?");
}
示例#28
0
static void call_failure(SalOp *op, SalError error, SalReason sr, const char *details, int code){
	LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
	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.");
	const char *msg=details;
	LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
	LinphoneCall *referer=call->referer;

	if (call==NULL){
		ms_warning("Call faillure reported on already terminated call.");
		return ;
	}
	
	if (lc->vtable.show) lc->vtable.show(lc);

	if (error==SalErrorNoResponse){
		msg=_("No response.");
		if (lc->vtable.display_status)
			lc->vtable.display_status(lc,msg);
	}else if (error==SalErrorProtocol){
		msg=details ? details : _("Protocol error.");
		if (lc->vtable.display_status)
			lc->vtable.display_status(lc, msg);
	}else if (error==SalErrorFailure){
		switch(sr){
			case SalReasonDeclined:
				msg=msg603;
				if (lc->vtable.display_status)
					lc->vtable.display_status(lc,msg603);
			break;
			case SalReasonBusy:
				msg=msg486;
				if (lc->vtable.display_status)
					lc->vtable.display_status(lc,msg486);
			break;
			case SalReasonRedirect:
			{
				ms_error("case SalReasonRedirect");
				linphone_call_stop_media_streams(call);
				if (	call->state==LinphoneCallOutgoingInit
						|| call->state==LinphoneCallOutgoingProgress
						|| call->state==LinphoneCallOutgoingRinging /*push case*/
						|| call->state==LinphoneCallOutgoingEarlyMedia){
					LinphoneAddress* redirection_to = (LinphoneAddress*)sal_op_get_remote_contact_address(call->op);
					if( redirection_to ){
						char* url = linphone_address_as_string(redirection_to);
						ms_error("Redirecting call [%p] to %s",call, url);
						ms_free(url);
						linphone_call_create_op(call);
						linphone_core_start_invite(lc, call, redirection_to);
						return;
					}
				}
				msg=_("Redirected");
				if (lc->vtable.display_status)
					lc->vtable.display_status(lc,msg);
			}
			break;
			case SalReasonTemporarilyUnavailable:
				msg=msg480;
				if (lc->vtable.display_status)
					lc->vtable.display_status(lc,msg480);
			break;
			case SalReasonNotFound:
				if (lc->vtable.display_status)
					lc->vtable.display_status(lc,msg);
			break;
			case SalReasonDoNotDisturb:
				msg=msg600;
				if (lc->vtable.display_status)
					lc->vtable.display_status(lc,msg600);
			break;
			case SalReasonUnsupportedContent: /*<this is for compatibility: linphone sent 415 because of SDP offer answer failure*/
			case SalReasonNotAcceptable:
			//media_encryption_mandatory
				if (call->params.media_encryption == LinphoneMediaEncryptionSRTP && 
					!linphone_core_is_media_encryption_mandatory(lc)) {
					int i;
					ms_message("Outgoing call [%p] failed with SRTP (SAVP) enabled",call);
					linphone_call_stop_media_streams(call);
					if (	call->state==LinphoneCallOutgoingInit
							|| call->state==LinphoneCallOutgoingProgress
							|| call->state==LinphoneCallOutgoingRinging /*push case*/
							|| call->state==LinphoneCallOutgoingEarlyMedia){
						ms_message("Retrying call [%p] with AVP",call);
						/* clear SRTP local params */
						call->params.media_encryption = LinphoneMediaEncryptionNone;
						for(i=0; i<call->localdesc->n_active_streams; i++) {
							call->localdesc->streams[i].proto = SalProtoRtpAvp;
							memset(call->localdesc->streams[i].crypto, 0, sizeof(call->localdesc->streams[i].crypto));
						}
						linphone_core_restart_invite(lc, call);
						return;
					}

				}
				msg=_("Incompatible media parameters.");
				if (lc->vtable.display_status)
					lc->vtable.display_status(lc,msg);
			break;
			case SalReasonRequestPending:
				/*restore previous state, the application will decide to resubmit the action if relevant*/
				call->reason=linphone_reason_from_sal(sr);
				linphone_call_set_state(call,call->prevstate,msg);
				return;
			break;
			default:
				if (lc->vtable.display_status)
					lc->vtable.display_status(lc,_("Call failed."));
		}
	}

	/*some call error are not fatal*/
	switch (call->state) {
	case LinphoneCallUpdating:
	case LinphoneCallPausing:
	case LinphoneCallResuming:
		ms_message("Call error on state [%s], restoring previous state",linphone_call_state_to_string(call->prevstate));
		call->reason=linphone_reason_from_sal(sr);
		linphone_call_set_state(call, call->prevstate,details);
		return;
	default:
		break; /*nothing to do*/
	}

	linphone_core_stop_ringing(lc);
	linphone_call_stop_media_streams(call);

#ifdef BUILD_UPNP
	linphone_call_delete_upnp_session(call);
#endif //BUILD_UPNP
	
	call->reason=linphone_reason_from_sal(sr);
	if (sr==SalReasonDeclined){
		linphone_call_set_state(call,LinphoneCallEnd,"Call declined.");
	}else{
		linphone_call_set_state(call,LinphoneCallError,details);
		if (sr==SalReasonBusy)
			linphone_core_play_named_tone(lc,LinphoneToneBusy);
	}
	
	if (referer){
		/*notify referer of the failure*/
		linphone_core_notify_refer_state(lc,referer,call);
		/*schedule automatic resume of the call. This must be done only after the notifications are completed due to dialog serialization of requests.*/
		linphone_core_queue_task(lc,(belle_sip_source_func_t)resume_call_after_failed_transfer,linphone_call_ref(referer),"Automatic call resuming after failed transfer");
	}
}
示例#29
0
/*
 * could be reach :
 *  - when the call is accepted
 *  - when a request is accepted (pause, resume)
 */
static void call_accepted(SalOp *op){
	LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
	LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
	SalMediaDescription *md;
	
	if (call==NULL){
		ms_warning("No call to accept.");
		return ;
	}
	/*set privacy*/
	call->current_params.privacy=(LinphonePrivacyMask)sal_op_get_privacy(call->op);

	/* Handle remote ICE attributes if any. */
	if (call->ice_session != NULL) {
		linphone_core_update_ice_from_remote_media_description(call, sal_call_get_remote_media_description(op));
	}
#ifdef BUILD_UPNP
	if (call->upnp_session != NULL) {
		linphone_core_update_upnp_from_remote_media_description(call, sal_call_get_remote_media_description(op));
	}
#endif //BUILD_UPNP

	md=sal_call_get_final_media_description(op);
	if (md) /*make sure re-invite will not propose video again*/
		call->params.has_video &= linphone_core_media_description_contains_video_stream(md);
	
	if (call->state==LinphoneCallOutgoingProgress ||
	    call->state==LinphoneCallOutgoingRinging ||
	    call->state==LinphoneCallOutgoingEarlyMedia){
		linphone_call_set_state(call,LinphoneCallConnected,"Connected");
		if (call->referer) linphone_core_notify_refer_state(lc,call->referer,call);
	}
	if (md && !sal_media_description_empty(md) && !linphone_core_incompatible_security(lc,md)){
		linphone_call_update_remote_session_id_and_ver(call);
		if (sal_media_description_has_dir(md,SalStreamSendOnly) ||
		    sal_media_description_has_dir(md,SalStreamInactive)){
			if (lc->vtable.display_status){
				char *tmp=linphone_call_get_remote_address_as_string (call);
				char *msg=ms_strdup_printf(_("Call with %s is paused."),tmp);
				lc->vtable.display_status(lc,msg);
				ms_free(tmp);
				ms_free(msg);
			}
			linphone_core_update_streams (lc,call,md);
			linphone_call_set_state(call,LinphoneCallPaused,"Call paused");
			if (call->refer_pending)
				linphone_core_start_refered_call(lc,call,NULL);
		}else if (sal_media_description_has_dir(md,SalStreamRecvOnly)){
			/*we are put on hold when the call is initially accepted */
			if (lc->vtable.display_status){
				char *tmp=linphone_call_get_remote_address_as_string (call);
				char *msg=ms_strdup_printf(_("Call answered by %s - on hold."),tmp);
				lc->vtable.display_status(lc,msg);
				ms_free(tmp);
				ms_free(msg);
			}
			linphone_core_update_streams (lc,call,md);
			linphone_call_set_state(call,LinphoneCallPausedByRemote,"Call paused by remote");
		}else{
			if (call->state!=LinphoneCallUpdating){
				if (call->state==LinphoneCallResuming){
					if (lc->vtable.display_status){
						lc->vtable.display_status(lc,_("Call resumed."));
					}
				}else{
					if (lc->vtable.display_status){
						char *tmp=linphone_call_get_remote_address_as_string (call);
						char *msg=ms_strdup_printf(_("Call answered by %s."),tmp);
						lc->vtable.display_status(lc,msg);
						ms_free(tmp);
						ms_free(msg);
					}
				}
			}
			linphone_core_update_streams(lc,call,md);
			/*also reflect the change if the "wished" params, in order to avoid to propose SAVP or video again
			* further in the call, for example during pause,resume, conferencing reINVITEs*/
			linphone_call_fix_call_parameters(call);
			if (!call->current_params.in_conference)
				lc->current_call=call;
			linphone_call_set_state(call, LinphoneCallStreamsRunning, "Streams running");
		}
	}else{
		/*send a bye*/
		ms_error("Incompatible SDP offer received in 200Ok, need to abort the call");
		linphone_core_abort_call(lc,call,_("Incompatible, check codecs or security settings..."));
	}
}
示例#30
0
/**
 * Adds authentication information to the LinphoneCore.
 *
 * This information will be used during all SIP transactions that require authentication.
**/
void linphone_core_add_auth_info(LinphoneCore *lc, const LinphoneAuthInfo *info){
	LinphoneAuthInfo *ai;
	bctbx_list_t *elem;
	bctbx_list_t *l;
	int restarted_op_count=0;
	bool_t updating=FALSE;

	if (info->ha1==NULL && info->passwd==NULL){
		ms_warning("linphone_core_add_auth_info(): info supplied with empty password or ha1.");
	}
	/* find if we are attempting to modify an existing auth info */
	ai=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,info->realm,info->username,info->domain);
	if (ai!=NULL && ai->domain && info->domain && strcmp(ai->domain, info->domain)==0){
		lc->auth_info=bctbx_list_remove(lc->auth_info,ai);
		linphone_auth_info_destroy(ai);
		updating=TRUE;
	}
	lc->auth_info=bctbx_list_append(lc->auth_info,linphone_auth_info_clone(info));

	/* retry pending authentication operations */
	for(l=elem=sal_get_pending_auths(lc->sal);elem!=NULL;elem=elem->next){
		SalOp *op=(SalOp*)elem->data;
		LinphoneAuthInfo *ai;
		const SalAuthInfo *req_sai=sal_op_get_auth_requested(op);
		ai=(LinphoneAuthInfo*)_linphone_core_find_auth_info(lc,req_sai->realm,req_sai->username,req_sai->domain, FALSE);
		if (ai){
			SalAuthInfo sai;
			bctbx_list_t* proxy;
			sai.username=ai->username;
			sai.userid=ai->userid;
			sai.realm=ai->realm;
			sai.password=ai->passwd;
			sai.ha1=ai->ha1;
			if (ai->tls_cert && ai->tls_key) {
				sal_certificates_chain_parse(&sai, ai->tls_cert, SAL_CERTIFICATE_RAW_FORMAT_PEM);
				sal_signing_key_parse(&sai, ai->tls_key, "");
			} else if (ai->tls_cert_path && ai->tls_key_path) {
				sal_certificates_chain_parse_file(&sai, ai->tls_cert_path, SAL_CERTIFICATE_RAW_FORMAT_PEM);
				sal_signing_key_parse_file(&sai, ai->tls_key_path, "");
			}
			/*proxy case*/
			for (proxy=(bctbx_list_t*)linphone_core_get_proxy_config_list(lc);proxy!=NULL;proxy=proxy->next) {
				if (proxy->data == sal_op_get_user_pointer(op)) {
					linphone_proxy_config_set_state((LinphoneProxyConfig*)(proxy->data),LinphoneRegistrationProgress,"Authentication...");
					break;
				}
			}
			sal_op_authenticate(op,&sai);
			restarted_op_count++;
		}
	}
	if (l){
		ms_message("linphone_core_add_auth_info(): restarted [%i] operation(s) after %s auth info for\n"
			"\tusername: [%s]\n"
			"\trealm [%s]\n"
			"\tdomain [%s]\n",
			restarted_op_count,
			updating ? "updating" : "adding",
			info->username ? info->username : "",
			info->realm ? info->realm : "",
			info->domain ? info->domain : "");
	}
	bctbx_list_free(l);
	write_auth_infos(lc);
}