Example #1
0
/** internal fuction used to config a SIP action */
int _tsip_action_set(tsip_action_handle_t* self, va_list* app)
{
	tsip_action_param_type_t curr;
	tsip_action_t* action = self;
	
	if(!action){ /* Nothing to do */
		return 0;
	}
	
	while((curr = va_arg(*app, tsip_action_param_type_t)) != aptype_null){

		switch(curr){
				case aptype_header:
					{	/* (const char*)NAME_STR, (const char*)VALUE_STR */
						const char* name = va_arg(*app, const char *);
						const char* value = va_arg(*app, const char *);

						tsk_params_add_param(&action->headers, name, value);
						break;
					}
				case aptype_config:
					{ /* (const tsip_action_handle_t*)ACTION_CONFIG_HANDLE */
						const tsip_action_t* handle = va_arg(*app, const tsip_action_handle_t *);
						if(handle && handle->type == tsip_atype_config){
							/* Copy headers */
							if(!TSK_LIST_IS_EMPTY(handle->headers)){
								tsk_list_pushback_list(action->headers, handle->headers);
							}
							/* Copy payload */
							if(handle->payload && handle->payload->data && handle->payload->size){
								TSK_OBJECT_SAFE_FREE(action->payload);
								action->payload = tsk_buffer_create(handle->payload->data, handle->payload->size);
							}
							/* Copy resp line */
							action->line_resp.code = handle->line_resp.code;
							tsk_strupdate(&action->line_resp.phrase, handle->line_resp.phrase);
							/* Copy media params */
							if(!TSK_LIST_IS_EMPTY(handle->media.params)){ 
								if(!action->media.params){
									action->media.params = tmedia_params_create();
								}
								tsk_list_pushback_list(action->media.params, handle->media.params);
							}
						}
						else if(handle){ /* Only invalid type should cause error */
							TSK_DEBUG_ERROR("Invalid action configuration handle.");
							return -2;
						}
						break;
					}
				case aptype_payload:
					{	/* (const void*)PAY_PTR, (tsk_size_t)PAY_SIZE */
						const void* payload = va_arg(*app, const void *);
						tsk_size_t size = va_arg(*app, tsk_size_t);
						if(payload && size){
							TSK_OBJECT_SAFE_FREE(action->payload);
							action->payload = tsk_buffer_create(payload, size);
						}
						break;
					}
				
				case aptype_resp_line:
					{	/* (int32_t)CODE_INT, (const char*)PHRASE_STR */
						int32_t code = va_arg(*app, int32_t);
						const char* phrase = va_arg(*app, const void *);
						action->line_resp.code = (short)code;
						tsk_strupdate(&action->line_resp.phrase, phrase);
						break;
					}

				case aptype_media:
					{	/* ... */
						tmedia_params_L_t* params;
						if((params = tmedia_params_create_2(app))){
							if(action->media.params){
								tsk_list_pushback_list(action->media.params, params);
							}
							else{
								action->media.params = tsk_object_ref(params);
							}
							TSK_OBJECT_SAFE_FREE(params);
						}
						break;
					}

				default:
					{	/* va_list will be unsafe ==> exit */
						TSK_DEBUG_ERROR("NOT SUPPORTED.");
						return -3;
					}
		} /* switch */
	} /* while */

	return 0;
}
/* Started -> (oINVITE) -> Outgoing
*/
int c0000_Started_2_Outgoing_X_oINVITE(va_list *app)
{
	int ret;
	tsip_dialog_invite_t *self;
	const tsip_action_t* action;

	self = va_arg(*app, tsip_dialog_invite_t *);
	va_arg(*app, const tsip_message_t *);
	action = va_arg(*app, const tsip_action_t *);
	
	/* This is the first FSM transaction when you try to make an audio/video/msrp call */
	if(!self->msession_mgr){
		int32_t transport_idx = TSIP_DIALOG_GET_STACK(self)->network.transport_idx_default;
		self->msession_mgr = tmedia_session_mgr_create(action ? action->media.type : tmedia_all,
			TSIP_DIALOG_GET_STACK(self)->network.local_ip[transport_idx], TNET_SOCKET_TYPE_IS_IPV6(TSIP_DIALOG_GET_STACK(self)->network.proxy_cscf_type[transport_idx]), tsk_true);
		if(TSIP_DIALOG_GET_STACK(self)->natt.ctx){
			ret = tmedia_session_mgr_set_natt_ctx(self->msession_mgr, TSIP_DIALOG_GET_STACK(self)->natt.ctx, TSIP_DIALOG_GET_STACK(self)->network.aor.ip[transport_idx]);
		}
		
		ret = tmedia_session_mgr_set_ice_ctx(self->msession_mgr, self->ice.ctx_audio, self->ice.ctx_video);
		ret = tsip_dialog_invite_msession_configure(self);
	}

	/* We are the client */
	self->is_client = tsk_true;
	/* Whether it's a client dialog for call transfer */
	self->is_transf = (TSIP_DIALOG_GET_SS(self)->id_parent != TSIP_SSESSION_INVALID_ID);

	/* Get Media type from the action */
	TSIP_DIALOG_GET_SS(self)->media.type = action->media.type;
	/* Appy media params received from the user */
	if(!TSK_LIST_IS_EMPTY(action->media.params)){
		tmedia_session_mgr_set_3(self->msession_mgr, action->media.params);
	}

	/*  RFC 4028 - 7.1. Generating an Initial Session Refresh Request

		A UAC MAY include a Session-Expires header field in an initial
		session refresh request if it wants a session timer applied to the
		session.  The value of this header field indicates the session
		interval desired by the UAC.  If a Min-SE header is included in the
		initial session refresh request, the value of the Session-Expires
		MUST be greater than or equal to the value in Min-SE.

		The UAC MAY include the refresher parameter with value 'uac' if it
		wants to perform the refreshes.  However, it is RECOMMENDED that the
		parameter be omitted so that it can be selected by the negotiation
		mechanisms described below.
	*/
	if(TSIP_DIALOG_GET_SS(self)->media.timers.timeout){
		self->stimers.timer.timeout = TSIP_DIALOG_GET_SS(self)->media.timers.timeout;
		tsk_strupdate(&self->stimers.refresher, TSIP_DIALOG_GET_SS(self)->media.timers.refresher);
		self->stimers.is_refresher = tsk_striequals(self->stimers.refresher, "uac");
		self->supported.timer = tsk_true;
	}
	
	/* QoS
	* One Voice Profile - 5.4.1 SIP Precondition Considerations
	* The UE shall use the Supported header, and not the Require header, to indicate the support of precondition in
	* accordance with Section 5.1.3.1 of 3GPP TS 24.229.
	*/
	self->qos.type = TSIP_DIALOG_GET_SS(self)->media.qos.type;
	self->qos.strength = TSIP_DIALOG_GET_SS(self)->media.qos.strength;
	tmedia_session_mgr_set_qos(self->msession_mgr, self->qos.type, self->qos.strength);
	self->supported.precondition = (self->qos.strength == tmedia_qos_strength_optional);
	self->required.precondition = (self->qos.strength == tmedia_qos_strength_mandatory);

	/* send the request */
	ret = send_INVITE(self, tsk_false);

	/* alert the user */
	TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_connecting, "Dialog connecting");

	return ret;
}