/* Outgoing -> (i2xx INVITE) -> Connected */ int c0000_Outgoing_2_Connected_X_i2xxINVITE(va_list *app) { int ret; tsip_dialog_invite_t *self = va_arg(*app, tsip_dialog_invite_t *); const tsip_response_t *r2xxINVITE = va_arg(*app, const tsip_response_t *); /* const tsip_action_t* action = */ va_arg(*app, const tsip_action_t *); /* Update the dialog state */ if((ret = tsip_dialog_update(TSIP_DIALOG(self), r2xxINVITE))){ return ret; } /* Process remote offer */ if((ret = tsip_dialog_invite_process_ro(self, r2xxINVITE))){ send_BYE(self); return ret; } else{ /* send ACK */ ret = send_ACK(self, r2xxINVITE); } /* Determine whether the remote party support UPDATE */ self->support_update = tsip_message_allowed(r2xxINVITE, "UPDATE"); /* Session Timers */ if(self->stimers.timer.timeout){ tsip_dialog_invite_stimers_handle(self, r2xxINVITE); } // starts ICE timers now that both parties received the "candidates" if(tsip_dialog_invite_ice_is_enabled(self)){ tsip_dialog_invite_ice_timers_set(self, (self->required.ice ? -1 : TSIP_DIALOG_INVITE_ICE_CONNCHECK_TIMEOUT)); } /* Alert the user (session) */ ret = TSIP_DIALOG_INVITE_SIGNAL(self, tsip_ao_request, TSIP_RESPONSE_CODE(r2xxINVITE), TSIP_RESPONSE_PHRASE(r2xxINVITE), r2xxINVITE); /* Alert the user (dialog) */ ret = TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_connected, "Dialog connected"); if(self->is_transf){ ret = tsip_dialog_invite_notify_parent(self, r2xxINVITE); self->is_transf = tsk_false;//final response -> no longer need to notify the parent } /* MSRP File Transfer */ /*if(TSIP_DIALOG(self)->curr_action && ((TSIP_DIALOG(self)->curr_action->media.type & tmedia_msrp) == tmedia_msrp)){ // FIXME tmedia_session_mgr_send_file(self->msession_mgr, "C:\\avatar.png", TMEDIA_SESSION_SET_NULL()); }*/ return ret; }
// Current -> (iINVITE) -> Current static int x0500_Current_2_Current_X_iINVITE(va_list *app) { int ret; tsip_dialog_invite_t *self; const tsip_action_t* action; const tsip_message_t *message; self = va_arg(*app, tsip_dialog_invite_t *); message = va_arg(*app, const tsip_message_t *); action = va_arg(*app, const tsip_action_t *); self->is_client = tsk_false; ret = tsip_dialog_invite_ice_save_action(self, _fsm_action_iINVITE, action, message); // Cancel without notifying ("silent mode") and perform the operation right now ("sync mode") tsip_dialog_invite_ice_cancel_silent_and_sync_ctx(self); // set remote candidates if(TSIP_MESSAGE_HAS_CONTENT(message)){ if(tsk_striequals("application/sdp", TSIP_MESSAGE_CONTENT_TYPE(message))){ tsdp_message_t* sdp_ro; if(!(sdp_ro = tsdp_message_parse(TSIP_MESSAGE_CONTENT_DATA(message), TSIP_MESSAGE_CONTENT_DATA_LENGTH(message)))){ TSK_DEBUG_ERROR("Failed to parse remote sdp message"); return -2; } // create ICE context if((ret = tsip_dialog_invite_ice_create_ctx(self, tmedia_type_from_sdp(sdp_ro)))){ TSK_DEBUG_ERROR("tsip_dialog_invite_ice_create_ctx() failed"); return ret; } ret = tsip_dialog_invite_ice_process_ro(self, sdp_ro, tsk_true); TSK_OBJECT_SAFE_FREE(sdp_ro); } else{ TSK_DEBUG_ERROR("[%s] content-type is not supportted", TSIP_MESSAGE_CONTENT_TYPE(message)); return -3; } } // For now disable ICE timers until we send the 2xx and receive the ACK ret = tsip_dialog_invite_ice_timers_set(self, -1); // Start ICE ret = tsip_dialog_invite_ice_start_ctx(self); return ret; }
// Current -> (oINVITE) -> Current static int x0500_Current_2_Current_X_oINVITE(va_list *app) { int ret; tsip_dialog_invite_t *self; const tsip_action_t* action; const tsip_message_t *message; tmedia_type_t media_type; static const tsk_bool_t __force_restart_is_yes = tsk_true; self = va_arg(*app, tsip_dialog_invite_t *); message = va_arg(*app, const tsip_message_t *); action = va_arg(*app, const tsip_action_t *); media_type = (action && action->media.type != tmedia_none) ? action->media.type : TSIP_DIALOG_GET_SS(self)->media.type; self->is_client = tsk_true; tsip_dialog_invite_ice_save_action(self, _fsm_action_oINVITE, action, message); // Cancel without notifying ("silent mode") and perform the operation right now ("sync mode") tsip_dialog_invite_ice_cancel_silent_and_sync_ctx(self); // create ICE context if((ret = tsip_dialog_invite_ice_create_ctx(self, media_type))){ TSK_DEBUG_ERROR("tsip_dialog_invite_ice_create_ctx() failed"); return ret; } // For now disable ICE timers until we receive the 2xx ret = tsip_dialog_invite_ice_timers_set(self, -1); // Start ICE ret = tsip_dialog_invite_ice_start_ctx(self); // alert the user only if we are in initial state which means that it's not media update if(TSIP_DIALOG(self)->state == tsip_initial){ TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_connecting, "Dialog connecting"); } return ret; }
static int tsip_dialog_invite_ice_create_ctx(tsip_dialog_invite_t * self, tmedia_type_t media_type) { int32_t transport_idx; if(!self){ TSK_DEBUG_ERROR("Invalid parameter"); return -1; } transport_idx = TSIP_DIALOG_GET_STACK(self)->network.transport_idx_default; if(!self->ice.ctx_audio && (media_type & tmedia_audio)){ self->ice.ctx_audio = tnet_ice_ctx_create(self->ice.is_jingle, TNET_SOCKET_TYPE_IS_IPV6(TSIP_DIALOG_GET_STACK(self)->network.proxy_cscf_type[transport_idx]), self->use_rtcp, tsk_false, tsip_dialog_invite_ice_audio_callback, self); if(!self->ice.ctx_audio){ TSK_DEBUG_ERROR("Failed to create ICE audio context"); return -2; } tnet_ice_ctx_set_stun(self->ice.ctx_audio, "stun.l.google.com", 19302, "Doubango", "*****@*****.**", "stun-password"); //FIXME tnet_ice_ctx_set_rtcpmux(self->ice.ctx_audio, self->use_rtcpmux); } if(!self->ice.ctx_video && (media_type & tmedia_video)){ self->ice.ctx_video = tnet_ice_ctx_create(self->ice.is_jingle, TNET_SOCKET_TYPE_IS_IPV6(TSIP_DIALOG_GET_STACK(self)->network.proxy_cscf_type[transport_idx]), self->use_rtcp, tsk_true, tsip_dialog_invite_ice_video_callback, self); if(!self->ice.ctx_video){ TSK_DEBUG_ERROR("Failed to create ICE video context"); return -2; } tnet_ice_ctx_set_stun(self->ice.ctx_video, "stun.l.google.com", 19302, "Doubango", "*****@*****.**", "stun-password"); // FIXME tnet_ice_ctx_set_rtcpmux(self->ice.ctx_video, self->use_rtcpmux); } // "none" comparison is used to exclude the "first call" if(self->ice.media_type != tmedia_none && self->ice.media_type != media_type){ // cancels contexts associated to old medias if(self->ice.ctx_audio && !(media_type & tmedia_audio)){ tnet_ice_ctx_cancel(self->ice.ctx_audio); } if(self->ice.ctx_video && !(media_type & tmedia_video)){ tnet_ice_ctx_cancel(self->ice.ctx_video); } // cancels contexts associated to new medias (e.g. session "remove" then "add") // cancel() on newly created contexts don't have any effect if(self->ice.ctx_audio && (!(media_type & tmedia_audio) && (self->ice.media_type & tmedia_audio))){ //tnet_ice_ctx_cancel(self->ice.ctx_audio); } if(self->ice.ctx_video && (!(media_type & tmedia_video) && (self->ice.media_type & tmedia_video))){ //tnet_ice_ctx_cancel(self->ice.ctx_video); } } self->ice.media_type = media_type; // For now disable timers until both parties get candidates // (RECV ACK) or RECV (200 OK) tsip_dialog_invite_ice_timers_set(self, -1); // update session manager with the right ICE contexts if(self->msession_mgr){ tmedia_session_mgr_set_ice_ctx(self->msession_mgr, self->ice.ctx_audio, self->ice.ctx_video); } return 0; }