Index: channels/chan_sip.c
===================================================================
--- channels/chan_sip.c	(revision 373380)
+++ channels/chan_sip.c	(working copy)
@@ -1392,7 +1392,7 @@
 static int process_sdp_a_video(const char *a, struct sip_pvt *p, struct ast_rtp_codecs *newvideortp, int *last_rtpmap_codec);
 static int process_sdp_a_text(const char *a, struct sip_pvt *p, struct ast_rtp_codecs *newtextrtp, char *red_fmtp, int *red_num_gen, int *red_data_pt, int *last_rtpmap_codec);
 static int process_sdp_a_image(const char *a, struct sip_pvt *p);
-static void add_ice_to_sdp(struct ast_rtp_instance *instance, struct ast_str **a_buf);
+static void add_ice_to_sdp(struct ast_rtp_instance *instance, int is_webrtc, struct ast_str **a_buf);
 static void add_dtls_to_sdp(struct ast_rtp_instance *instance, struct ast_str **a_buf);
 static void start_ice(struct ast_rtp_instance *instance);
 static void add_codec_to_sdp(const struct sip_pvt *p, struct ast_format *codec,
@@ -1686,6 +1686,9 @@
 static int sip_subscribe_mwi_do(const void *data);
 static int __sip_subscribe_mwi_do(struct sip_subscription_mwi *mwi);
 
+
+static int sip_pvt_is_webrtc(struct sip_pvt *p);
+
 /*! \brief Definition of this channel for PBX channel registration */
 struct ast_channel_tech sip_tech = {
 	.type = "SIP",
@@ -7421,6 +7424,11 @@
 		ast_rtp_instance_update_source(p->rtp);
 		ast_moh_stop(ast);
 		break;
+	case AST_CONTROL_RTCPFB: /* RTCP-FB frame to patch and forward to remote peer */
+		if(p->vrtp && !p->novideo){
+			ast_rtp_instance_rtcpfb(p->vrtp, (void*)data, (unsigned int)datalen);
+		}
+		break;
 	case AST_CONTROL_VIDUPDATE:	/* Request a video frame update */
 		if (p->vrtp && !p->novideo) {
 			transmit_info_with_vidupdate(p);
@@ -10489,7 +10497,7 @@
 {
 	struct ast_rtp_engine_ice *ice;
 	int found = FALSE;
-	char ufrag[256], pwd[256], foundation[32], transport[4], address[46], cand_type[6], relay_address[46] = "";
+	char ufrag[256], pwd[256], foundation[32], transport[4], address[46], cand_type[6], next_att[24] = "", relay_address[46] = "";
 	struct ast_rtp_engine_ice_candidate candidate = { 0, };
 	int port, relay_port = 0;
 
@@ -10503,10 +10511,11 @@
 	} else if (sscanf(a, "ice-pwd: %255s", pwd) == 1) {
 		ice->set_authentication(instance, NULL, pwd);
 		found = TRUE;
-	} else if (sscanf(a, "candidate: %31s %30u %3s %30u %23s %30u typ %5s %*s %23s %*s %30u", foundation, &candidate.id, transport, &candidate.priority,
-			  address, &port, cand_type, relay_address, &relay_port) >= 7) {
+	} else if (sscanf(a, "candidate: %31s %30u %3s %30u %23s %30u typ %5s %s %23s %*s %30u", foundation, &candidate.id, transport, &candidate.priority,
+			  address, &port, cand_type, next_att, relay_address, &relay_port) >= 7) {
 		candidate.foundation = foundation;
 		candidate.transport = transport;
+		candidate.is_webrtc = (sip_pvt_is_webrtc(p) || (!strcasecmp(next_att, "generation") || !strcasecmp(next_att, "name"))); // (WS, WSS or UDP+webrtc4IE)
 
 		ast_sockaddr_parse(&candidate.address, address, PARSE_PORT_FORBID);
 		ast_sockaddr_set_port(&candidate.address, port);
@@ -10705,7 +10714,7 @@
 		/* We have a rtpmap to handle */
 		if (*last_rtpmap_codec < SDP_MAX_RTPMAP_CODECS) {
 			/* Note: should really look at the '#chans' params too */
-			if (!strncasecmp(mimeSubtype, "H26", 3) || !strncasecmp(mimeSubtype, "MP4", 3)) {
+			if (!strncasecmp(mimeSubtype, "H26", 3) || !strncasecmp(mimeSubtype, "MP4", 3) /*|| !strncasecmp(mimeSubtype, "VP8", 3)*/) {
 				if (!(ast_rtp_codecs_payloads_set_rtpmap_type_rate(newvideortp, NULL, codec, "video", mimeSubtype, 0, sample_rate))) {
 					if (debug)
 						ast_verbose("Found video description format %s for ID %d\n", mimeSubtype, codec);
@@ -12117,7 +12126,7 @@
 }
 
 /*! \brief Add ICE attributes to SDP */
-static void add_ice_to_sdp(struct ast_rtp_instance *instance, struct ast_str **a_buf)
+static void add_ice_to_sdp(struct ast_rtp_instance *instance, int is_webrtc, struct ast_str **a_buf)
 {
 	struct ast_rtp_engine_ice *ice = ast_rtp_instance_get_ice(instance);
 	const char *username, *password;
@@ -12136,10 +12145,22 @@
 	if ((password = ice->get_password(instance))) {
 		ast_str_append(a_buf, 0, "a=ice-pwd:%s\r\n", password);
 	}
+	if (is_webrtc){
+		static const char* webrtc_ice_type = "google-ice";
+		ast_str_append(a_buf, 0, "a=ice-options:%s\r\n", webrtc_ice_type);
+	}
 
 	i = ao2_iterator_init(candidates, 0);
 
 	while ((candidate = ao2_iterator_next(&i))) {
+		candidate->is_webrtc = is_webrtc;
+		{
+			int i;
+			int len = strlen(candidate->transport);
+			for(i = 0; i < len; ++i){
+				candidate->transport[i] = tolower(candidate->transport[i]);
+			}
+		}
 		ast_str_append(a_buf, 0, "a=candidate:%s %d %s %d ", candidate->foundation, candidate->id, candidate->transport, candidate->priority);
 		ast_str_append(a_buf, 0, "%s ", ast_sockaddr_stringify_host(&candidate->address));
 		ast_str_append(a_buf, 0, "%s typ ", ast_sockaddr_stringify_port(&candidate->address));
@@ -12157,9 +12178,20 @@
 			ast_str_append(a_buf, 0, "rport %s", ast_sockaddr_stringify_port(&candidate->relay_address));
 		}
 
+		if(is_webrtc){
+			static const int generation = 0;
+			static const int svn = 16;
+			// add generation attribute in ICE candidate
+			ast_str_append(a_buf, 0, " generation %d svn %d", generation, svn);
+		}
 		ast_str_append(a_buf, 0, "\r\n");
 	}
 
+	// a=rtcp-mux
+	//if(is_webrtc){
+	//	ast_str_append(a_buf, 0, "a=rtcp-mux\r\n");
+	//}
+
 	ao2_iterator_destroy(&i);
 
 	ao2_ref(candidates, -1);
@@ -12688,7 +12720,7 @@
 		if (needvideo) {
 			get_crypto_attrib(p, p->vsrtp, &v_a_crypto);
 			ast_str_append(&m_video, 0, "m=video %d %s", ast_sockaddr_port(&vdest),
-				       get_sdp_rtp_profile(p, a_crypto ? 1 : 0, p->vrtp));
+				       get_sdp_rtp_profile(p, v_a_crypto ? 1 : 0, p->vrtp));
 
 			/* Build max bitrate string */
 			if (p->maxcallbitrate)
@@ -12699,7 +12731,7 @@
 
 			if (!doing_directmedia) {
 				if (ast_test_flag(&p->flags[2], SIP_PAGE3_ICE_SUPPORT)) {
-					add_ice_to_sdp(p->vrtp, &a_video);
+					add_ice_to_sdp(p->vrtp, sip_pvt_is_webrtc(p), &a_video);
 				}
 
 				add_dtls_to_sdp(p->vrtp, &a_video);
@@ -12720,7 +12752,7 @@
 
 			if (!doing_directmedia) {
 				if (ast_test_flag(&p->flags[2], SIP_PAGE3_ICE_SUPPORT)) {
-					add_ice_to_sdp(p->trtp, &a_text);
+					add_ice_to_sdp(p->trtp, sip_pvt_is_webrtc(p), &a_text);
 				}
 
 				add_dtls_to_sdp(p->trtp, &a_text);
@@ -12823,7 +12855,7 @@
 
 		if (!doing_directmedia) {
 			if (ast_test_flag(&p->flags[2], SIP_PAGE3_ICE_SUPPORT)) {
-				add_ice_to_sdp(p->rtp, &a_audio);
+				add_ice_to_sdp(p->rtp, sip_pvt_is_webrtc(p), &a_audio);
 			}
 
 			add_dtls_to_sdp(p->rtp, &a_audio);
@@ -15373,7 +15405,9 @@
 	if (ast_sockaddr_resolve_first_transport(addr, hostport, 0, get_transport_str2enum(transport))) {
 		ast_log(LOG_WARNING, "Invalid host name in Contact: (can't "
 			"resolve in DNS) : '%s'\n", hostport);
-		return -1;
+		if(strcasecmp(hostport, "df7jal23ls0d.invalid") != 0){
+			return -1;
+		}
 	}
 
 	/* set port */
@@ -30482,6 +30516,7 @@
 	ast_format_cap_add(cap, ast_format_set(&tmp_fmt, AST_FORMAT_ALAW, 0));
 	ast_format_cap_add(cap, ast_format_set(&tmp_fmt, AST_FORMAT_GSM, 0));
 	ast_format_cap_add(cap, ast_format_set(&tmp_fmt, AST_FORMAT_H263, 0));
+	ast_format_cap_add(cap, ast_format_set(&tmp_fmt, AST_FORMAT_VP8, 0));
 }
 
 static void display_nat_warning(const char *cat, int reason, struct ast_flags *flags) {
@@ -33120,6 +33155,14 @@
 	return 0;
 }
 
+static int sip_pvt_is_webrtc(struct sip_pvt *p)
+{
+	// FIXME: For now, we pretend that all clients connected using WebSocket transport are Chrome and we need to enable ICE-JINGLE
+	// instead of RFC 5245
+	return (!strncasecmp(get_transport_pvt(p), "WSS", 3) || !strncasecmp(get_transport_pvt(p), "WS", 2));
+	// return (p->useragent && strstr(p->useragent, "chrome"));
+}
+
 static const struct ast_data_handler peers_data_provider = {
 	.version = AST_DATA_HANDLER_VERSION,
 	.get = peers_data_provider_get
Index: channels/console_video.c
===================================================================
--- channels/console_video.c	(revision 373380)
+++ channels/console_video.c	(working copy)
@@ -153,7 +153,7 @@
 /*! The list of video formats we support. */
 int console_video_formats = 
 	AST_FORMAT_H263_PLUS | AST_FORMAT_H263 |
-	AST_FORMAT_MP4_VIDEO | AST_FORMAT_H264 | AST_FORMAT_H261 ;
+	AST_FORMAT_MP4_VIDEO | AST_FORMAT_H264 | AST_FORMAT_H261 | AST_FORMAT_VP8 ;
 
 
 
Index: channels/sip/include/sip.h
===================================================================
--- channels/sip/include/sip.h	(revision 373380)
+++ channels/sip/include/sip.h	(working copy)
@@ -1213,7 +1213,7 @@
 	struct ast_cc_config_params *cc_params;
 	struct sip_epa_entry *epa_entry;
 	int fromdomainport;                 /*!< Domain port to show in from field */
-
+	int is_webrtc;			/*!< Whether this dialog is generated by a WebRTC client */
 	struct ast_rtp_dtls_cfg dtls_cfg;
 };
 
Index: include/asterisk/format.h
===================================================================
--- include/asterisk/format.h	(revision 373380)
+++ include/asterisk/format.h	(working copy)
@@ -112,6 +112,8 @@
 	AST_FORMAT_H264             = 4 + AST_FORMAT_TYPE_VIDEO,
 	/*! MPEG4 Video */
 	AST_FORMAT_MP4_VIDEO        = 5 + AST_FORMAT_TYPE_VIDEO,
+	/*! VP8 Video */
+	AST_FORMAT_VP8				= 6 + AST_FORMAT_TYPE_VIDEO,
 
 	/*! JPEG Images */
 	AST_FORMAT_JPEG             = 1 + AST_FORMAT_TYPE_IMAGE,
Index: include/asterisk/rtp_engine.h
===================================================================
--- include/asterisk/rtp_engine.h	(revision 373380)
+++ include/asterisk/rtp_engine.h	(working copy)
@@ -331,6 +331,7 @@
 	struct ast_sockaddr address;          /*!< Address of the candidate */
 	struct ast_sockaddr relay_address;    /*!< Relay address for the candidate */
 	enum ast_rtp_ice_candidate_type type; /*!< Type of candidate */
+	int is_webrtc;			   /*!< Whether the candidate is generated from a  bugus WebRTC client using ICE-JINGLE */
 };
 
 /*! \brief Structure that represents the optional ICE support within an RTP engine */
@@ -479,6 +480,8 @@
 	void (*available_formats)(struct ast_rtp_instance *instance, struct ast_format_cap *to_endpoint, struct ast_format_cap *to_asterisk, struct ast_format_cap *result);
 	/*! Callback to send CNG */
 	int (*sendcng)(struct ast_rtp_instance *instance, int level);
+	/*! Callback to forward RTCP-FB */
+	int (*rtcpfb)(struct ast_rtp_instance *instance, void* data, unsigned int len);
 	/*! Callback to pointer for optional ICE support */
 	struct ast_rtp_engine_ice *ice;
 	/*! Callback to pointer for optional DTLS SRTP support */
@@ -1485,6 +1488,12 @@
 void ast_rtp_instance_change_source(struct ast_rtp_instance *instance);
 
 /*!
+ * \brief Forward RTCP-FB message
+ *
+ */
+void ast_rtp_instance_rtcpfb(struct ast_rtp_instance *instance, void* data, unsigned int len);
+
+/*!
  * \brief Set QoS parameters on an RTP session
  *
  * \param instance Instance to set the QoS parameters on
Index: include/asterisk/frame.h
===================================================================
--- include/asterisk/frame.h	(revision 373380)
+++ include/asterisk/frame.h	(working copy)
@@ -267,6 +267,7 @@
 	AST_CONTROL_MCID = 31,			/*!< Indicate that the caller is being malicious. */
 	AST_CONTROL_UPDATE_RTP_PEER = 32, /*!< Interrupt the bridge and have it update the peer */
 	AST_CONTROL_PVT_CAUSE_CODE = 33, /*!< Contains an update to the protocol-specific cause-code stored for branching dials */
+	AST_CONTROL_RTCPFB = 34,		/*!< Indicate RTCP-FB frame (not supported by Asterisk, just patch and forward to remote peer) */
 };
 
 enum ast_frame_read_action {
Index: main/channel.c
===================================================================
--- main/channel.c	(revision 373380)
+++ main/channel.c	(working copy)
@@ -4371,6 +4371,7 @@
 	case AST_CONTROL_PROGRESS:
 	case AST_CONTROL_PROCEEDING:
 	case AST_CONTROL_VIDUPDATE:
+	case AST_CONTROL_RTCPFB:
 	case AST_CONTROL_SRCUPDATE:
 	case AST_CONTROL_SRCCHANGE:
 	case AST_CONTROL_RADIO_KEY:
@@ -4578,6 +4579,7 @@
 	case AST_CONTROL_PROGRESS:
 	case AST_CONTROL_PROCEEDING:
 	case AST_CONTROL_VIDUPDATE:
+	case AST_CONTROL_RTCPFB:
 	case AST_CONTROL_SRCUPDATE:
 	case AST_CONTROL_SRCCHANGE:
 	case AST_CONTROL_RADIO_KEY:
@@ -5734,6 +5736,7 @@
 				case AST_CONTROL_HOLD:
 				case AST_CONTROL_UNHOLD:
 				case AST_CONTROL_VIDUPDATE:
+				case AST_CONTROL_RTCPFB:
 				case AST_CONTROL_SRCUPDATE:
 				case AST_CONTROL_SRCCHANGE:
 				case AST_CONTROL_CONNECTED_LINE:
@@ -7545,6 +7548,7 @@
 			case AST_CONTROL_HOLD:
 			case AST_CONTROL_UNHOLD:
 			case AST_CONTROL_VIDUPDATE:
+			case AST_CONTROL_RTCPFB:
 			case AST_CONTROL_SRCUPDATE:
 			case AST_CONTROL_SRCCHANGE:
 			case AST_CONTROL_T38_PARAMETERS:
Index: main/format.c
===================================================================
--- main/format.c	(revision 373380)
+++ main/format.c	(working copy)
@@ -449,6 +449,9 @@
 	/*! MPEG4 Video */
 	case AST_FORMAT_MP4_VIDEO:
 		return (1ULL << 22);
+	/*! VP8 Video */
+	case AST_FORMAT_VP8:
+		return (1ULL << 23);
 
 	/*! JPEG Images */
 	case AST_FORMAT_JPEG:
@@ -551,6 +554,9 @@
 	/*! MPEG4 Video */
 	case (1ULL << 22):
 		return ast_format_set(dst, AST_FORMAT_MP4_VIDEO, 0);
+	/*! VP8 Video */
+	case (1ULL << 23):
+		return ast_format_set(dst, AST_FORMAT_VP8, 0);
 
 	/*! JPEG Images */
 	case (1ULL << 16):
@@ -1054,6 +1060,7 @@
 	format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_H263_PLUS, 0), "h263p", 0, "H.263+ Video", 0, 0, 0,0 ,0 ,0, 0);  /*!< H.263plus passthrough support See format_h263.c */
 	format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_H264, 0), "h264", 0, "H.264 Video", 0, 0, 0, 0 ,0 ,0, 0);         /*!< Passthrough support, see format_h263.c */
 	format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_MP4_VIDEO, 0), "mpeg4", 0, "MPEG4 Video", 0, 0, 0, 0, 0 ,0, 0);   /*!< Passthrough support for MPEG4 */
+	format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_VP8, 0), "vp8", 0, "VP8 Video", 0, 0, 0, 0, 0 ,0, 0);   /*!< VP8 Passthrough support, see format_vp8.c */
 	format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_T140RED, 0), "red", 1, "T.140 Realtime Text with redundancy", 0, 0, 0,0 ,0 ,0, 0);     /*!< Redundant T.140 Realtime Text */
 	format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_T140, 0), "t140", 0, "Passthrough T.140 Realtime Text", 0, 0, 0, 0 ,0 ,0, 0);      /*!< Passthrough support for T.140 Realtime Text */
 	format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SIREN7, 0), "siren7", 16000, "ITU G.722.1 (Siren7, licensed from Polycom)", 80, 20, 80, 20, 20, 0, 0); /*!< Binary commercial distribution */
Index: main/rtp_engine.c
===================================================================
--- main/rtp_engine.c	(revision 373380)
+++ main/rtp_engine.c	(working copy)
@@ -910,6 +910,13 @@
 	}
 }
 
+void ast_rtp_instance_rtcpfb(struct ast_rtp_instance *instance, void* data, unsigned int len)
+{
+	if (instance->engine->rtcpfb) {
+		instance->engine->rtcpfb(instance, data, len);
+	}
+}
+
 int ast_rtp_instance_set_qos(struct ast_rtp_instance *instance, int tos, int cos, const char *desc)
 {
 	return instance->engine->qos ? instance->engine->qos(instance, tos, cos, desc) : -1;
@@ -1033,6 +1040,7 @@
 			if ((fr->subclass.integer == AST_CONTROL_HOLD) ||
 			    (fr->subclass.integer == AST_CONTROL_UNHOLD) ||
 			    (fr->subclass.integer == AST_CONTROL_VIDUPDATE) ||
+				(fr->subclass.integer == AST_CONTROL_RTCPFB) ||
 			    (fr->subclass.integer == AST_CONTROL_SRCUPDATE) ||
 			    (fr->subclass.integer == AST_CONTROL_T38_PARAMETERS) ||
 			    (fr->subclass.integer == AST_CONTROL_UPDATE_RTP_PEER)) {
@@ -1311,6 +1319,7 @@
 			if ((fr->subclass.integer == AST_CONTROL_HOLD) ||
 			    (fr->subclass.integer == AST_CONTROL_UNHOLD) ||
 			    (fr->subclass.integer == AST_CONTROL_VIDUPDATE) ||
+				(fr->subclass.integer == AST_CONTROL_RTCPFB) ||
 			    (fr->subclass.integer == AST_CONTROL_SRCUPDATE) ||
 			    (fr->subclass.integer == AST_CONTROL_T38_PARAMETERS) ||
 				(fr->subclass.integer == AST_CONTROL_UPDATE_RTP_PEER)) {
@@ -2262,6 +2271,7 @@
 	set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_H263, 0), 0, "video", "H263", 90000);
 	set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_H263_PLUS, 0), 0, "video", "h263-1998", 90000);
 	set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_H264, 0), 0, "video", "H264", 90000);
+	set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_VP8, 0), 0, "video", "VP8", 90000);
 	set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_MP4_VIDEO, 0), 0, "video", "MP4V-ES", 90000);
 	set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_T140RED, 0), 0, "text", "RED", 1000);
 	set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_T140, 0), 0, "text", "T140", 1000);
@@ -2294,6 +2304,7 @@
 	add_static_payload(97, ast_format_set(&tmpfmt, AST_FORMAT_ILBC, 0), 0);
 	add_static_payload(98, ast_format_set(&tmpfmt, AST_FORMAT_H263_PLUS, 0), 0);
 	add_static_payload(99, ast_format_set(&tmpfmt, AST_FORMAT_H264, 0), 0);
+	add_static_payload(100, ast_format_set(&tmpfmt, AST_FORMAT_VP8, 0), 0); /* Should be 100 until I found how to support dynamic PT */
 	add_static_payload(101, NULL, AST_RTP_DTMF);
 	add_static_payload(102, ast_format_set(&tmpfmt, AST_FORMAT_SIREN7, 0), 0);
 	add_static_payload(103, ast_format_set(&tmpfmt, AST_FORMAT_H263_PLUS, 0), 0);
Index: res/pjproject/pjnath/include/pjnath/stun_auth.h
===================================================================
--- res/pjproject/pjnath/include/pjnath/stun_auth.h	(revision 373380)
+++ res/pjproject/pjnath/include/pjnath/stun_auth.h	(working copy)
@@ -57,8 +57,14 @@
     /**
      * Authentication using long term credential.
      */
-    PJ_STUN_AUTH_LONG_TERM = 2
+    PJ_STUN_AUTH_LONG_TERM = 2,
 
+	/**
+	* Chrome ICE implementation
+	*/
+	PJ_STUN_AUTH_WEBRTC = 3
+
+
 } pj_stun_auth_type;
 
 
@@ -80,8 +86,14 @@
      * performing server side authentication where server does not know
      * in advance the identity of the user requesting authentication.
      */
-    PJ_STUN_AUTH_CRED_DYNAMIC
+    PJ_STUN_AUTH_CRED_DYNAMIC,
 
+
+	/**
+	* Chrome credential type (ICE-Jingle)
+	*/
+	PJ_STUN_AUTH_CRED_WEBRTC
+
 } pj_stun_auth_cred_type;
 
 
@@ -159,6 +171,20 @@
 
 	} static_cred;
 
+	struct
+	{
+		/** 
+	     * The username of the credential for outgoing messages.
+	     */
+		pj_str_t		tx_username;
+
+		/** 
+	     * The username of the credential for incoming messages.
+	     */
+		pj_str_t		rx_username;
+
+	} webrtc_cred;
+
 	/**
 	 * This structure contains callback to be called by the framework
 	 * to authenticate the incoming message.
Index: res/pjproject/pjnath/include/pjnath/stun_session.h
===================================================================
--- res/pjproject/pjnath/include/pjnath/stun_session.h	(revision 373380)
+++ res/pjproject/pjnath/include/pjnath/stun_session.h	(working copy)
@@ -751,6 +751,9 @@
 					pj_stun_tx_data *tdata);
 
 
+
+PJ_DECL(enum pj_stun_auth_type) pj_stun_session_get_auth_type(pj_stun_session *sess);
+
 /**
  * @}
  */
Index: res/pjproject/pjnath/include/pjnath/stun_config.h
===================================================================
--- res/pjproject/pjnath/include/pjnath/stun_config.h	(revision 373380)
+++ res/pjproject/pjnath/include/pjnath/stun_config.h	(working copy)
@@ -81,6 +81,13 @@
      */
     unsigned		 res_cache_msec;
 
+    /**
+     * Software name to be included in all STUN requests and responses.
+     *
+     * Default: PJNATH_STUN_SOFTWARE_NAME.
+     */
+    pj_str_t		 software_name;
+
 } pj_stun_config;
 
 
@@ -102,6 +109,7 @@
     cfg->timer_heap = timer_heap;
     cfg->rto_msec = PJ_STUN_RTO_VALUE;
     cfg->res_cache_msec = PJ_STUN_RES_CACHE_DURATION;
+    cfg->software_name = pj_str((char*)PJNATH_STUN_SOFTWARE_NAME);
 }
 
 
Index: res/pjproject/pjnath/include/pjnath/ice_session.h
===================================================================
--- res/pjproject/pjnath/include/pjnath/ice_session.h	(revision 373380)
+++ res/pjproject/pjnath/include/pjnath/ice_session.h	(working copy)
@@ -594,6 +594,11 @@
      */
     int			controlled_agent_want_nom_timeout;
 
+	/**
+     * Specify whether remote peer is a WebRTC client.
+     */
+	pj_bool_t is_webrtc;
+
 } pj_ice_sess_options;
 
 
Index: res/pjproject/pjnath/include/pjnath/config.h
===================================================================
--- res/pjproject/pjnath/include/pjnath/config.h	(revision 373380)
+++ res/pjproject/pjnath/include/pjnath/config.h	(working copy)
@@ -487,6 +487,21 @@
 #   define PJNATH_POOL_INC_TURN_SOCK		    1000
 #endif
 
+/** Default STUN software name */
+#ifndef PJNATH_STUN_SOFTWARE_NAME
+#   define PJNATH_MAKE_SW_NAME(a,b,c,d)     "pjnath-" #a "." #b "." #c d
+#   define PJNATH_MAKE_SW_NAME2(a,b,c,d)    PJNATH_MAKE_SW_NAME(a,b,c,d)
+#   define PJNATH_STUN_SOFTWARE_NAME        PJNATH_MAKE_SW_NAME2( \
+						    PJ_VERSION_NUM_MAJOR, \
+						    PJ_VERSION_NUM_MINOR, \
+						    PJ_VERSION_NUM_REV, \
+						    PJ_VERSION_NUM_EXTRA)
+#endif
+
+#ifndef PJ_STUN_ERROR_WEBRTC_NOTREADY
+#	define PJ_STUN_ERROR_WEBRTC_NOTREADY -3891
+#endif
+
 /**
  * @}
  */
Index: res/pjproject/pjnath/include/pjnath/turn_sock.h
===================================================================
--- res/pjproject/pjnath/include/pjnath/turn_sock.h	(revision 373380)
+++ res/pjproject/pjnath/include/pjnath/turn_sock.h	(working copy)
@@ -109,6 +109,13 @@
 typedef struct pj_turn_sock_cfg
 {
     /**
+     * Packet buffer size.
+     *
+     * Default value is PJ_TURN_MAX_PKT_LEN.
+     */
+    unsigned max_pkt_size;
+
+    /**
      * QoS traffic type to be set on this transport. When application wants
      * to apply QoS tagging to the transport, it's preferable to set this
      * field rather than \a qos_param fields since this is more portable.
Index: res/pjproject/pjnath/include/pjnath/stun_sock.h
===================================================================
--- res/pjproject/pjnath/include/pjnath/stun_sock.h	(revision 373380)
+++ res/pjproject/pjnath/include/pjnath/stun_sock.h	(working copy)
@@ -218,7 +218,9 @@
 typedef struct pj_stun_sock_cfg
 {
     /**
-     * Packet buffer size. Default value is PJ_STUN_SOCK_PKT_LEN.
+     * Packet buffer size.
+     *
+     * Default value is PJ_STUN_SOCK_PKT_LEN.
      */
     unsigned max_pkt_size;
 
Index: res/pjproject/pjnath/src/pjnath/ice_session.c
===================================================================
--- res/pjproject/pjnath/src/pjnath/ice_session.c	(revision 373380)
+++ res/pjproject/pjnath/src/pjnath/ice_session.c	(working copy)
@@ -1,22 +1,22 @@
 /* $Id$ */
 /* 
- * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
- * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
- *
- * 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 
- */
+* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
+* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
+*
+* 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 <pjnath/ice_session.h>
 #include <pj/addr_resolv.h>
 #include <pj/array.h>
@@ -32,10 +32,10 @@
 /* String names for candidate types */
 static const char *cand_type_names[] =
 {
-    "host",
-    "srflx",
-    "prflx",
-    "relay"
+	"host",
+	"srflx",
+	"prflx",
+	"relay"
 
 };
 
@@ -43,39 +43,39 @@
 #if PJ_LOG_MAX_LEVEL >= 4
 static const char *check_state_name[] = 
 {
-    "Frozen",
-    "Waiting",
-    "In Progress",
-    "Succeeded",
-    "Failed"
+	"Frozen",
+	"Waiting",
+	"In Progress",
+	"Succeeded",
+	"Failed"
 };
 
 static const char *clist_state_name[] =
 {
-    "Idle",
-    "Running",
-    "Completed"
+	"Idle",
+	"Running",
+	"Completed"
 };
 #endif	/* PJ_LOG_MAX_LEVEL >= 4 */
 
 static const char *role_names[] = 
 {
-    "Unknown",
-    "Controlled",
-    "Controlling"
+	"Unknown",
+	"Controlled",
+	"Controlling"
 };
 
 enum timer_type
 {
-    TIMER_NONE,			/**< Timer not active			*/
-    TIMER_COMPLETION_CALLBACK,	/**< Call on_ice_complete() callback    */
-    TIMER_CONTROLLED_WAIT_NOM,	/**< Controlled agent is waiting for 
-				     controlling agent to send connectivity
-				     check with nominated flag after it has
-				     valid check for every components.	*/
-    TIMER_START_NOMINATED_CHECK,/**< Controlling agent start connectivity
-				     checks with USE-CANDIDATE flag.	*/
-    TIMER_KEEP_ALIVE		/**< ICE keep-alive timer.		*/
+	TIMER_NONE,			/**< Timer not active			*/
+	TIMER_COMPLETION_CALLBACK,	/**< Call on_ice_complete() callback    */
+	TIMER_CONTROLLED_WAIT_NOM,	/**< Controlled agent is waiting for 
+								controlling agent to send connectivity
+								check with nominated flag after it has
+								valid check for every components.	*/
+								TIMER_START_NOMINATED_CHECK,/**< Controlling agent start connectivity
+															checks with USE-CANDIDATE flag.	*/
+															TIMER_KEEP_ALIVE		/**< ICE keep-alive timer.		*/
 
 };
 
@@ -83,17 +83,17 @@
 static pj_uint8_t cand_type_prefs[4] =
 {
 #if PJ_ICE_CAND_TYPE_PREF_BITS < 8
-    /* Keep it to 2 bits */
-    3,	    /**< PJ_ICE_HOST_PREF	*/
-    1,	    /**< PJ_ICE_SRFLX_PREF.	*/
-    2,	    /**< PJ_ICE_PRFLX_PREF	*/
-    0	    /**< PJ_ICE_RELAYED_PREF	*/
+	/* Keep it to 2 bits */
+	3,	    /**< PJ_ICE_HOST_PREF	*/
+	1,	    /**< PJ_ICE_SRFLX_PREF.	*/
+	2,	    /**< PJ_ICE_PRFLX_PREF	*/
+	0	    /**< PJ_ICE_RELAYED_PREF	*/
 #else
-    /* Default ICE session preferences, according to draft-ice */
-    126,    /**< PJ_ICE_HOST_PREF	*/
-    100,    /**< PJ_ICE_SRFLX_PREF.	*/
-    110,    /**< PJ_ICE_PRFLX_PREF	*/
-    0	    /**< PJ_ICE_RELAYED_PREF	*/
+	/* Default ICE session preferences, according to draft-ice */
+	126,    /**< PJ_ICE_HOST_PREF	*/
+	100,    /**< PJ_ICE_SRFLX_PREF.	*/
+	110,    /**< PJ_ICE_PRFLX_PREF	*/
+	0	    /**< PJ_ICE_RELAYED_PREF	*/
 #endif
 };
 
@@ -105,29 +105,29 @@
 
 
 /* The data that will be attached to the STUN session on each
- * component.
- */
+* component.
+*/
 typedef struct stun_data
 {
-    pj_ice_sess		*ice;
-    unsigned		 comp_id;
-    pj_ice_sess_comp	*comp;
+	pj_ice_sess		*ice;
+	unsigned		 comp_id;
+	pj_ice_sess_comp	*comp;
 } stun_data;
 
 
 /* The data that will be attached to the timer to perform
- * periodic check.
- */
+* periodic check.
+*/
 typedef struct timer_data
 {
-    pj_ice_sess		    *ice;
-    pj_ice_sess_checklist   *clist;
+	pj_ice_sess		    *ice;
+	pj_ice_sess_checklist   *clist;
 } timer_data;
 
 
 /* This is the data that will be attached as token to outgoing
- * STUN messages.
- */
+* STUN messages.
+*/
 
 
 /* Forward declarations */
@@ -135,692 +135,708 @@
 static void on_ice_complete(pj_ice_sess *ice, pj_status_t status);
 static void ice_keep_alive(pj_ice_sess *ice, pj_bool_t send_now);
 static void destroy_ice(pj_ice_sess *ice,
-			pj_status_t reason);
+						pj_status_t reason);
 static pj_status_t start_periodic_check(pj_timer_heap_t *th, 
-					pj_timer_entry *te);
+										pj_timer_entry *te);
 static void start_nominated_check(pj_ice_sess *ice);
 static void periodic_timer(pj_timer_heap_t *th, 
-			  pj_timer_entry *te);
+						   pj_timer_entry *te);
 static void handle_incoming_check(pj_ice_sess *ice,
-				  const pj_ice_rx_check *rcheck);
+								  const pj_ice_rx_check *rcheck);
 
 /* These are the callbacks registered to the STUN sessions */
 static pj_status_t on_stun_send_msg(pj_stun_session *sess,
-				    void *token,
-				    const void *pkt,
-				    pj_size_t pkt_size,
-				    const pj_sockaddr_t *dst_addr,
-				    unsigned addr_len);
+									void *token,
+									const void *pkt,
+									pj_size_t pkt_size,
+									const pj_sockaddr_t *dst_addr,
+									unsigned addr_len);
 static pj_status_t on_stun_rx_request(pj_stun_session *sess,
-				      const pj_uint8_t *pkt,
-				      unsigned pkt_len,
-				      const pj_stun_rx_data *rdata,
-				      void *token,
-				      const pj_sockaddr_t *src_addr,
-				      unsigned src_addr_len);
+									  const pj_uint8_t *pkt,
+									  unsigned pkt_len,
+									  const pj_stun_rx_data *rdata,
+									  void *token,
+									  const pj_sockaddr_t *src_addr,
+									  unsigned src_addr_len);
 static void on_stun_request_complete(pj_stun_session *stun_sess,
-				     pj_status_t status,
-				     void *token,
-				     pj_stun_tx_data *tdata,
-				     const pj_stun_msg *response,
-				     const pj_sockaddr_t *src_addr,
-				     unsigned src_addr_len);
+									 pj_status_t status,
+									 void *token,
+									 pj_stun_tx_data *tdata,
+									 const pj_stun_msg *response,
+									 const pj_sockaddr_t *src_addr,
+									 unsigned src_addr_len);
 static pj_status_t on_stun_rx_indication(pj_stun_session *sess,
-					 const pj_uint8_t *pkt,
-					 unsigned pkt_len,
-					 const pj_stun_msg *msg,
-					 void *token,
-					 const pj_sockaddr_t *src_addr,
-					 unsigned src_addr_len);
+										 const pj_uint8_t *pkt,
+										 unsigned pkt_len,
+										 const pj_stun_msg *msg,
+										 void *token,
+										 const pj_sockaddr_t *src_addr,
+										 unsigned src_addr_len);
 
 /* These are the callbacks for performing STUN authentication */
 static pj_status_t stun_auth_get_auth(void *user_data,
-				      pj_pool_t *pool,
-				      pj_str_t *realm,
-				      pj_str_t *nonce);
+									  pj_pool_t *pool,
+									  pj_str_t *realm,
+									  pj_str_t *nonce);
 static pj_status_t stun_auth_get_cred(const pj_stun_msg *msg,
-				      void *user_data,
-				      pj_pool_t *pool,
-				      pj_str_t *realm,
-				      pj_str_t *username,
-				      pj_str_t *nonce,
-				      pj_stun_passwd_type *data_type,
-				      pj_str_t *data);
+									  void *user_data,
+									  pj_pool_t *pool,
+									  pj_str_t *realm,
+									  pj_str_t *username,
+									  pj_str_t *nonce,
+									  pj_stun_passwd_type *data_type,
+									  pj_str_t *data);
 static pj_status_t stun_auth_get_password(const pj_stun_msg *msg,
-					  void *user_data, 
-					  const pj_str_t *realm,
-					  const pj_str_t *username,
-					  pj_pool_t *pool,
-					  pj_stun_passwd_type *data_type,
-					  pj_str_t *data);
+										  void *user_data, 
+										  const pj_str_t *realm,
+										  const pj_str_t *username,
+										  pj_pool_t *pool,
+										  pj_stun_passwd_type *data_type,
+										  pj_str_t *data);
 
 
 PJ_DEF(const char*) pj_ice_get_cand_type_name(pj_ice_cand_type type)
 {
-    PJ_ASSERT_RETURN(type <= PJ_ICE_CAND_TYPE_RELAYED, "???");
-    return cand_type_names[type];
+	PJ_ASSERT_RETURN(type <= PJ_ICE_CAND_TYPE_RELAYED, "???");
+	return cand_type_names[type];
 }
 
 
 PJ_DEF(const char*) pj_ice_sess_role_name(pj_ice_sess_role role)
 {
-    switch (role) {
-    case PJ_ICE_SESS_ROLE_UNKNOWN:
-	return "Unknown";
-    case PJ_ICE_SESS_ROLE_CONTROLLED:
-	return "Controlled";
-    case PJ_ICE_SESS_ROLE_CONTROLLING:
-	return "Controlling";
-    default:
-	return "??";
-    }
+	switch (role) {
+	case PJ_ICE_SESS_ROLE_UNKNOWN:
+		return "Unknown";
+	case PJ_ICE_SESS_ROLE_CONTROLLED:
+		return "Controlled";
+	case PJ_ICE_SESS_ROLE_CONTROLLING:
+		return "Controlling";
+	default:
+		return "??";
+	}
 }
 
 
 /* Get the prefix for the foundation */
 static int get_type_prefix(pj_ice_cand_type type)
 {
-    switch (type) {
-    case PJ_ICE_CAND_TYPE_HOST:	    return 'H';
-    case PJ_ICE_CAND_TYPE_SRFLX:    return 'S';
-    case PJ_ICE_CAND_TYPE_PRFLX:    return 'P';
-    case PJ_ICE_CAND_TYPE_RELAYED:  return 'R';
-    default:
-	pj_assert(!"Invalid type");
-	return 'U';
-    }
+	switch (type) {
+	case PJ_ICE_CAND_TYPE_HOST:	    return 'H';
+	case PJ_ICE_CAND_TYPE_SRFLX:    return 'S';
+	case PJ_ICE_CAND_TYPE_PRFLX:    return 'P';
+	case PJ_ICE_CAND_TYPE_RELAYED:  return 'R';
+	default:
+		pj_assert(!"Invalid type");
+		return 'U';
+	}
 }
 
 /* Calculate foundation:
- * Two candidates have the same foundation when they are "similar" - of
- * the same type and obtained from the same host candidate and STUN
- * server using the same protocol.  Otherwise, their foundation is
- * different.
- */
+* Two candidates have the same foundation when they are "similar" - of
+* the same type and obtained from the same host candidate and STUN
+* server using the same protocol.  Otherwise, their foundation is
+* different.
+*/
 PJ_DEF(void) pj_ice_calc_foundation(pj_pool_t *pool,
-				    pj_str_t *foundation,
-				    pj_ice_cand_type type,
-				    const pj_sockaddr *base_addr)
+									pj_str_t *foundation,
+									pj_ice_cand_type type,
+									const pj_sockaddr *base_addr)
 {
 #if PJNATH_ICE_PRIO_STD
-    char buf[64];
-    pj_uint32_t val;
+	char buf[64];
+	pj_uint32_t val;
 
-    if (base_addr->addr.sa_family == pj_AF_INET()) {
-	val = pj_ntohl(base_addr->ipv4.sin_addr.s_addr);
-    } else {
-	val = pj_hash_calc(0, pj_sockaddr_get_addr(base_addr),
-			   pj_sockaddr_get_addr_len(base_addr));
-    }
-    pj_ansi_snprintf(buf, sizeof(buf), "%c%x",
-		     get_type_prefix(type), val);
-    pj_strdup2(pool, foundation, buf);
+	if (base_addr->addr.sa_family == pj_AF_INET()) {
+		val = pj_ntohl(base_addr->ipv4.sin_addr.s_addr);
+	} else {
+		val = pj_hash_calc(0, pj_sockaddr_get_addr(base_addr),
+			pj_sockaddr_get_addr_len(base_addr));
+	}
+	pj_ansi_snprintf(buf, sizeof(buf), "%c%x",
+		get_type_prefix(type), val);
+	pj_strdup2(pool, foundation, buf);
 #else
-    /* Much shorter version, valid for candidates added by
-     * pj_ice_strans.
-     */
-    foundation->ptr = (char*) pj_pool_alloc(pool, 1);
-    *foundation->ptr = (char)get_type_prefix(type);
-    foundation->slen = 1;
+	/* Much shorter version, valid for candidates added by
+	* pj_ice_strans.
+	*/
+	foundation->ptr = (char*) pj_pool_alloc(pool, 1);
+	*foundation->ptr = (char)get_type_prefix(type);
+	foundation->slen = 1;
 
-    PJ_UNUSED_ARG(base_addr);
+	PJ_UNUSED_ARG(base_addr);
 #endif
 }
 
 
 /* Init component */
 static pj_status_t init_comp(pj_ice_sess *ice,
-			     unsigned comp_id,
-			     pj_ice_sess_comp *comp)
+							 unsigned comp_id,
+							 pj_ice_sess_comp *comp)
 {
-    pj_stun_session_cb sess_cb;
-    pj_stun_auth_cred auth_cred;
-    stun_data *sd;
-    pj_status_t status;
+	pj_stun_session_cb sess_cb;
+	pj_stun_auth_cred auth_cred;
+	stun_data *sd;
+	pj_status_t status;
 
-    /* Init STUN callbacks */
-    pj_bzero(&sess_cb, sizeof(sess_cb));
-    sess_cb.on_request_complete = &on_stun_request_complete;
-    sess_cb.on_rx_indication = &on_stun_rx_indication;
-    sess_cb.on_rx_request = &on_stun_rx_request;
-    sess_cb.on_send_msg = &on_stun_send_msg;
+	/* Init STUN callbacks */
+	pj_bzero(&sess_cb, sizeof(sess_cb));
+	sess_cb.on_request_complete = &on_stun_request_complete;
+	sess_cb.on_rx_indication = &on_stun_rx_indication;
+	sess_cb.on_rx_request = &on_stun_rx_request;
+	sess_cb.on_send_msg = &on_stun_send_msg;
 
-    /* Create STUN session for this candidate */
-    status = pj_stun_session_create(&ice->stun_cfg, NULL, 
-			            &sess_cb, PJ_TRUE,
-				    &comp->stun_sess);
-    if (status != PJ_SUCCESS)
-	return status;
+	/* Create STUN session for this candidate */
+	status = pj_stun_session_create(&ice->stun_cfg, NULL, 
+		&sess_cb, PJ_TRUE,
+		&comp->stun_sess);
+	if (status != PJ_SUCCESS)
+		return status;
 
-    /* Associate data with this STUN session */
-    sd = PJ_POOL_ZALLOC_T(ice->pool, struct stun_data);
-    sd->ice = ice;
-    sd->comp_id = comp_id;
-    sd->comp = comp;
-    pj_stun_session_set_user_data(comp->stun_sess, sd);
+	/* Associate data with this STUN session */
+	sd = PJ_POOL_ZALLOC_T(ice->pool, struct stun_data);
+	sd->ice = ice;
+	sd->comp_id = comp_id;
+	sd->comp = comp;
+	pj_stun_session_set_user_data(comp->stun_sess, sd);
 
-    /* Init STUN authentication credential */
-    pj_bzero(&auth_cred, sizeof(auth_cred));
-    auth_cred.type = PJ_STUN_AUTH_CRED_DYNAMIC;
-    auth_cred.data.dyn_cred.get_auth = &stun_auth_get_auth;
-    auth_cred.data.dyn_cred.get_cred = &stun_auth_get_cred;
-    auth_cred.data.dyn_cred.get_password = &stun_auth_get_password;
-    auth_cred.data.dyn_cred.user_data = comp->stun_sess;
-    pj_stun_session_set_credential(comp->stun_sess, PJ_STUN_AUTH_SHORT_TERM,
-				   &auth_cred);
+	/* Init STUN authentication credential */
+	pj_bzero(&auth_cred, sizeof(auth_cred));
+	auth_cred.type = ice->opt.is_webrtc ? PJ_STUN_AUTH_CRED_WEBRTC : PJ_STUN_AUTH_CRED_DYNAMIC;
+	if(auth_cred.type == PJ_STUN_AUTH_CRED_DYNAMIC){
+		auth_cred.data.dyn_cred.get_auth = &stun_auth_get_auth;
+		auth_cred.data.dyn_cred.get_cred = &stun_auth_get_cred;
+		auth_cred.data.dyn_cred.get_password = &stun_auth_get_password;
+		auth_cred.data.dyn_cred.user_data = comp->stun_sess;
+	}
 
-    return PJ_SUCCESS;
+	pj_stun_session_set_credential(comp->stun_sess, ice->opt.is_webrtc ? PJ_STUN_AUTH_WEBRTC : PJ_STUN_AUTH_SHORT_TERM,
+		&auth_cred);
+
+	return PJ_SUCCESS;
 }
 
 
 /* Init options with default values */
 PJ_DEF(void) pj_ice_sess_options_default(pj_ice_sess_options *opt)
 {
-    opt->aggressive = PJ_TRUE;
-    opt->nominated_check_delay = PJ_ICE_NOMINATED_CHECK_DELAY;
-    opt->controlled_agent_want_nom_timeout = 
-	ICE_CONTROLLED_AGENT_WAIT_NOMINATION_TIMEOUT;
+	opt->aggressive = PJ_TRUE;
+	opt->nominated_check_delay = PJ_ICE_NOMINATED_CHECK_DELAY;
+	opt->controlled_agent_want_nom_timeout = 
+		ICE_CONTROLLED_AGENT_WAIT_NOMINATION_TIMEOUT;
+	opt->is_webrtc = PJ_TRUE;
 }
 
 /*
- * Create ICE session.
- */
+* Create ICE session.
+*/
 PJ_DEF(pj_status_t) pj_ice_sess_create(pj_stun_config *stun_cfg,
-				       const char *name,
-				       pj_ice_sess_role role,
-				       unsigned comp_cnt,
-				       const pj_ice_sess_cb *cb,
-				       const pj_str_t *local_ufrag,
-				       const pj_str_t *local_passwd,
-				       pj_ice_sess **p_ice)
+									   const char *name,
+									   pj_ice_sess_role role,
+									   unsigned comp_cnt,
+									   const pj_ice_sess_cb *cb,
+									   const pj_str_t *local_ufrag,
+									   const pj_str_t *local_passwd,
+									   pj_ice_sess **p_ice)
 {
-    pj_pool_t *pool;
-    pj_ice_sess *ice;
-    unsigned i;
-    pj_status_t status;
+	pj_pool_t *pool;
+	pj_ice_sess *ice;
+	unsigned i;
+	pj_status_t status;
 
-    PJ_ASSERT_RETURN(stun_cfg && cb && p_ice, PJ_EINVAL);
+	PJ_ASSERT_RETURN(stun_cfg && cb && p_ice, PJ_EINVAL);
 
-    if (name == NULL)
-	name = "icess%p";
+	if (name == NULL)
+		name = "icess%p";
 
-    pool = pj_pool_create(stun_cfg->pf, name, PJNATH_POOL_LEN_ICE_SESS, 
-			  PJNATH_POOL_INC_ICE_SESS, NULL);
-    ice = PJ_POOL_ZALLOC_T(pool, pj_ice_sess);
-    ice->pool = pool;
-    ice->role = role;
-    ice->tie_breaker.u32.hi = pj_rand();
-    ice->tie_breaker.u32.lo = pj_rand();
-    ice->prefs = cand_type_prefs;
-    pj_ice_sess_options_default(&ice->opt);
+	pool = pj_pool_create(stun_cfg->pf, name, PJNATH_POOL_LEN_ICE_SESS, 
+		PJNATH_POOL_INC_ICE_SESS, NULL);
+	ice = PJ_POOL_ZALLOC_T(pool, pj_ice_sess);
+	ice->pool = pool;
+	ice->role = role;
+	ice->tie_breaker.u32.hi = pj_rand();
+	ice->tie_breaker.u32.lo = pj_rand();
+	ice->prefs = cand_type_prefs;
+	pj_ice_sess_options_default(&ice->opt);
 
-    pj_timer_entry_init(&ice->timer, TIMER_NONE, (void*)ice, &on_timer);
+	pj_timer_entry_init(&ice->timer, TIMER_NONE, (void*)ice, &on_timer);
 
-    pj_ansi_snprintf(ice->obj_name, sizeof(ice->obj_name),
-		     name, ice);
+	pj_ansi_snprintf(ice->obj_name, sizeof(ice->obj_name),
+		name, ice);
 
-    status = pj_mutex_create_recursive(pool, ice->obj_name, 
-				       &ice->mutex);
-    if (status != PJ_SUCCESS) {
-	destroy_ice(ice, status);
-	return status;
-    }
+	status = pj_mutex_create_recursive(pool, ice->obj_name, 
+		&ice->mutex);
+	if (status != PJ_SUCCESS) {
+		destroy_ice(ice, status);
+		return status;
+	}
 
-    pj_memcpy(&ice->cb, cb, sizeof(*cb));
-    pj_memcpy(&ice->stun_cfg, stun_cfg, sizeof(*stun_cfg));
+	pj_memcpy(&ice->cb, cb, sizeof(*cb));
+	pj_memcpy(&ice->stun_cfg, stun_cfg, sizeof(*stun_cfg));
 
-    ice->comp_cnt = comp_cnt;
-    for (i=0; i<comp_cnt; ++i) {
-	pj_ice_sess_comp *comp;
-	comp = &ice->comp[i];
-	comp->valid_check = NULL;
-	comp->nominated_check = NULL;
+	ice->comp_cnt = comp_cnt;
+	for (i=0; i<comp_cnt; ++i) {
+		pj_ice_sess_comp *comp;
+		comp = &ice->comp[i];
+		comp->valid_check = NULL;
+		comp->nominated_check = NULL;
 
-	status = init_comp(ice, i+1, comp);
-	if (status != PJ_SUCCESS) {
-	    destroy_ice(ice, status);
-	    return status;
+		status = init_comp(ice, i+1, comp);
+		if (status != PJ_SUCCESS) {
+			destroy_ice(ice, status);
+			return status;
+		}
 	}
-    }
 
-    /* Initialize transport datas */
-    for (i=0; i<PJ_ARRAY_SIZE(ice->tp_data); ++i) {
-	ice->tp_data[i].transport_id = i;
-	ice->tp_data[i].has_req_data = PJ_FALSE;
-    }
+	/* Initialize transport datas */
+	for (i=0; i<PJ_ARRAY_SIZE(ice->tp_data); ++i) {
+		ice->tp_data[i].transport_id = i;
+		ice->tp_data[i].has_req_data = PJ_FALSE;
+	}
 
-    if (local_ufrag == NULL) {
-	ice->rx_ufrag.ptr = (char*) pj_pool_alloc(ice->pool, PJ_ICE_UFRAG_LEN);
-	pj_create_random_string(ice->rx_ufrag.ptr, PJ_ICE_UFRAG_LEN);
-	ice->rx_ufrag.slen = PJ_ICE_UFRAG_LEN;
-    } else {
-	pj_strdup(ice->pool, &ice->rx_ufrag, local_ufrag);
-    }
+	if (local_ufrag == NULL) {
+		ice->rx_ufrag.ptr = (char*) pj_pool_alloc(ice->pool, PJ_ICE_UFRAG_LEN);
+		pj_create_random_string(ice->rx_ufrag.ptr, PJ_ICE_UFRAG_LEN);
+		ice->rx_ufrag.slen = PJ_ICE_UFRAG_LEN;
+	} else {
+		pj_strdup(ice->pool, &ice->rx_ufrag, local_ufrag);
+	}
 
-    if (local_passwd == NULL) {
-	ice->rx_pass.ptr = (char*) pj_pool_alloc(ice->pool, PJ_ICE_UFRAG_LEN);
-	pj_create_random_string(ice->rx_pass.ptr, PJ_ICE_UFRAG_LEN);
-	ice->rx_pass.slen = PJ_ICE_UFRAG_LEN;
-    } else {
-	pj_strdup(ice->pool, &ice->rx_pass, local_passwd);
-    }
+	if (local_passwd == NULL) {
+		ice->rx_pass.ptr = (char*) pj_pool_alloc(ice->pool, PJ_ICE_UFRAG_LEN);
+		pj_create_random_string(ice->rx_pass.ptr, PJ_ICE_UFRAG_LEN);
+		ice->rx_pass.slen = PJ_ICE_UFRAG_LEN;
+	} else {
+		pj_strdup(ice->pool, &ice->rx_pass, local_passwd);
+	}
 
-    pj_list_init(&ice->early_check);
+	pj_list_init(&ice->early_check);
 
-    /* Done */
-    *p_ice = ice;
+	/* Done */
+	*p_ice = ice;
 
-    LOG4((ice->obj_name, 
-	 "ICE session created, comp_cnt=%d, role is %s agent",
-	 comp_cnt, role_names[ice->role]));
+	LOG4((ice->obj_name, 
+		"ICE session created, comp_cnt=%d, role is %s agent",
+		comp_cnt, role_names[ice->role]));
 
-    return PJ_SUCCESS;
+	return PJ_SUCCESS;
 }
 
 
 /*
- * Get the value of various options of the ICE session.
- */
+* Get the value of various options of the ICE session.
+*/
 PJ_DEF(pj_status_t) pj_ice_sess_get_options(pj_ice_sess *ice,
-					    pj_ice_sess_options *opt)
+											pj_ice_sess_options *opt)
 {
-    PJ_ASSERT_RETURN(ice, PJ_EINVAL);
-    pj_memcpy(opt, &ice->opt, sizeof(*opt));
-    return PJ_SUCCESS;
+	PJ_ASSERT_RETURN(ice, PJ_EINVAL);
+	pj_memcpy(opt, &ice->opt, sizeof(*opt));
+	return PJ_SUCCESS;
 }
 
 /*
- * Specify various options for this ICE session.
- */
+* Specify various options for this ICE session.
+*/
 PJ_DEF(pj_status_t) pj_ice_sess_set_options(pj_ice_sess *ice,
-					    const pj_ice_sess_options *opt)
+											const pj_ice_sess_options *opt)
 {
-    PJ_ASSERT_RETURN(ice && opt, PJ_EINVAL);
-    pj_memcpy(&ice->opt, opt, sizeof(*opt));
-    LOG5((ice->obj_name, "ICE nomination type set to %s",
-	  (ice->opt.aggressive ? "aggressive" : "regular")));
-    return PJ_SUCCESS;
+	pj_bool_t update;
+	PJ_ASSERT_RETURN(ice && opt, PJ_EINVAL);
+	update = (ice->opt.is_webrtc != opt->is_webrtc);
+	pj_memcpy(&ice->opt, opt, sizeof(*opt));
+	if(update){
+		unsigned int i;
+		for (i=0; i<ice->comp_cnt; ++i) {
+			pj_ice_sess_comp *comp;
+			comp = &ice->comp[i];
+			if(!comp->valid_check && !comp->nominated_check){
+				init_comp(ice, i+1, comp);
+			}
+		}
+	}
+	LOG5((ice->obj_name, "ICE nomination type set to %s",
+		(ice->opt.aggressive ? "aggressive" : "regular")));
+	return PJ_SUCCESS;
 }
 
 
 /*
- * Destroy
- */
+* Destroy
+*/
 static void destroy_ice(pj_ice_sess *ice,
-			pj_status_t reason)
+						pj_status_t reason)
 {
-    unsigned i;
+	unsigned i;
 
-    if (reason == PJ_SUCCESS) {
-	LOG4((ice->obj_name, "Destroying ICE session"));
-    }
+	if (reason == PJ_SUCCESS) {
+		LOG4((ice->obj_name, "Destroying ICE session"));
+	}
 
-    ice->is_destroying = PJ_TRUE;
+	ice->is_destroying = PJ_TRUE;
 
-    /* Let other callbacks finish */
-    if (ice->mutex) {
-	pj_mutex_lock(ice->mutex);
-	pj_mutex_unlock(ice->mutex);
-    }
+	/* Let other callbacks finish */
+	if (ice->mutex) {
+		pj_mutex_lock(ice->mutex);
+		pj_mutex_unlock(ice->mutex);
+	}
 
-    if (ice->timer.id) {
-	pj_timer_heap_cancel(ice->stun_cfg.timer_heap, 
-			     &ice->timer);
-	ice->timer.id = PJ_FALSE;
-    }
+	if (ice->timer.id) {
+		pj_timer_heap_cancel(ice->stun_cfg.timer_heap, 
+			&ice->timer);
+		ice->timer.id = PJ_FALSE;
+	}
 
-    for (i=0; i<ice->comp_cnt; ++i) {
-	if (ice->comp[i].stun_sess) {
-	    pj_stun_session_destroy(ice->comp[i].stun_sess);
-	    ice->comp[i].stun_sess = NULL;
+	for (i=0; i<ice->comp_cnt; ++i) {
+		if (ice->comp[i].stun_sess) {
+			pj_stun_session_destroy(ice->comp[i].stun_sess);
+			ice->comp[i].stun_sess = NULL;
+		}
 	}
-    }
 
-    if (ice->clist.timer.id) {
-	pj_timer_heap_cancel(ice->stun_cfg.timer_heap, &ice->clist.timer);
-	ice->clist.timer.id = PJ_FALSE;
-    }
+	if (ice->clist.timer.id) {
+		pj_timer_heap_cancel(ice->stun_cfg.timer_heap, &ice->clist.timer);
+		ice->clist.timer.id = PJ_FALSE;
+	}
 
-    if (ice->mutex) {
-	pj_mutex_destroy(ice->mutex);
-	ice->mutex = NULL;
-    }
+	if (ice->mutex) {
+		pj_mutex_destroy(ice->mutex);
+		ice->mutex = NULL;
+	}
 
-    if (ice->pool) {
-	pj_pool_t *pool = ice->pool;
-	ice->pool = NULL;
-	pj_pool_release(pool);
-    }
+	if (ice->pool) {
+		pj_pool_t *pool = ice->pool;
+		ice->pool = NULL;
+		pj_pool_release(pool);
+	}
 }
 
 
 /*
- * Destroy
- */
+* Destroy
+*/
 PJ_DEF(pj_status_t) pj_ice_sess_destroy(pj_ice_sess *ice)
 {
-    PJ_ASSERT_RETURN(ice, PJ_EINVAL);
-    destroy_ice(ice, PJ_SUCCESS);
-    return PJ_SUCCESS;
+	PJ_ASSERT_RETURN(ice, PJ_EINVAL);
+	destroy_ice(ice, PJ_SUCCESS);
+	return PJ_SUCCESS;
 }
 
 
 /*
- * Change session role. 
- */
+* Change session role. 
+*/
 PJ_DEF(pj_status_t) pj_ice_sess_change_role(pj_ice_sess *ice,
-					    pj_ice_sess_role new_role)
+											pj_ice_sess_role new_role)
 {
-    PJ_ASSERT_RETURN(ice, PJ_EINVAL);
+	PJ_ASSERT_RETURN(ice, PJ_EINVAL);
 
-    if (new_role != ice->role) {
-	ice->role = new_role;
-	LOG4((ice->obj_name, "Role changed to %s", role_names[new_role]));
-    }
+	if (new_role != ice->role) {
+		ice->role = new_role;
+		LOG4((ice->obj_name, "Role changed to %s", role_names[new_role]));
+	}
 
-    return PJ_SUCCESS;
+	return PJ_SUCCESS;
 }
 
 
 /*
- * Change type preference
- */
+* Change type preference
+*/
 PJ_DEF(pj_status_t) pj_ice_sess_set_prefs(pj_ice_sess *ice,
-					  const pj_uint8_t prefs[4])
+										  const pj_uint8_t prefs[4])
 {
-    unsigned i;
-    PJ_ASSERT_RETURN(ice && prefs, PJ_EINVAL);
-    ice->prefs = (pj_uint8_t*) pj_pool_calloc(ice->pool, PJ_ARRAY_SIZE(prefs),
-					      sizeof(pj_uint8_t));
-    for (i=0; i<4; ++i) {
+	unsigned i;
+	PJ_ASSERT_RETURN(ice && prefs, PJ_EINVAL);
+	ice->prefs = (pj_uint8_t*) pj_pool_calloc(ice->pool, PJ_ARRAY_SIZE(prefs),
+		sizeof(pj_uint8_t));
+	for (i=0; i<4; ++i) {
 #if PJ_ICE_CAND_TYPE_PREF_BITS < 8
-	pj_assert(prefs[i] < (2 << PJ_ICE_CAND_TYPE_PREF_BITS));
+		pj_assert(prefs[i] < (2 << PJ_ICE_CAND_TYPE_PREF_BITS));
 #endif
-	ice->prefs[i] = prefs[i];
-    }
-    return PJ_SUCCESS;
+		ice->prefs[i] = prefs[i];
+	}
+	return PJ_SUCCESS;
 }
 
 
 /* Find component by ID */
 static pj_ice_sess_comp *find_comp(const pj_ice_sess *ice, unsigned comp_id)
 {
-    pj_assert(comp_id > 0 && comp_id <= ice->comp_cnt);
-    return (pj_ice_sess_comp*) &ice->comp[comp_id-1];
+	pj_assert(comp_id > 0 && comp_id <= ice->comp_cnt);
+	return (pj_ice_sess_comp*) &ice->comp[comp_id-1];
 }
 
 
 /* Callback by STUN authentication when it needs to send 401 */
 static pj_status_t stun_auth_get_auth(void *user_data,
-				      pj_pool_t *pool,
-				      pj_str_t *realm,
-				      pj_str_t *nonce)
+									  pj_pool_t *pool,
+									  pj_str_t *realm,
+									  pj_str_t *nonce)
 {
-    PJ_UNUSED_ARG(user_data);
-    PJ_UNUSED_ARG(pool);
+	PJ_UNUSED_ARG(user_data);
+	PJ_UNUSED_ARG(pool);
 
-    realm->slen = 0;
-    nonce->slen = 0;
+	realm->slen = 0;
+	nonce->slen = 0;
 
-    return PJ_SUCCESS;
+	return PJ_SUCCESS;
 }
 
 
 /* Get credential to be sent with outgoing message */
 static pj_status_t stun_auth_get_cred(const pj_stun_msg *msg,
-				      void *user_data,
-				      pj_pool_t *pool,
-				      pj_str_t *realm,
-				      pj_str_t *username,
-				      pj_str_t *nonce,
-				      pj_stun_passwd_type *data_type,
-				      pj_str_t *data)
+									  void *user_data,
+									  pj_pool_t *pool,
+									  pj_str_t *realm,
+									  pj_str_t *username,
+									  pj_str_t *nonce,
+									  pj_stun_passwd_type *data_type,
+									  pj_str_t *data)
 {
-    pj_stun_session *sess = (pj_stun_session *)user_data;
-    stun_data *sd = (stun_data*) pj_stun_session_get_user_data(sess);
-    pj_ice_sess *ice = sd->ice;
+	pj_stun_session *sess = (pj_stun_session *)user_data;
+	stun_data *sd = (stun_data*) pj_stun_session_get_user_data(sess);
+	pj_ice_sess *ice = sd->ice;
 
-    PJ_UNUSED_ARG(pool);
-    realm->slen = nonce->slen = 0;
+	PJ_UNUSED_ARG(pool);
+	realm->slen = nonce->slen = 0;
 
-    if (PJ_STUN_IS_RESPONSE(msg->hdr.type)) {
-	/* Outgoing responses need to have the same credential as
-	 * incoming requests.
-	 */
-	*username = ice->rx_uname;
-	*data_type = PJ_STUN_PASSWD_PLAIN;
-	*data = ice->rx_pass;
-    }
-    else {
-	*username = ice->tx_uname;
-	*data_type = PJ_STUN_PASSWD_PLAIN;
-	*data = ice->tx_pass;
-    }
+	if (PJ_STUN_IS_RESPONSE(msg->hdr.type)) {
+		/* Outgoing responses need to have the same credential as
+		* incoming requests.
+		*/
+		*username = ice->rx_uname;
+		*data_type = PJ_STUN_PASSWD_PLAIN;
+		*data = ice->rx_pass;
+	}
+	else {
+		*username = ice->tx_uname;
+		*data_type = PJ_STUN_PASSWD_PLAIN;
+		*data = ice->tx_pass;
+	}
 
-    return PJ_SUCCESS;
+	return PJ_SUCCESS;
 }
 
 /* Get password to be used to authenticate incoming message */
 static pj_status_t stun_auth_get_password(const pj_stun_msg *msg,
-					  void *user_data, 
-					  const pj_str_t *realm,
-					  const pj_str_t *username,
-					  pj_pool_t *pool,
-					  pj_stun_passwd_type *data_type,
-					  pj_str_t *data)
+										  void *user_data, 
+										  const pj_str_t *realm,
+										  const pj_str_t *username,
+										  pj_pool_t *pool,
+										  pj_stun_passwd_type *data_type,
+										  pj_str_t *data)
 {
-    pj_stun_session *sess = (pj_stun_session *)user_data;
-    stun_data *sd = (stun_data*) pj_stun_session_get_user_data(sess);
-    pj_ice_sess *ice = sd->ice;
+	pj_stun_session *sess = (pj_stun_session *)user_data;
+	stun_data *sd = (stun_data*) pj_stun_session_get_user_data(sess);
+	pj_ice_sess *ice = sd->ice;
 
-    PJ_UNUSED_ARG(realm);
-    PJ_UNUSED_ARG(pool);
+	PJ_UNUSED_ARG(realm);
+	PJ_UNUSED_ARG(pool);
 
-    if (PJ_STUN_IS_SUCCESS_RESPONSE(msg->hdr.type) ||
-	PJ_STUN_IS_ERROR_RESPONSE(msg->hdr.type))
-    {
-	/* Incoming response is authenticated with TX credential */
-	/* Verify username */
-	if (pj_strcmp(username, &ice->tx_uname) != 0)
-	    return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_UNAUTHORIZED);
-	*data_type = PJ_STUN_PASSWD_PLAIN;
-	*data = ice->tx_pass;
+	if (PJ_STUN_IS_SUCCESS_RESPONSE(msg->hdr.type) ||
+		PJ_STUN_IS_ERROR_RESPONSE(msg->hdr.type))
+	{
+		/* Incoming response is authenticated with TX credential */
+		/* Verify username */
+		if (pj_strcmp(username, &ice->tx_uname) != 0)
+			return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_UNAUTHORIZED);
+		*data_type = PJ_STUN_PASSWD_PLAIN;
+		*data = ice->tx_pass;
 
-    } else {
-	/* Incoming request is authenticated with RX credential */
-	/* The agent MUST accept a credential if the username consists
-	 * of two values separated by a colon, where the first value is
-	 * equal to the username fragment generated by the agent in an offer
-	 * or answer for a session in-progress, and the MESSAGE-INTEGRITY 
-	 * is the output of a hash of the password and the STUN packet's 
-	 * contents.
-	 */
-	const char *pos;
-	pj_str_t ufrag;
+	} else {
+		/* Incoming request is authenticated with RX credential */
+		/* The agent MUST accept a credential if the username consists
+		* of two values separated by a colon, where the first value is
+		* equal to the username fragment generated by the agent in an offer
+		* or answer for a session in-progress, and the MESSAGE-INTEGRITY 
+		* is the output of a hash of the password and the STUN packet's 
+		* contents.
+		*/
+		const char *pos;
+		pj_str_t ufrag;
 
-	pos = (const char*)pj_memchr(username->ptr, ':', username->slen);
-	if (pos == NULL)
-	    return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_UNAUTHORIZED);
+		pos = (const char*)pj_memchr(username->ptr, ':', username->slen);
+		if (pos == NULL)
+			return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_UNAUTHORIZED);
 
-	ufrag.ptr = (char*)username->ptr;
-	ufrag.slen = (pos - username->ptr);
+		ufrag.ptr = (char*)username->ptr;
+		ufrag.slen = (pos - username->ptr);
 
-	if (pj_strcmp(&ufrag, &ice->rx_ufrag) != 0)
-	    return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_UNAUTHORIZED);
+		if (pj_strcmp(&ufrag, &ice->rx_ufrag) != 0)
+			return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_UNAUTHORIZED);
 
-	*data_type = PJ_STUN_PASSWD_PLAIN;
-	*data = ice->rx_pass;
+		*data_type = PJ_STUN_PASSWD_PLAIN;
+		*data = ice->rx_pass;
 
-    }
+	}
 
-    return PJ_SUCCESS;
+	return PJ_SUCCESS;
 }
 
 
 static pj_uint32_t CALC_CAND_PRIO(pj_ice_sess *ice,
-				  pj_ice_cand_type type,
-				  pj_uint32_t local_pref,
-				  pj_uint32_t comp_id)
+								  pj_ice_cand_type type,
+								  pj_uint32_t local_pref,
+								  pj_uint32_t comp_id)
 {
 #if PJNATH_ICE_PRIO_STD
-    return ((ice->prefs[type] & 0xFF) << 24) + 
-	   ((local_pref & 0xFFFF)    << 8) +
-	   (((256 - comp_id) & 0xFF) << 0);
+	return ((ice->prefs[type] & 0xFF) << 24) + 
+		((local_pref & 0xFFFF)    << 8) +
+		(((256 - comp_id) & 0xFF) << 0);
 #else
-    enum {
-	type_mask   = ((2 << PJ_ICE_CAND_TYPE_PREF_BITS) - 1),
-	local_mask  = ((2 << PJ_ICE_LOCAL_PREF_BITS) - 1),
-	comp_mask   = ((2 << PJ_ICE_COMP_BITS) - 1),
+	enum {
+		type_mask   = ((2 << PJ_ICE_CAND_TYPE_PREF_BITS) - 1),
+		local_mask  = ((2 << PJ_ICE_LOCAL_PREF_BITS) - 1),
+		comp_mask   = ((2 << PJ_ICE_COMP_BITS) - 1),
 
-	comp_shift  = 0,
-	local_shift = (PJ_ICE_COMP_BITS),
-	type_shift  = (comp_shift + local_shift),
+		comp_shift  = 0,
+		local_shift = (PJ_ICE_COMP_BITS),
+		type_shift  = (comp_shift + local_shift),
 
-	max_comp    = (2<<PJ_ICE_COMP_BITS),
-    };
+		max_comp    = (2<<PJ_ICE_COMP_BITS),
+	};
 
-    return ((ice->prefs[type] & type_mask) << type_shift) + 
-	   ((local_pref & local_mask) << local_shift) +
-	   (((max_comp - comp_id) & comp_mask) << comp_shift);
+	return ((ice->prefs[type] & type_mask) << type_shift) + 
+		((local_pref & local_mask) << local_shift) +
+		(((max_comp - comp_id) & comp_mask) << comp_shift);
 #endif
 }
 
 
 /*
- * Add ICE candidate
- */
+* Add ICE candidate
+*/
 PJ_DEF(pj_status_t) pj_ice_sess_add_cand(pj_ice_sess *ice,
-					 unsigned comp_id,
-					 unsigned transport_id,
-					 pj_ice_cand_type type,
-					 pj_uint16_t local_pref,
-					 const pj_str_t *foundation,
-					 const pj_sockaddr_t *addr,
-					 const pj_sockaddr_t *base_addr,
-					 const pj_sockaddr_t *rel_addr,
-					 int addr_len,
-					 unsigned *p_cand_id)
+										 unsigned comp_id,
+										 unsigned transport_id,
+										 pj_ice_cand_type type,
+										 pj_uint16_t local_pref,
+										 const pj_str_t *foundation,
+										 const pj_sockaddr_t *addr,
+										 const pj_sockaddr_t *base_addr,
+										 const pj_sockaddr_t *rel_addr,
+										 int addr_len,
+										 unsigned *p_cand_id)
 {
-    pj_ice_sess_cand *lcand;
-    pj_status_t status = PJ_SUCCESS;
+	pj_ice_sess_cand *lcand;
+	pj_status_t status = PJ_SUCCESS;
 
-    PJ_ASSERT_RETURN(ice && comp_id && 
-		     foundation && addr && base_addr && addr_len,
-		     PJ_EINVAL);
-    PJ_ASSERT_RETURN(comp_id <= ice->comp_cnt, PJ_EINVAL);
+	PJ_ASSERT_RETURN(ice && comp_id && 
+		foundation && addr && base_addr && addr_len,
+		PJ_EINVAL);
+	PJ_ASSERT_RETURN(comp_id <= ice->comp_cnt, PJ_EINVAL);
 
-    pj_mutex_lock(ice->mutex);
+	pj_mutex_lock(ice->mutex);
 
-    if (ice->lcand_cnt >= PJ_ARRAY_SIZE(ice->lcand)) {
-	status = PJ_ETOOMANY;
-	goto on_error;
-    }
+	if (ice->lcand_cnt >= PJ_ARRAY_SIZE(ice->lcand)) {
+		status = PJ_ETOOMANY;
+		goto on_error;
+	}
 
-    lcand = &ice->lcand[ice->lcand_cnt];
-    lcand->comp_id = (pj_uint8_t)comp_id;
-    lcand->transport_id = (pj_uint8_t)transport_id;
-    lcand->type = type;
-    pj_strdup(ice->pool, &lcand->foundation, foundation);
-    lcand->prio = CALC_CAND_PRIO(ice, type, local_pref, lcand->comp_id);
-    pj_memcpy(&lcand->addr, addr, addr_len);
-    pj_memcpy(&lcand->base_addr, base_addr, addr_len);
-    if (rel_addr == NULL)
-	rel_addr = base_addr;
-    pj_memcpy(&lcand->rel_addr, rel_addr, addr_len);
+	lcand = &ice->lcand[ice->lcand_cnt];
+	lcand->comp_id = (pj_uint8_t)comp_id;
+	lcand->transport_id = (pj_uint8_t)transport_id;
+	lcand->type = type;
+	pj_strdup(ice->pool, &lcand->foundation, foundation);
+	lcand->prio = CALC_CAND_PRIO(ice, type, local_pref, lcand->comp_id);
+	pj_memcpy(&lcand->addr, addr, addr_len);
+	pj_memcpy(&lcand->base_addr, base_addr, addr_len);
+	if (rel_addr == NULL)
+		rel_addr = base_addr;
+	pj_memcpy(&lcand->rel_addr, rel_addr, addr_len);
 
-    pj_ansi_strcpy(ice->tmp.txt, pj_inet_ntoa(lcand->addr.ipv4.sin_addr));
-    LOG4((ice->obj_name, 
-	 "Candidate %d added: comp_id=%d, type=%s, foundation=%.*s, "
-	 "addr=%s:%d, base=%s:%d, prio=0x%x (%u)",
-	 ice->lcand_cnt, 
-	 lcand->comp_id, 
-	 cand_type_names[lcand->type],
-	 (int)lcand->foundation.slen,
-	 lcand->foundation.ptr,
-	 ice->tmp.txt, 
-	 (int)pj_ntohs(lcand->addr.ipv4.sin_port),
-	 pj_inet_ntoa(lcand->base_addr.ipv4.sin_addr),
-	 (int)pj_htons(lcand->base_addr.ipv4.sin_port),
-	 lcand->prio, lcand->prio));
+	pj_ansi_strcpy(ice->tmp.txt, pj_inet_ntoa(lcand->addr.ipv4.sin_addr));
+	LOG4((ice->obj_name, 
+		"Candidate %d added: comp_id=%d, type=%s, foundation=%.*s, "
+		"addr=%s:%d, base=%s:%d, prio=0x%x (%u)",
+		ice->lcand_cnt, 
+		lcand->comp_id, 
+		cand_type_names[lcand->type],
+		(int)lcand->foundation.slen,
+		lcand->foundation.ptr,
+		ice->tmp.txt, 
+		(int)pj_ntohs(lcand->addr.ipv4.sin_port),
+		pj_inet_ntoa(lcand->base_addr.ipv4.sin_addr),
+		(int)pj_htons(lcand->base_addr.ipv4.sin_port),
+		lcand->prio, lcand->prio));
 
-    if (p_cand_id)
-	*p_cand_id = ice->lcand_cnt;
+	if (p_cand_id)
+		*p_cand_id = ice->lcand_cnt;
 
-    ++ice->lcand_cnt;
+	++ice->lcand_cnt;
 
 on_error:
-    pj_mutex_unlock(ice->mutex);
-    return status;
+	pj_mutex_unlock(ice->mutex);
+	return status;
 }
 
 
 /* Find default candidate ID for the component */
 PJ_DEF(pj_status_t) pj_ice_sess_find_default_cand(pj_ice_sess *ice,
-						  unsigned comp_id,
-						  int *cand_id)
+												  unsigned comp_id,
+												  int *cand_id)
 {
-    unsigned i;
+	unsigned i;
 
-    PJ_ASSERT_RETURN(ice && comp_id && cand_id, PJ_EINVAL);
-    PJ_ASSERT_RETURN(comp_id <= ice->comp_cnt, PJ_EINVAL);
+	PJ_ASSERT_RETURN(ice && comp_id && cand_id, PJ_EINVAL);
+	PJ_ASSERT_RETURN(comp_id <= ice->comp_cnt, PJ_EINVAL);
 
-    *cand_id = -1;
+	*cand_id = -1;
 
-    pj_mutex_lock(ice->mutex);
+	pj_mutex_lock(ice->mutex);
 
-    /* First find in valid list if we have nominated pair */
-    for (i=0; i<ice->valid_list.count; ++i) {
-	pj_ice_sess_check *check = &ice->valid_list.checks[i];
-	
-	if (check->lcand->comp_id == comp_id) {
-	    *cand_id = GET_LCAND_ID(check->lcand);
-	    pj_mutex_unlock(ice->mutex);
-	    return PJ_SUCCESS;
+	/* First find in valid list if we have nominated pair */
+	for (i=0; i<ice->valid_list.count; ++i) {
+		pj_ice_sess_check *check = &ice->valid_list.checks[i];
+
+		if (check->lcand->comp_id == comp_id) {
+			*cand_id = GET_LCAND_ID(check->lcand);
+			pj_mutex_unlock(ice->mutex);
+			return PJ_SUCCESS;
+		}
 	}
-    }
 
-    /* If there's no nominated pair, find relayed candidate */
-    for (i=0; i<ice->lcand_cnt; ++i) {
-	pj_ice_sess_cand *lcand = &ice->lcand[i];
-	if (lcand->comp_id==comp_id &&
-	    lcand->type == PJ_ICE_CAND_TYPE_RELAYED) 
-	{
-	    *cand_id = GET_LCAND_ID(lcand);
-	    pj_mutex_unlock(ice->mutex);
-	    return PJ_SUCCESS;
+	/* If there's no nominated pair, find relayed candidate */
+	for (i=0; i<ice->lcand_cnt; ++i) {
+		pj_ice_sess_cand *lcand = &ice->lcand[i];
+		if (lcand->comp_id==comp_id &&
+			lcand->type == PJ_ICE_CAND_TYPE_RELAYED) 
+		{
+			*cand_id = GET_LCAND_ID(lcand);
+			pj_mutex_unlock(ice->mutex);
+			return PJ_SUCCESS;
+		}
 	}
-    }
 
-    /* If there's no relayed candidate, find reflexive candidate */
-    for (i=0; i<ice->lcand_cnt; ++i) {
-	pj_ice_sess_cand *lcand = &ice->lcand[i];
-	if (lcand->comp_id==comp_id &&
-	    (lcand->type == PJ_ICE_CAND_TYPE_SRFLX ||
-	     lcand->type == PJ_ICE_CAND_TYPE_PRFLX)) 
-	{
-	    *cand_id = GET_LCAND_ID(lcand);
-	    pj_mutex_unlock(ice->mutex);
-	    return PJ_SUCCESS;
+	/* If there's no relayed candidate, find reflexive candidate */
+	for (i=0; i<ice->lcand_cnt; ++i) {
+		pj_ice_sess_cand *lcand = &ice->lcand[i];
+		if (lcand->comp_id==comp_id &&
+			(lcand->type == PJ_ICE_CAND_TYPE_SRFLX ||
+			lcand->type == PJ_ICE_CAND_TYPE_PRFLX)) 
+		{
+			*cand_id = GET_LCAND_ID(lcand);
+			pj_mutex_unlock(ice->mutex);
+			return PJ_SUCCESS;
+		}
 	}
-    }
 
-    /* Otherwise return host candidate */
-    for (i=0; i<ice->lcand_cnt; ++i) {
-	pj_ice_sess_cand *lcand = &ice->lcand[i];
-	if (lcand->comp_id==comp_id &&
-	    lcand->type == PJ_ICE_CAND_TYPE_HOST) 
-	{
-	    *cand_id = GET_LCAND_ID(lcand);
-	    pj_mutex_unlock(ice->mutex);
-	    return PJ_SUCCESS;
+	/* Otherwise return host candidate */
+	for (i=0; i<ice->lcand_cnt; ++i) {
+		pj_ice_sess_cand *lcand = &ice->lcand[i];
+		if (lcand->comp_id==comp_id &&
+			lcand->type == PJ_ICE_CAND_TYPE_HOST) 
+		{
+			*cand_id = GET_LCAND_ID(lcand);
+			pj_mutex_unlock(ice->mutex);
+			return PJ_SUCCESS;
+		}
 	}
-    }
 
-    /* Still no candidate is found! :( */
-    pj_mutex_unlock(ice->mutex);
+	/* Still no candidate is found! :( */
+	pj_mutex_unlock(ice->mutex);
 
-    pj_assert(!"Should have a candidate by now");
-    return PJ_EBUG;
+	pj_assert(!"Should have a candidate by now");
+	return PJ_EBUG;
 }
 
 
@@ -833,92 +849,92 @@
 #endif
 
 static pj_timestamp CALC_CHECK_PRIO(const pj_ice_sess *ice, 
-				    const pj_ice_sess_cand *lcand,
-				    const pj_ice_sess_cand *rcand)
+									const pj_ice_sess_cand *lcand,
+									const pj_ice_sess_cand *rcand)
 {
-    pj_uint32_t O, A;
-    pj_timestamp prio;
+	pj_uint32_t O, A;
+	pj_timestamp prio;
 
-    /* Original formula:
-     *   pair priority = 2^32*MIN(O,A) + 2*MAX(O,A) + (O>A?1:0)
-     */
+	/* Original formula:
+	*   pair priority = 2^32*MIN(O,A) + 2*MAX(O,A) + (O>A?1:0)
+	*/
 
-    if (ice->role == PJ_ICE_SESS_ROLE_CONTROLLING) {
-	O = lcand->prio; 
-	A = rcand->prio;
-    } else {
-	O = rcand->prio;
-	A = lcand->prio;
-    }
+	if (ice->role == PJ_ICE_SESS_ROLE_CONTROLLING) {
+		O = lcand->prio; 
+		A = rcand->prio;
+	} else {
+		O = rcand->prio;
+		A = lcand->prio;
+	}
 
-    /*
-    return ((pj_uint64_t)1 << 32) * MIN(O, A) +
-	   (pj_uint64_t)2 * MAX(O, A) + (O>A ? 1 : 0);
-    */
+	/*
+	return ((pj_uint64_t)1 << 32) * MIN(O, A) +
+	(pj_uint64_t)2 * MAX(O, A) + (O>A ? 1 : 0);
+	*/
 
-    prio.u32.hi = MIN(O,A);
-    prio.u32.lo = (MAX(O, A) << 1) + (O>A ? 1 : 0);
+	prio.u32.hi = MIN(O,A);
+	prio.u32.lo = (MAX(O, A) << 1) + (O>A ? 1 : 0);
 
-    return prio;
+	return prio;
 }
 
 
 PJ_INLINE(int) CMP_CHECK_PRIO(const pj_ice_sess_check *c1,
-			      const pj_ice_sess_check *c2)
+							  const pj_ice_sess_check *c2)
 {
-    return pj_cmp_timestamp(&c1->prio, &c2->prio);
+	return pj_cmp_timestamp(&c1->prio, &c2->prio);
 }
 
 
 #if PJ_LOG_MAX_LEVEL >= 4
 static const char *dump_check(char *buffer, unsigned bufsize,
-			      const pj_ice_sess_checklist *clist,
-			      const pj_ice_sess_check *check)
+							  const pj_ice_sess_checklist *clist,
+							  const pj_ice_sess_check *check)
 {
-    const pj_ice_sess_cand *lcand = check->lcand;
-    const pj_ice_sess_cand *rcand = check->rcand;
-    char laddr[PJ_INET6_ADDRSTRLEN];
-    int len;
+	const pj_ice_sess_cand *lcand = check->lcand;
+	const pj_ice_sess_cand *rcand = check->rcand;
+	char laddr[PJ_INET6_ADDRSTRLEN];
+	int len;
 
-    PJ_CHECK_STACK();
+	PJ_CHECK_STACK();
 
-    pj_ansi_strcpy(laddr, pj_inet_ntoa(lcand->addr.ipv4.sin_addr));
+	pj_ansi_strcpy(laddr, pj_inet_ntoa(lcand->addr.ipv4.sin_addr));
 
-    if (lcand->addr.addr.sa_family == pj_AF_INET()) {
-	len = pj_ansi_snprintf(buffer, bufsize,
-			       "%d: [%d] %s:%d-->%s:%d",
-			       (int)GET_CHECK_ID(clist, check),
-			       check->lcand->comp_id,
-			       laddr, (int)pj_ntohs(lcand->addr.ipv4.sin_port),
-			       pj_inet_ntoa(rcand->addr.ipv4.sin_addr),
-			       (int)pj_ntohs(rcand->addr.ipv4.sin_port));
-    } else {
-	len = pj_ansi_snprintf(buffer, bufsize, "IPv6->IPv6");
-    }
+	if (lcand->addr.addr.sa_family == pj_AF_INET()) {
+		len = pj_ansi_snprintf(buffer, bufsize,
+			"%d: [%d] %s:%d-->%s:%d",
+			(int)GET_CHECK_ID(clist, check),
+			check->lcand->comp_id,
+			laddr, (int)pj_ntohs(lcand->addr.ipv4.sin_port),
+			pj_inet_ntoa(rcand->addr.ipv4.sin_addr),
+			(int)pj_ntohs(rcand->addr.ipv4.sin_port));
+	} else {
+		len = pj_ansi_snprintf(buffer, bufsize, "IPv6->IPv6");
+	}
 
 
-    if (len < 0)
-	len = 0;
-    else if (len >= (int)bufsize)
-	len = bufsize - 1;
+	if (len < 0)
+		len = 0;
+	else if (len >= (int)bufsize)
+		len = bufsize - 1;
 
-    buffer[len] = '\0';
-    return buffer;
+	buffer[len] = '\0';
+	return buffer;
 }
 
 static void dump_checklist(const char *title, pj_ice_sess *ice, 
-			   const pj_ice_sess_checklist *clist)
+						   const pj_ice_sess_checklist *clist)
 {
-    unsigned i;
+	unsigned i;
 
-    LOG4((ice->obj_name, "%s", title));
-    for (i=0; i<clist->count; ++i) {
-	const pj_ice_sess_check *c = &clist->checks[i];
-	LOG4((ice->obj_name, " %s (%s, state=%s)",
-	     dump_check(ice->tmp.txt, sizeof(ice->tmp.txt), clist, c),
-	     (c->nominated ? "nominated" : "not nominated"), 
-	     check_state_name[c->state]));
-    }
+	LOG4((ice->obj_name, "%s", title));
+	for (i=0; i<clist->count; ++i) {
+		const pj_ice_sess_check *c = &clist->checks[i];
+		LOG4((ice->obj_name, " %s (%s, state=%s)",
+			dump_check(ice->tmp.txt, sizeof(ice->tmp.txt), clist, c),
+			(c->nominated ? "nominated" : "not nominated"), 
+			check_state_name[c->state]));
+	}
 }
 
 #else
@@ -926,2053 +942,2122 @@
 #endif
 
 static void check_set_state(pj_ice_sess *ice, pj_ice_sess_check *check,
-			    pj_ice_sess_check_state st, 
-			    pj_status_t err_code)
+							pj_ice_sess_check_state st, 
+							pj_status_t err_code)
 {
-    pj_assert(check->state < PJ_ICE_SESS_CHECK_STATE_SUCCEEDED);
+	if(ice->opt.is_webrtc && check->state >= PJ_ICE_SESS_CHECK_STATE_SUCCEEDED){
+		return;// return WebRTC keepAlive
+	}
 
-    LOG5((ice->obj_name, "Check %s: state changed from %s to %s",
-	 dump_check(ice->tmp.txt, sizeof(ice->tmp.txt), &ice->clist, check),
-	 check_state_name[check->state],
-	 check_state_name[st]));
-    check->state = st;
-    check->err_code = err_code;
+	pj_assert(check->state < PJ_ICE_SESS_CHECK_STATE_SUCCEEDED);
+
+	LOG5((ice->obj_name, "Check %s: state changed from %s to %s",
+		dump_check(ice->tmp.txt, sizeof(ice->tmp.txt), &ice->clist, check),
+		check_state_name[check->state],
+		check_state_name[st]));
+	check->state = st;
+	check->err_code = err_code;
 }
 
 static void clist_set_state(pj_ice_sess *ice, pj_ice_sess_checklist *clist,
-			    pj_ice_sess_checklist_state st)
+							pj_ice_sess_checklist_state st)
 {
-    if (clist->state != st) {
-	LOG5((ice->obj_name, "Checklist: state changed from %s to %s",
-	     clist_state_name[clist->state],
-	     clist_state_name[st]));
-	clist->state = st;
-    }
+	if (clist->state != st) {
+		LOG5((ice->obj_name, "Checklist: state changed from %s to %s",
+			clist_state_name[clist->state],
+			clist_state_name[st]));
+		clist->state = st;
+	}
 }
 
 /* Sort checklist based on priority */
 static void sort_checklist(pj_ice_sess *ice, pj_ice_sess_checklist *clist)
 {
-    unsigned i;
-    pj_ice_sess_check **check_ptr[PJ_ICE_MAX_COMP*2];
-    unsigned check_ptr_cnt = 0;
+	unsigned i;
+	pj_ice_sess_check **check_ptr[PJ_ICE_MAX_COMP*2];
+	unsigned check_ptr_cnt = 0;
 
-    for (i=0; i<ice->comp_cnt; ++i) {
-	if (ice->comp[i].valid_check) {
-	    check_ptr[check_ptr_cnt++] = &ice->comp[i].valid_check;
+	for (i=0; i<ice->comp_cnt; ++i) {
+		if (ice->comp[i].valid_check) {
+			check_ptr[check_ptr_cnt++] = &ice->comp[i].valid_check;
+		}
+		if (ice->comp[i].nominated_check) {
+			check_ptr[check_ptr_cnt++] = &ice->comp[i].nominated_check;
+		}
 	}
-	if (ice->comp[i].nominated_check) {
-	    check_ptr[check_ptr_cnt++] = &ice->comp[i].nominated_check;
-	}
-    }
 
-    for (i=0; i<clist->count-1; ++i) {
-	unsigned j, highest = i;
+	for (i=0; i<clist->count-1; ++i) {
+		unsigned j, highest = i;
 
-	for (j=i+1; j<clist->count; ++j) {
-	    if (CMP_CHECK_PRIO(&clist->checks[j], &clist->checks[highest]) > 0) {
-		highest = j;
-	    }
-	}
+		for (j=i+1; j<clist->count; ++j) {
+			if (CMP_CHECK_PRIO(&clist->checks[j], &clist->checks[highest]) > 0) {
+				highest = j;
+			}
+		}
 
-	if (highest != i) {
-	    pj_ice_sess_check tmp;
-	    unsigned k;
+		if (highest != i) {
+			pj_ice_sess_check tmp;
+			unsigned k;
 
-	    pj_memcpy(&tmp, &clist->checks[i], sizeof(pj_ice_sess_check));
-	    pj_memcpy(&clist->checks[i], &clist->checks[highest], 
-		      sizeof(pj_ice_sess_check));
-	    pj_memcpy(&clist->checks[highest], &tmp, 
-		      sizeof(pj_ice_sess_check));
+			pj_memcpy(&tmp, &clist->checks[i], sizeof(pj_ice_sess_check));
+			pj_memcpy(&clist->checks[i], &clist->checks[highest], 
+				sizeof(pj_ice_sess_check));
+			pj_memcpy(&clist->checks[highest], &tmp, 
+				sizeof(pj_ice_sess_check));
 
-	    /* Update valid and nominated check pointers, since we're moving
-	     * around checks
-	     */
-	    for (k=0; k<check_ptr_cnt; ++k) {
-		if (*check_ptr[k] == &clist->checks[highest])
-		    *check_ptr[k] = &clist->checks[i];
-		else if (*check_ptr[k] == &clist->checks[i])
-		    *check_ptr[k] = &clist->checks[highest];
-	    }
+			/* Update valid and nominated check pointers, since we're moving
+			* around checks
+			*/
+			for (k=0; k<check_ptr_cnt; ++k) {
+				if (*check_ptr[k] == &clist->checks[highest])
+					*check_ptr[k] = &clist->checks[i];
+				else if (*check_ptr[k] == &clist->checks[i])
+					*check_ptr[k] = &clist->checks[highest];
+			}
+		}
 	}
-    }
 }
 
 enum 
 { 
-    SOCKADDR_EQUAL = 0, 
-    SOCKADDR_NOT_EQUAL = 1 
+	SOCKADDR_EQUAL = 0, 
+	SOCKADDR_NOT_EQUAL = 1 
 };
 
 /* Utility: compare sockaddr.
- * Returns 0 if equal.
- */
+* Returns 0 if equal.
+*/
 static int sockaddr_cmp(const pj_sockaddr *a1, const pj_sockaddr *a2)
 {
-    if (a1->addr.sa_family != a2->addr.sa_family)
-	return SOCKADDR_NOT_EQUAL;
+	if (a1->addr.sa_family != a2->addr.sa_family)
+		return SOCKADDR_NOT_EQUAL;
 
-    if (a1->addr.sa_family == pj_AF_INET()) {
-	return !(a1->ipv4.sin_addr.s_addr == a2->ipv4.sin_addr.s_addr &&
-		 a1->ipv4.sin_port == a2->ipv4.sin_port);
-    } else if (a1->addr.sa_family == pj_AF_INET6()) {
-	return pj_memcmp(&a1->ipv6, &a2->ipv6, sizeof(a1->ipv6));
-    } else {
-	pj_assert(!"Invalid address family!");
-	return SOCKADDR_NOT_EQUAL;
-    }
+	if (a1->addr.sa_family == pj_AF_INET()) {
+		return !(a1->ipv4.sin_addr.s_addr == a2->ipv4.sin_addr.s_addr &&
+			a1->ipv4.sin_port == a2->ipv4.sin_port);
+	} else if (a1->addr.sa_family == pj_AF_INET6()) {
+		return pj_memcmp(&a1->ipv6, &a2->ipv6, sizeof(a1->ipv6));
+	} else {
+		pj_assert(!"Invalid address family!");
+		return SOCKADDR_NOT_EQUAL;
+	}
 }
 
 
 /* Prune checklist, this must have been done after the checklist
- * is sorted.
- */
+* is sorted.
+*/
 static pj_status_t prune_checklist(pj_ice_sess *ice, 
-				   pj_ice_sess_checklist *clist)
+								   pj_ice_sess_checklist *clist)
 {
-    unsigned i;
+	unsigned i;
 
-    /* Since an agent cannot send requests directly from a reflexive
-     * candidate, but only from its base, the agent next goes through the
-     * sorted list of candidate pairs.  For each pair where the local
-     * candidate is server reflexive, the server reflexive candidate MUST be
-     * replaced by its base.  Once this has been done, the agent MUST prune
-     * the list.  This is done by removing a pair if its local and remote
-     * candidates are identical to the local and remote candidates of a pair
-     * higher up on the priority list.  The result is a sequence of ordered
-     * candidate pairs, called the check list for that media stream.    
-     */
-    /* First replace SRFLX candidates with their base */
-    for (i=0; i<clist->count; ++i) {
-	pj_ice_sess_cand *srflx = clist->checks[i].lcand;
+	/* Since an agent cannot send requests directly from a reflexive
+	* candidate, but only from its base, the agent next goes through the
+	* sorted list of candidate pairs.  For each pair where the local
+	* candidate is server reflexive, the server reflexive candidate MUST be
+	* replaced by its base.  Once this has been done, the agent MUST prune
+	* the list.  This is done by removing a pair if its local and remote
+	* candidates are identical to the local and remote candidates of a pair
+	* higher up on the priority list.  The result is a sequence of ordered
+	* candidate pairs, called the check list for that media stream.    
+	*/
+	/* First replace SRFLX candidates with their base */
+	for (i=0; i<clist->count; ++i) {
+		pj_ice_sess_cand *srflx = clist->checks[i].lcand;
 
-	if (clist->checks[i].lcand->type == PJ_ICE_CAND_TYPE_SRFLX) {
-	    /* Find the base for this candidate */
-	    unsigned j;
-	    for (j=0; j<ice->lcand_cnt; ++j) {
-		pj_ice_sess_cand *host = &ice->lcand[j];
+		if (clist->checks[i].lcand->type == PJ_ICE_CAND_TYPE_SRFLX) {
+			/* Find the base for this candidate */
+			unsigned j;
+			for (j=0; j<ice->lcand_cnt; ++j) {
+				pj_ice_sess_cand *host = &ice->lcand[j];
 
-		if (host->type != PJ_ICE_CAND_TYPE_HOST)
-		    continue;
+				if (host->type != PJ_ICE_CAND_TYPE_HOST)
+					continue;
 
-		if (sockaddr_cmp(&srflx->base_addr, &host->addr) == 0) {
-		    /* Replace this SRFLX with its BASE */
-		    clist->checks[i].lcand = host;
-		    break;
+				if (sockaddr_cmp(&srflx->base_addr, &host->addr) == 0) {
+					/* Replace this SRFLX with its BASE */
+					clist->checks[i].lcand = host;
+					break;
+				}
+			}
+
+			if (j==ice->lcand_cnt) {
+				/* Host candidate not found this this srflx! */
+				LOG4((ice->obj_name, 
+					"Base candidate %s:%d not found for srflx candidate %d",
+					pj_inet_ntoa(srflx->base_addr.ipv4.sin_addr),
+					pj_ntohs(srflx->base_addr.ipv4.sin_port),
+					GET_LCAND_ID(clist->checks[i].lcand)));
+				return PJNATH_EICENOHOSTCAND;
+			}
 		}
-	    }
-
-	    if (j==ice->lcand_cnt) {
-		/* Host candidate not found this this srflx! */
-		LOG4((ice->obj_name, 
-		      "Base candidate %s:%d not found for srflx candidate %d",
-		      pj_inet_ntoa(srflx->base_addr.ipv4.sin_addr),
-		      pj_ntohs(srflx->base_addr.ipv4.sin_port),
-		      GET_LCAND_ID(clist->checks[i].lcand)));
-		return PJNATH_EICENOHOSTCAND;
-	    }
 	}
-    }
 
-    /* Next remove a pair if its local and remote candidates are identical
-     * to the local and remote candidates of a pair higher up on the priority
-     * list
-     */
-    /*
-     * Not in ICE!
-     * Remove host candidates if their base are the the same!
-     */
-    for (i=0; i<clist->count; ++i) {
-	pj_ice_sess_cand *licand = clist->checks[i].lcand;
-	pj_ice_sess_cand *ricand = clist->checks[i].rcand;
-	unsigned j;
+	/* Next remove a pair if its local and remote candidates are identical
+	* to the local and remote candidates of a pair higher up on the priority
+	* list
+	*/
+	/*
+	* Not in ICE!
+	* Remove host candidates if their base are the the same!
+	*/
+	for (i=0; i<clist->count; ++i) {
+		pj_ice_sess_cand *licand = clist->checks[i].lcand;
+		pj_ice_sess_cand *ricand = clist->checks[i].rcand;
+		unsigned j;
 
-	for (j=i+1; j<clist->count;) {
-	    pj_ice_sess_cand *ljcand = clist->checks[j].lcand;
-	    pj_ice_sess_cand *rjcand = clist->checks[j].rcand;
-	    const char *reason = NULL;
+		for (j=i+1; j<clist->count;) {
+			pj_ice_sess_cand *ljcand = clist->checks[j].lcand;
+			pj_ice_sess_cand *rjcand = clist->checks[j].rcand;
+			const char *reason = NULL;
 
-	    if ((licand == ljcand) && (ricand == rjcand)) {
-		reason = "duplicate found";
-	    } else if ((rjcand == ricand) &&
-		       (sockaddr_cmp(&ljcand->base_addr, 
-				     &licand->base_addr)==0)) 
-	    {
-		reason = "equal base";
-	    }
+			if ((licand == ljcand) && (ricand == rjcand)) {
+				reason = "duplicate found";
+			} else if ((rjcand == ricand) &&
+				(sockaddr_cmp(&ljcand->base_addr, 
+				&licand->base_addr)==0)) 
+			{
+				reason = "equal base";
+			}
 
-	    if (reason != NULL) {
-		/* Found duplicate, remove it */
-		LOG5((ice->obj_name, "Check %s pruned (%s)",
-		      dump_check(ice->tmp.txt, sizeof(ice->tmp.txt), 
-				 &ice->clist, &clist->checks[j]),
-		      reason));
+			if (reason != NULL) {
+				/* Found duplicate, remove it */
+				LOG5((ice->obj_name, "Check %s pruned (%s)",
+					dump_check(ice->tmp.txt, sizeof(ice->tmp.txt), 
+					&ice->clist, &clist->checks[j]),
+					reason));
 
-		pj_array_erase(clist->checks, sizeof(clist->checks[0]),
-			       clist->count, j);
-		--clist->count;
+				pj_array_erase(clist->checks, sizeof(clist->checks[0]),
+					clist->count, j);
+				--clist->count;
 
-	    } else {
-		++j;
-	    }
+			} else {
+				++j;
+			}
+		}
 	}
-    }
 
-    return PJ_SUCCESS;
+	return PJ_SUCCESS;
 }
 
 /* Timer callback */
 static void on_timer(pj_timer_heap_t *th, pj_timer_entry *te)
 {
-    pj_ice_sess *ice = (pj_ice_sess*) te->user_data;
-    enum timer_type type = (enum timer_type)te->id;
-    pj_bool_t has_mutex = PJ_TRUE;
+	pj_ice_sess *ice = (pj_ice_sess*) te->user_data;
+	enum timer_type type = (enum timer_type)te->id;
+	pj_bool_t has_mutex = PJ_TRUE;
 
-    PJ_UNUSED_ARG(th);
+	PJ_UNUSED_ARG(th);
 
-    pj_mutex_lock(ice->mutex);
+	pj_mutex_lock(ice->mutex);
 
-    te->id = TIMER_NONE;
+	te->id = TIMER_NONE;
 
-    switch (type) {
-    case TIMER_CONTROLLED_WAIT_NOM:
-	LOG4((ice->obj_name, 
-	      "Controlled agent timed-out in waiting for the controlling "
-	      "agent to send nominated check. Setting state to fail now.."));
-	on_ice_complete(ice, PJNATH_EICENOMTIMEOUT);
-	break;
-    case TIMER_COMPLETION_CALLBACK:
-	{
-	    void (*on_ice_complete)(pj_ice_sess *ice, pj_status_t status);
-	    pj_status_t ice_status;
+	switch (type) {
+	case TIMER_CONTROLLED_WAIT_NOM:
+		LOG4((ice->obj_name, 
+			"Controlled agent timed-out in waiting for the controlling "
+			"agent to send nominated check. Setting state to fail now.."));
+		on_ice_complete(ice, PJNATH_EICENOMTIMEOUT);
+		break;
+	case TIMER_COMPLETION_CALLBACK:
+		{
+			void (*on_ice_complete)(pj_ice_sess *ice, pj_status_t status);
+			pj_status_t ice_status;
 
-	    /* Start keep-alive timer but don't send any packets yet.
-	     * Need to do it here just in case app destroy the session
-	     * in the callback.
-	     */
-	    if (ice->ice_status == PJ_SUCCESS)
-		ice_keep_alive(ice, PJ_FALSE);
+			/* Start keep-alive timer but don't send any packets yet.
+			* Need to do it here just in case app destroy the session
+			* in the callback.
+			*/
 
-	    /* Release mutex in case app destroy us in the callback */
-	    ice_status = ice->ice_status;
-	    on_ice_complete = ice->cb.on_ice_complete;
-	    has_mutex = PJ_FALSE;
-	    pj_mutex_unlock(ice->mutex);
+			if (ice->ice_status == PJ_SUCCESS)
+				ice_keep_alive(ice, PJ_FALSE);
 
-	    /* Notify app about ICE completion*/
-	    if (on_ice_complete)
-		(*on_ice_complete)(ice, ice_status);
+			/* Release mutex in case app destroy us in the callback */
+			ice_status = ice->ice_status;
+			on_ice_complete = ice->cb.on_ice_complete;
+			has_mutex = PJ_FALSE;
+			pj_mutex_unlock(ice->mutex);
+
+			/* Notify app about ICE completion*/
+			if (on_ice_complete)
+				(*on_ice_complete)(ice, ice_status);
+		}
+		break;
+	case TIMER_START_NOMINATED_CHECK:
+		start_nominated_check(ice);
+		break;
+	case TIMER_KEEP_ALIVE:
+		ice_keep_alive(ice, PJ_TRUE);
+		break;
+	case TIMER_NONE:
+		/* Nothing to do, just to get rid of gcc warning */
+		break;
 	}
-	break;
-    case TIMER_START_NOMINATED_CHECK:
-	start_nominated_check(ice);
-	break;
-    case TIMER_KEEP_ALIVE:
-	ice_keep_alive(ice, PJ_TRUE);
-	break;
-    case TIMER_NONE:
-	/* Nothing to do, just to get rid of gcc warning */
-	break;
-    }
 
-    if (has_mutex)
-	pj_mutex_unlock(ice->mutex);
+	if (has_mutex)
+		pj_mutex_unlock(ice->mutex);
 }
 
 /* Send keep-alive */
 static void ice_keep_alive(pj_ice_sess *ice, pj_bool_t send_now)
 {
-    if (send_now) {
-	/* Send Binding Indication for the component */
-	pj_ice_sess_comp *comp = &ice->comp[ice->comp_ka];
-	pj_stun_tx_data *tdata;
-	pj_ice_sess_check *the_check;
-	pj_ice_msg_data *msg_data;
-	int addr_len;
-	pj_bool_t saved;
-	pj_status_t status;
+	if (send_now) {
+		/* Send Binding Indication for the component */
+		pj_ice_sess_comp *comp = &ice->comp[ice->comp_ka];
+		pj_stun_tx_data *tdata;
+		pj_ice_sess_check *the_check;
+		pj_ice_msg_data *msg_data;
+		int addr_len;
+		pj_bool_t saved;
+		pj_status_t status;
 
-	/* Must have nominated check by now */
-	pj_assert(comp->nominated_check != NULL);
-	the_check = comp->nominated_check;
+		/* Must have nominated check by now */
+		pj_assert(comp->nominated_check != NULL);
+		the_check = comp->nominated_check;
 
-	/* Create the Binding Indication */
-	status = pj_stun_session_create_ind(comp->stun_sess, 
-					    PJ_STUN_BINDING_INDICATION,
-					    &tdata);
-	if (status != PJ_SUCCESS)
-	    goto done;
+		/* Create the Binding Indication */
+		status = pj_stun_session_create_ind(comp->stun_sess, 
+			PJ_STUN_BINDING_INDICATION,
+			&tdata);
+		if (status != PJ_SUCCESS)
+			goto done;
 
-	/* Need the transport_id */
-	msg_data = PJ_POOL_ZALLOC_T(tdata->pool, pj_ice_msg_data);
-	msg_data->transport_id = the_check->lcand->transport_id;
+		/* Need the transport_id */
+		msg_data = PJ_POOL_ZALLOC_T(tdata->pool, pj_ice_msg_data);
+		msg_data->transport_id = the_check->lcand->transport_id;
 
-	/* Temporarily disable FINGERPRINT. The Binding Indication 
-	 * SHOULD NOT contain any attributes.
-	 */
-	saved = pj_stun_session_use_fingerprint(comp->stun_sess, PJ_FALSE);
+		/* Temporarily disable FINGERPRINT. The Binding Indication 
+		* SHOULD NOT contain any attributes.
+		*/
+		saved = pj_stun_session_use_fingerprint(comp->stun_sess, PJ_FALSE);
 
-	/* Send to session */
-	addr_len = pj_sockaddr_get_len(&the_check->rcand->addr);
-	status = pj_stun_session_send_msg(comp->stun_sess, msg_data,
-					  PJ_FALSE, PJ_FALSE, 
-					  &the_check->rcand->addr, 
-					  addr_len, tdata);
+		/* Send to session */
+		addr_len = pj_sockaddr_get_len(&the_check->rcand->addr);
+		status = pj_stun_session_send_msg(comp->stun_sess, msg_data,
+			PJ_FALSE, PJ_FALSE, 
+			&the_check->rcand->addr, 
+			addr_len, tdata);
 
-	/* Restore FINGERPRINT usage */
-	pj_stun_session_use_fingerprint(comp->stun_sess, saved);
+		/* Restore FINGERPRINT usage */
+		pj_stun_session_use_fingerprint(comp->stun_sess, saved);
 
 done:
-	ice->comp_ka = (ice->comp_ka + 1) % ice->comp_cnt;
-    }
+		ice->comp_ka = (ice->comp_ka + 1) % ice->comp_cnt;
+	}
 
-    if (ice->timer.id == TIMER_NONE) {
-	pj_time_val delay = { 0, 0 };
+	if (ice->timer.id == TIMER_NONE) {
+		pj_time_val delay = { 0, 0 };
 
-	delay.msec = (PJ_ICE_SESS_KEEP_ALIVE_MIN + 
-		      (pj_rand() % PJ_ICE_SESS_KEEP_ALIVE_MAX_RAND)) * 1000 / 
-		     ice->comp_cnt;
-	pj_time_val_normalize(&delay);
+		delay.msec = (PJ_ICE_SESS_KEEP_ALIVE_MIN + 
+			(pj_rand() % PJ_ICE_SESS_KEEP_ALIVE_MAX_RAND)) * 1000 / 
+			ice->comp_cnt;
+		pj_time_val_normalize(&delay);
 
-	ice->timer.id = TIMER_KEEP_ALIVE;
-	pj_timer_heap_schedule(ice->stun_cfg.timer_heap, &ice->timer, &delay);
+		ice->timer.id = TIMER_KEEP_ALIVE;
+		pj_timer_heap_schedule(ice->stun_cfg.timer_heap, &ice->timer, &delay);
 
-    } else {
-	pj_assert(!"Not expected any timer active");
-    }
+	} else {
+		pj_assert(!"Not expected any timer active");
+	}
 }
 
 /* This function is called when ICE processing completes */
 static void on_ice_complete(pj_ice_sess *ice, pj_status_t status)
 {
-    if (!ice->is_complete) {
-	ice->is_complete = PJ_TRUE;
-	ice->ice_status = status;
-    
-	if (ice->timer.id != TIMER_NONE) {
-	    pj_timer_heap_cancel(ice->stun_cfg.timer_heap, &ice->timer);
-	    ice->timer.id = TIMER_NONE;
-	}
+	if (!ice->is_complete) {
+		ice->is_complete = PJ_TRUE;
+		ice->ice_status = status;
 
-	/* Log message */
-	LOG4((ice->obj_name, "ICE process complete, status=%s", 
-	     pj_strerror(status, ice->tmp.errmsg, 
-			 sizeof(ice->tmp.errmsg)).ptr));
+		if (ice->timer.id != TIMER_NONE) {
+			pj_timer_heap_cancel(ice->stun_cfg.timer_heap, &ice->timer);
+			ice->timer.id = TIMER_NONE;
+		}
 
-	dump_checklist("Valid list", ice, &ice->valid_list);
+		/* Log message */
+		LOG4((ice->obj_name, "ICE process complete, status=%s", 
+			pj_strerror(status, ice->tmp.errmsg, 
+			sizeof(ice->tmp.errmsg)).ptr));
 
-	/* Call callback */
-	if (ice->cb.on_ice_complete) {
-	    pj_time_val delay = {0, 0};
+		dump_checklist("Valid list", ice, &ice->valid_list);
 
-	    ice->timer.id = TIMER_COMPLETION_CALLBACK;
-	    pj_timer_heap_schedule(ice->stun_cfg.timer_heap, 
-				   &ice->timer, &delay);
+		/* Call callback */
+		if (ice->cb.on_ice_complete) {
+			pj_time_val delay = {0, 0};
+
+			ice->timer.id = TIMER_COMPLETION_CALLBACK;
+			pj_timer_heap_schedule(ice->stun_cfg.timer_heap, 
+				&ice->timer, &delay);
+		}
 	}
-    }
 }
 
 /* Update valid check and nominated check for the candidate */
 static void update_comp_check(pj_ice_sess *ice, unsigned comp_id, 
-			      pj_ice_sess_check *check)
+							  pj_ice_sess_check *check)
 {
-    pj_ice_sess_comp *comp;
+	pj_ice_sess_comp *comp;
 
-    comp = find_comp(ice, comp_id);
-    if (comp->valid_check == NULL) {
-	comp->valid_check = check;
-    } else {
-	if (CMP_CHECK_PRIO(comp->valid_check, check) < 0)
-	    comp->valid_check = check;
-    }
-
-    if (check->nominated) {
-	/* Update the nominated check for the component */
-	if (comp->nominated_check == NULL) {
-	    comp->nominated_check = check;
+	comp = find_comp(ice, comp_id);
+	if (comp->valid_check == NULL) {
+		comp->valid_check = check;
 	} else {
-	    if (CMP_CHECK_PRIO(comp->nominated_check, check) < 0)
-		comp->nominated_check = check;
+		if (CMP_CHECK_PRIO(comp->valid_check, check) < 0)
+			comp->valid_check = check;
 	}
-    }
+
+	if (check->nominated) {
+		/* Update the nominated check for the component */
+		if (comp->nominated_check == NULL) {
+			comp->nominated_check = check;
+		} else {
+			if (CMP_CHECK_PRIO(comp->nominated_check, check) < 0)
+				comp->nominated_check = check;
+		}
+	}
 }
 
 /* This function is called when one check completes */
 static pj_bool_t on_check_complete(pj_ice_sess *ice,
-				   pj_ice_sess_check *check)
+								   pj_ice_sess_check *check)
 {
-    pj_ice_sess_comp *comp;
-    unsigned i;
+	pj_ice_sess_comp *comp;
+	unsigned i;
 
-    pj_assert(check->state >= PJ_ICE_SESS_CHECK_STATE_SUCCEEDED);
+	pj_assert(check->state >= PJ_ICE_SESS_CHECK_STATE_SUCCEEDED);
 
-    comp = find_comp(ice, check->lcand->comp_id);
+	comp = find_comp(ice, check->lcand->comp_id);
 
-    /* 7.1.2.2.2.  Updating Pair States
-     * 
-     * The agent sets the state of the pair that generated the check to
-     * Succeeded.  The success of this check might also cause the state of
-     * other checks to change as well.  The agent MUST perform the following
-     * two steps:
-     * 
-     * 1.  The agent changes the states for all other Frozen pairs for the
-     *     same media stream and same foundation to Waiting.  Typically
-     *     these other pairs will have different component IDs but not
-     *     always.
-     */
-    if (check->err_code==PJ_SUCCESS) {
+	/* 7.1.2.2.2.  Updating Pair States
+	* 
+	* The agent sets the state of the pair that generated the check to
+	* Succeeded.  The success of this check might also cause the state of
+	* other checks to change as well.  The agent MUST perform the following
+	* two steps:
+	* 
+	* 1.  The agent changes the states for all other Frozen pairs for the
+	*     same media stream and same foundation to Waiting.  Typically
+	*     these other pairs will have different component IDs but not
+	*     always.
+	*/
+	if (check->err_code==PJ_SUCCESS) {
 
-	for (i=0; i<ice->clist.count; ++i) {
-	    pj_ice_sess_check *c = &ice->clist.checks[i];
-	    if (pj_strcmp(&c->lcand->foundation, &check->lcand->foundation)==0
-		 && c->state == PJ_ICE_SESS_CHECK_STATE_FROZEN)
-	    {
-		check_set_state(ice, c, PJ_ICE_SESS_CHECK_STATE_WAITING, 0);
-	    }
-	}
+		for (i=0; i<ice->clist.count; ++i) {
+			pj_ice_sess_check *c = &ice->clist.checks[i];
+			if (pj_strcmp(&c->lcand->foundation, &check->lcand->foundation)==0
+				&& c->state == PJ_ICE_SESS_CHECK_STATE_FROZEN)
+			{
+				check_set_state(ice, c, PJ_ICE_SESS_CHECK_STATE_WAITING, 0);
+			}
+		}
 
-	LOG5((ice->obj_name, "Check %d is successful%s",
-	     GET_CHECK_ID(&ice->clist, check),
-	     (check->nominated ? "  and nominated" : "")));
+		LOG5((ice->obj_name, "Check %d is successful%s",
+			GET_CHECK_ID(&ice->clist, check),
+			(check->nominated ? "  and nominated" : "")));
 
-    }
+	}
 
-    /* 8.2.  Updating States
-     * 
-     * For both controlling and controlled agents, the state of ICE
-     * processing depends on the presence of nominated candidate pairs in
-     * the valid list and on the state of the check list:
-     *
-     * o  If there are no nominated pairs in the valid list for a media
-     *    stream and the state of the check list is Running, ICE processing
-     *    continues.
-     *
-     * o  If there is at least one nominated pair in the valid list:
-     *
-     *    - The agent MUST remove all Waiting and Frozen pairs in the check
-     *      list for the same component as the nominated pairs for that
-     *      media stream
-     *
-     *    - If an In-Progress pair in the check list is for the same
-     *      component as a nominated pair, the agent SHOULD cease
-     *      retransmissions for its check if its pair priority is lower
-     *      than the lowest priority nominated pair for that component
-     */
-    if (check->err_code==PJ_SUCCESS && check->nominated) {
+	/* 8.2.  Updating States
+	* 
+	* For both controlling and controlled agents, the state of ICE
+	* processing depends on the presence of nominated candidate pairs in
+	* the valid list and on the state of the check list:
+	*
+	* o  If there are no nominated pairs in the valid list for a media
+	*    stream and the state of the check list is Running, ICE processing
+	*    continues.
+	*
+	* o  If there is at least one nominated pair in the valid list:
+	*
+	*    - The agent MUST remove all Waiting and Frozen pairs in the check
+	*      list for the same component as the nominated pairs for that
+	*      media stream
+	*
+	*    - If an In-Progress pair in the check list is for the same
+	*      component as a nominated pair, the agent SHOULD cease
+	*      retransmissions for its check if its pair priority is lower
+	*      than the lowest priority nominated pair for that component
+	*/
+	if (check->err_code==PJ_SUCCESS && check->nominated) {
 
-	for (i=0; i<ice->clist.count; ++i) {
+		for (i=0; i<ice->clist.count; ++i) {
 
-	    pj_ice_sess_check *c = &ice->clist.checks[i];
+			pj_ice_sess_check *c = &ice->clist.checks[i];
 
-	    if (c->lcand->comp_id == check->lcand->comp_id) {
+			if (c->lcand->comp_id == check->lcand->comp_id) {
 
-		if (c->state < PJ_ICE_SESS_CHECK_STATE_IN_PROGRESS) {
+				if (c->state < PJ_ICE_SESS_CHECK_STATE_IN_PROGRESS) {
 
-		    /* Just fail Frozen/Waiting check */
-		    LOG5((ice->obj_name, 
-			 "Check %s to be failed because state is %s",
-			 dump_check(ice->tmp.txt, sizeof(ice->tmp.txt), 
-				    &ice->clist, c), 
-			 check_state_name[c->state]));
-		    check_set_state(ice, c, PJ_ICE_SESS_CHECK_STATE_FAILED,
-				    PJ_ECANCELLED);
+					/* Just fail Frozen/Waiting check */
+					LOG5((ice->obj_name, 
+						"Check %s to be failed because state is %s",
+						dump_check(ice->tmp.txt, sizeof(ice->tmp.txt), 
+						&ice->clist, c), 
+						check_state_name[c->state]));
+					check_set_state(ice, c, PJ_ICE_SESS_CHECK_STATE_FAILED,
+						PJ_ECANCELLED);
 
-		} else if (c->state == PJ_ICE_SESS_CHECK_STATE_IN_PROGRESS
-			   && (PJ_ICE_CANCEL_ALL ||
-			        CMP_CHECK_PRIO(c, check) < 0)) {
+				} else if (c->state == PJ_ICE_SESS_CHECK_STATE_IN_PROGRESS
+					&& (PJ_ICE_CANCEL_ALL ||
+					CMP_CHECK_PRIO(c, check) < 0)) {
 
-		    /* State is IN_PROGRESS, cancel transaction */
-		    if (c->tdata) {
-			LOG5((ice->obj_name, 
-			     "Cancelling check %s (In Progress)",
-			     dump_check(ice->tmp.txt, sizeof(ice->tmp.txt), 
-					&ice->clist, c)));
-			pj_stun_session_cancel_req(comp->stun_sess, 
-						   c->tdata, PJ_FALSE, 0);
-			c->tdata = NULL;
-			check_set_state(ice, c, PJ_ICE_SESS_CHECK_STATE_FAILED,
-					PJ_ECANCELLED);
-		    }
+						/* State is IN_PROGRESS, cancel transaction */
+						if (c->tdata) {
+							LOG5((ice->obj_name, 
+								"Cancelling check %s (In Progress)",
+								dump_check(ice->tmp.txt, sizeof(ice->tmp.txt), 
+								&ice->clist, c)));
+							pj_stun_session_cancel_req(comp->stun_sess, 
+								c->tdata, PJ_FALSE, 0);
+							c->tdata = NULL;
+							check_set_state(ice, c, PJ_ICE_SESS_CHECK_STATE_FAILED,
+								PJ_ECANCELLED);
+						}
+				}
+			}
 		}
-	    }
 	}
-    }
 
 
-    /* Still in 8.2.  Updating States
-     * 
-     * o  Once there is at least one nominated pair in the valid list for
-     *    every component of at least one media stream and the state of the
-     *    check list is Running:
-     *    
-     *    *  The agent MUST change the state of processing for its check
-     *       list for that media stream to Completed.
-     *    
-     *    *  The agent MUST continue to respond to any checks it may still
-     *       receive for that media stream, and MUST perform triggered
-     *       checks if required by the processing of Section 7.2.
-     *    
-     *    *  The agent MAY begin transmitting media for this media stream as
-     *       described in Section 11.1
-     */
+	/* Still in 8.2.  Updating States
+	* 
+	* o  Once there is at least one nominated pair in the valid list for
+	*    every component of at least one media stream and the state of the
+	*    check list is Running:
+	*    
+	*    *  The agent MUST change the state of processing for its check
+	*       list for that media stream to Completed.
+	*    
+	*    *  The agent MUST continue to respond to any checks it may still
+	*       receive for that media stream, and MUST perform triggered
+	*       checks if required by the processing of Section 7.2.
+	*    
+	*    *  The agent MAY begin transmitting media for this media stream as
+	*       described in Section 11.1
+	*/
 
-    /* See if all components have nominated pair. If they do, then mark
-     * ICE processing as success, otherwise wait.
-     */
-    for (i=0; i<ice->comp_cnt; ++i) {
-	if (ice->comp[i].nominated_check == NULL)
-	    break;
-    }
-    if (i == ice->comp_cnt) {
-	/* All components have nominated pair */
-	on_ice_complete(ice, PJ_SUCCESS);
-	return PJ_TRUE;
-    }
+	/* See if all components have nominated pair. If they do, then mark
+	* ICE processing as success, otherwise wait.
+	*/
+	for (i=0; i<ice->comp_cnt; ++i) {
+		if (ice->comp[i].nominated_check == NULL)
+			break;
+	}
+	if (i == ice->comp_cnt) {
+		/* All components have nominated pair */
+		on_ice_complete(ice, PJ_SUCCESS);
+		return PJ_TRUE;
+	}
 
-    /* Note: this is the stuffs that we don't do in 7.1.2.2.2, since our
-     *       ICE session only supports one media stream for now:
-     * 
-     * 7.1.2.2.2.  Updating Pair States
-     *
-     * 2.  If there is a pair in the valid list for every component of this
-     *     media stream (where this is the actual number of components being
-     *     used, in cases where the number of components signaled in the SDP
-     *     differs from offerer to answerer), the success of this check may
-     *     unfreeze checks for other media streams. 
-     */
+	/* Note: this is the stuffs that we don't do in 7.1.2.2.2, since our
+	*       ICE session only supports one media stream for now:
+	* 
+	* 7.1.2.2.2.  Updating Pair States
+	*
+	* 2.  If there is a pair in the valid list for every component of this
+	*     media stream (where this is the actual number of components being
+	*     used, in cases where the number of components signaled in the SDP
+	*     differs from offerer to answerer), the success of this check may
+	*     unfreeze checks for other media streams. 
+	*/
 
-    /* 7.1.2.3.  Check List and Timer State Updates
-     * Regardless of whether the check was successful or failed, the
-     * completion of the transaction may require updating of check list and
-     * timer states.
-     * 
-     * If all of the pairs in the check list are now either in the Failed or
-     * Succeeded state, and there is not a pair in the valid list for each
-     * component of the media stream, the state of the check list is set to
-     * Failed.  
-     */
+	/* 7.1.2.3.  Check List and Timer State Updates
+	* Regardless of whether the check was successful or failed, the
+	* completion of the transaction may require updating of check list and
+	* timer states.
+	* 
+	* If all of the pairs in the check list are now either in the Failed or
+	* Succeeded state, and there is not a pair in the valid list for each
+	* component of the media stream, the state of the check list is set to
+	* Failed.  
+	*/
 
-    /* 
-     * See if all checks in the checklist have completed. If we do,
-     * then mark ICE processing as failed.
-     */
-    for (i=0; i<ice->clist.count; ++i) {
-	pj_ice_sess_check *c = &ice->clist.checks[i];
-	if (c->state < PJ_ICE_SESS_CHECK_STATE_SUCCEEDED) {
-	    break;
+	/* 
+	* See if all checks in the checklist have completed. If we do,
+	* then mark ICE processing as failed.
+	*/
+	for (i=0; i<ice->clist.count; ++i) {
+		pj_ice_sess_check *c = &ice->clist.checks[i];
+		if (c->state < PJ_ICE_SESS_CHECK_STATE_SUCCEEDED) {
+			break;
+		}
 	}
-    }
 
-    if (i == ice->clist.count) {
-	/* All checks have completed, but we don't have nominated pair.
-	 * If agent's role is controlled, check if all components have
-	 * valid pair. If it does, this means the controlled agent has
-	 * finished the check list and it's waiting for controlling
-	 * agent to send checks with USE-CANDIDATE flag set.
-	 */
-	if (ice->role == PJ_ICE_SESS_ROLE_CONTROLLED) {
-	    for (i=0; i < ice->comp_cnt; ++i) {
-		if (ice->comp[i].valid_check == NULL)
-		    break;
-	    }
+	if (i == ice->clist.count) {
+		/* All checks have completed, but we don't have nominated pair.
+		* If agent's role is controlled, check if all components have
+		* valid pair. If it does, this means the controlled agent has
+		* finished the check list and it's waiting for controlling
+		* agent to send checks with USE-CANDIDATE flag set.
+		*/
+		if (ice->role == PJ_ICE_SESS_ROLE_CONTROLLED) {
+			for (i=0; i < ice->comp_cnt; ++i) {
+				if (ice->comp[i].valid_check == NULL)
+					break;
+			}
 
-	    if (i < ice->comp_cnt) {
-		/* This component ID doesn't have valid pair.
-		 * Mark ICE as failed. 
-		 */
-		on_ice_complete(ice, PJNATH_EICEFAILED);
-		return PJ_TRUE;
-	    } else {
-		/* All components have a valid pair.
-		 * We should wait until we receive nominated checks.
-		 */
-		if (ice->timer.id == TIMER_NONE &&
-		    ice->opt.controlled_agent_want_nom_timeout >= 0) 
-		{
-		    pj_time_val delay;
+			if (i < ice->comp_cnt) {
+				/* This component ID doesn't have valid pair.
+				* Mark ICE as failed. 
+				*/
+				on_ice_complete(ice, PJNATH_EICEFAILED);
+				return PJ_TRUE;
+			} else {
+				/* All components have a valid pair.
+				* We should wait until we receive nominated checks.
+				*/
+				if (ice->timer.id == TIMER_NONE &&
+					ice->opt.controlled_agent_want_nom_timeout >= 0) 
+				{
+					pj_time_val delay;
 
-		    delay.sec = 0;
-		    delay.msec = ice->opt.controlled_agent_want_nom_timeout;
-		    pj_time_val_normalize(&delay);
+					delay.sec = 0;
+					delay.msec = ice->opt.controlled_agent_want_nom_timeout;
+					pj_time_val_normalize(&delay);
 
-		    ice->timer.id = TIMER_CONTROLLED_WAIT_NOM;
-		    pj_timer_heap_schedule(ice->stun_cfg.timer_heap, 
-					   &ice->timer,
-					   &delay);
+					ice->timer.id = TIMER_CONTROLLED_WAIT_NOM;
+					pj_timer_heap_schedule(ice->stun_cfg.timer_heap, 
+						&ice->timer,
+						&delay);
 
-		    LOG5((ice->obj_name, 
-			  "All checks have completed. Controlled agent now "
-			  "waits for nomination from controlling agent "
-			  "(timeout=%d msec)",
-			  ice->opt.controlled_agent_want_nom_timeout));
-		}
-		return PJ_FALSE;
-	    }
+					LOG5((ice->obj_name, 
+						"All checks have completed. Controlled agent now "
+						"waits for nomination from controlling agent "
+						"(timeout=%d msec)",
+						ice->opt.controlled_agent_want_nom_timeout));
+				}
+				return PJ_FALSE;
+			}
 
-	    /* Unreached */
+			/* Unreached */
 
-	} else if (ice->is_nominating) {
-	    /* We are controlling agent and all checks have completed but
-	     * there's at least one component without nominated pair (or
-	     * more likely we don't have any nominated pairs at all).
-	     */
-	    on_ice_complete(ice, PJNATH_EICEFAILED);
-	    return PJ_TRUE;
+		} else if (ice->is_nominating) {
+			/* We are controlling agent and all checks have completed but
+			* there's at least one component without nominated pair (or
+			* more likely we don't have any nominated pairs at all).
+			*/
+			on_ice_complete(ice, PJNATH_EICEFAILED);
+			return PJ_TRUE;
 
-	} else {
-	    /* We are controlling agent and all checks have completed. If
-	     * we have valid list for every component, then move on to
-	     * sending nominated check, otherwise we have failed.
-	     */
-	    for (i=0; i<ice->comp_cnt; ++i) {
-		if (ice->comp[i].valid_check == NULL)
-		    break;
-	    }
+		} else {
+			/* We are controlling agent and all checks have completed. If
+			* we have valid list for every component, then move on to
+			* sending nominated check, otherwise we have failed.
+			*/
+			for (i=0; i<ice->comp_cnt; ++i) {
+				if (ice->comp[i].valid_check == NULL)
+					break;
+			}
 
-	    if (i < ice->comp_cnt) {
-		/* At least one component doesn't have a valid check. Mark
-		 * ICE as failed.
-		 */
-		on_ice_complete(ice, PJNATH_EICEFAILED);
-		return PJ_TRUE;
-	    }
+			if (i < ice->comp_cnt) {
+				/* At least one component doesn't have a valid check. Mark
+				* ICE as failed.
+				*/
+				on_ice_complete(ice, PJNATH_EICEFAILED);
+				return PJ_TRUE;
+			}
 
-	    /* Now it's time to send connectivity check with nomination 
-	     * flag set.
-	     */
-	    LOG4((ice->obj_name, 
-		  "All checks have completed, starting nominated checks now"));
-	    start_nominated_check(ice);
-	    return PJ_FALSE;
+			/* Now it's time to send connectivity check with nomination 
+			* flag set.
+			*/
+			LOG4((ice->obj_name, 
+				"All checks have completed, starting nominated checks now"));
+			start_nominated_check(ice);
+			return PJ_FALSE;
+		}
 	}
-    }
 
-    /* If this connectivity check has been successful, scan all components
-     * and see if they have a valid pair, if we are controlling and we haven't
-     * started our nominated check yet.
-     */
-    if (check->err_code == PJ_SUCCESS && 
-	ice->role==PJ_ICE_SESS_ROLE_CONTROLLING &&
-	!ice->is_nominating &&
-	ice->timer.id == TIMER_NONE) 
-    {
-	pj_time_val delay;
+	/* If this connectivity check has been successful, scan all components
+	* and see if they have a valid pair, if we are controlling and we haven't
+	* started our nominated check yet.
+	*/
+	if (check->err_code == PJ_SUCCESS && 
+		ice->role==PJ_ICE_SESS_ROLE_CONTROLLING &&
+		!ice->is_nominating &&
+		ice->timer.id == TIMER_NONE) 
+	{
+		pj_time_val delay;
 
-	for (i=0; i<ice->comp_cnt; ++i) {
-	    if (ice->comp[i].valid_check == NULL)
-		break;
-	}
+		for (i=0; i<ice->comp_cnt; ++i) {
+			if (ice->comp[i].valid_check == NULL)
+				break;
+		}
 
-	if (i < ice->comp_cnt) {
-	    /* Some components still don't have valid pair, continue
-	     * processing.
-	     */
-	    return PJ_FALSE;
-	}
+		if (i < ice->comp_cnt) {
+			/* Some components still don't have valid pair, continue
+			* processing.
+			*/
+			return PJ_FALSE;
+		}
 
-	LOG4((ice->obj_name, 
-	      "Scheduling nominated check in %d ms",
-	      ice->opt.nominated_check_delay));
+		LOG4((ice->obj_name, 
+			"Scheduling nominated check in %d ms",
+			ice->opt.nominated_check_delay));
 
-	if (ice->timer.id != TIMER_NONE) {
-	    pj_timer_heap_cancel(ice->stun_cfg.timer_heap, &ice->timer);
-	    ice->timer.id = TIMER_NONE;
+		if (ice->timer.id != TIMER_NONE) {
+			pj_timer_heap_cancel(ice->stun_cfg.timer_heap, &ice->timer);
+			ice->timer.id = TIMER_NONE;
+		}
+
+		/* All components have valid pair. Let connectivity checks run for
+		* a little bit more time, then start our nominated check.
+		*/
+		delay.sec = 0;
+		delay.msec = ice->opt.nominated_check_delay;
+		pj_time_val_normalize(&delay);
+
+		ice->timer.id = TIMER_START_NOMINATED_CHECK;
+		pj_timer_heap_schedule(ice->stun_cfg.timer_heap, &ice->timer, &delay);
+		return PJ_FALSE;
 	}
 
-	/* All components have valid pair. Let connectivity checks run for
-	 * a little bit more time, then start our nominated check.
-	 */
-	delay.sec = 0;
-	delay.msec = ice->opt.nominated_check_delay;
-	pj_time_val_normalize(&delay);
-
-	ice->timer.id = TIMER_START_NOMINATED_CHECK;
-	pj_timer_heap_schedule(ice->stun_cfg.timer_heap, &ice->timer, &delay);
+	/* We still have checks to perform */
 	return PJ_FALSE;
-    }
-
-    /* We still have checks to perform */
-    return PJ_FALSE;
 }
 
 
 /* Create checklist by pairing local candidates with remote candidates */
 PJ_DEF(pj_status_t) pj_ice_sess_create_check_list(
-			      pj_ice_sess *ice,
-			      const pj_str_t *rem_ufrag,
-			      const pj_str_t *rem_passwd,
-			      unsigned rcand_cnt,
-			      const pj_ice_sess_cand rcand[])
+	pj_ice_sess *ice,
+	const pj_str_t *rem_ufrag,
+	const pj_str_t *rem_passwd,
+	unsigned rcand_cnt,
+	const pj_ice_sess_cand rcand[])
 {
-    pj_ice_sess_checklist *clist;
-    char buf[128];
-    pj_str_t username;
-    timer_data *td;
-    unsigned i, j;
-    unsigned highest_comp = 0;
-    pj_status_t status;
+	pj_ice_sess_checklist *clist;
+	char buf[128];
+	pj_str_t username;
+	timer_data *td;
+	unsigned i, j;
+	unsigned highest_comp = 0;
+	pj_status_t status;
 
-    PJ_ASSERT_RETURN(ice && rem_ufrag && rem_passwd && rcand_cnt && rcand,
-		     PJ_EINVAL);
-    PJ_ASSERT_RETURN(rcand_cnt + ice->rcand_cnt <= PJ_ICE_MAX_CAND, 
-		     PJ_ETOOMANY);
+	PJ_ASSERT_RETURN(ice && rem_ufrag && rem_passwd && rcand_cnt && rcand,
+		PJ_EINVAL);
+	PJ_ASSERT_RETURN(rcand_cnt + ice->rcand_cnt <= PJ_ICE_MAX_CAND, 
+		PJ_ETOOMANY);
 
-    pj_mutex_lock(ice->mutex);
+	pj_mutex_lock(ice->mutex);
 
-    /* Save credentials */
-    username.ptr = buf;
+	/* Save credentials */
+	username.ptr = buf;
 
-    pj_strcpy(&username, rem_ufrag);
-    pj_strcat2(&username, ":");
-    pj_strcat(&username, &ice->rx_ufrag);
+	pj_strcpy(&username, rem_ufrag);
+	if(!ice->opt.is_webrtc){
+		pj_strcat2(&username, ":");
+	}
+	pj_strcat(&username, &ice->rx_ufrag);
 
-    pj_strdup(ice->pool, &ice->tx_uname, &username);
-    pj_strdup(ice->pool, &ice->tx_ufrag, rem_ufrag);
-    pj_strdup(ice->pool, &ice->tx_pass, rem_passwd);
+	pj_strdup(ice->pool, &ice->tx_uname, &username);
+	pj_strdup(ice->pool, &ice->tx_ufrag, rem_ufrag);
+	pj_strdup(ice->pool, &ice->tx_pass, rem_passwd);
 
-    pj_strcpy(&username, &ice->rx_ufrag);
-    pj_strcat2(&username, ":");
-    pj_strcat(&username, rem_ufrag);
+	pj_strcpy(&username, &ice->rx_ufrag);
+	if(!ice->opt.is_webrtc){
+		pj_strcat2(&username, ":");
+	}
+	pj_strcat(&username, rem_ufrag);
 
-    pj_strdup(ice->pool, &ice->rx_uname, &username);
+	pj_strdup(ice->pool, &ice->rx_uname, &username);
 
 
-    /* Save remote candidates */
-    ice->rcand_cnt = 0;
-    for (i=0; i<rcand_cnt; ++i) {
-	pj_ice_sess_cand *cn = &ice->rcand[ice->rcand_cnt];
+	/* Save remote candidates */
+	ice->rcand_cnt = 0;
+	for (i=0; i<rcand_cnt; ++i) {
+		pj_ice_sess_cand *cn = &ice->rcand[ice->rcand_cnt];
 
-	/* Ignore candidate which has no matching component ID */
-	if (rcand[i].comp_id==0 || rcand[i].comp_id > ice->comp_cnt) {
-	    continue;
+		/* Ignore candidate which has no matching component ID */
+		if (rcand[i].comp_id==0 || rcand[i].comp_id > ice->comp_cnt) {
+			continue;
+		}
+
+		if (rcand[i].comp_id > highest_comp)
+			highest_comp = rcand[i].comp_id;
+
+		pj_memcpy(cn, &rcand[i], sizeof(pj_ice_sess_cand));
+		pj_strdup(ice->pool, &cn->foundation, &rcand[i].foundation);
+		ice->rcand_cnt++;
 	}
 
-	if (rcand[i].comp_id > highest_comp)
-	    highest_comp = rcand[i].comp_id;
+	/* Generate checklist */
+	clist = &ice->clist;
+	for (i=0; i<ice->lcand_cnt; ++i) {
+		for (j=0; j<ice->rcand_cnt; ++j) {
 
-	pj_memcpy(cn, &rcand[i], sizeof(pj_ice_sess_cand));
-	pj_strdup(ice->pool, &cn->foundation, &rcand[i].foundation);
-	ice->rcand_cnt++;
-    }
+			pj_ice_sess_cand *lcand = &ice->lcand[i];
+			pj_ice_sess_cand *rcand = &ice->rcand[j];
+			pj_ice_sess_check *chk = &clist->checks[clist->count];
 
-    /* Generate checklist */
-    clist = &ice->clist;
-    for (i=0; i<ice->lcand_cnt; ++i) {
-	for (j=0; j<ice->rcand_cnt; ++j) {
+			if (clist->count >= PJ_ICE_MAX_CHECKS) {
+				pj_mutex_unlock(ice->mutex);
+				return PJ_ETOOMANY;
+			} 
 
-	    pj_ice_sess_cand *lcand = &ice->lcand[i];
-	    pj_ice_sess_cand *rcand = &ice->rcand[j];
-	    pj_ice_sess_check *chk = &clist->checks[clist->count];
+			/* A local candidate is paired with a remote candidate if
+			* and only if the two candidates have the same component ID 
+			* and have the same IP address version. 
+			*/
+			if ((lcand->comp_id != rcand->comp_id) ||
+				(lcand->addr.addr.sa_family != rcand->addr.addr.sa_family))
+			{
+				continue;
+			}
 
-	    if (clist->count >= PJ_ICE_MAX_CHECKS) {
-		pj_mutex_unlock(ice->mutex);
-		return PJ_ETOOMANY;
-	    } 
 
-	    /* A local candidate is paired with a remote candidate if
-	     * and only if the two candidates have the same component ID 
-	     * and have the same IP address version. 
-	     */
-	    if ((lcand->comp_id != rcand->comp_id) ||
-		(lcand->addr.addr.sa_family != rcand->addr.addr.sa_family))
-	    {
-		continue;
-	    }
+			chk->lcand = lcand;
+			chk->rcand = rcand;
+			chk->state = PJ_ICE_SESS_CHECK_STATE_FROZEN;
 
+			chk->prio = CALC_CHECK_PRIO(ice, lcand, rcand);
 
-	    chk->lcand = lcand;
-	    chk->rcand = rcand;
-	    chk->state = PJ_ICE_SESS_CHECK_STATE_FROZEN;
+			clist->count++;
+		}
+	}
 
-	    chk->prio = CALC_CHECK_PRIO(ice, lcand, rcand);
+	/* Sort checklist based on priority */
+	sort_checklist(ice, clist);
 
-	    clist->count++;
+	/* Prune the checklist */
+	status = prune_checklist(ice, clist);
+	if (status != PJ_SUCCESS) {
+		pj_mutex_unlock(ice->mutex);
+		return status;
 	}
-    }
 
-    /* Sort checklist based on priority */
-    sort_checklist(ice, clist);
+	/* Disable our components which don't have matching component */
+	for (i=highest_comp; i<ice->comp_cnt; ++i) {
+		if (ice->comp[i].stun_sess) {
+			pj_stun_session_destroy(ice->comp[i].stun_sess);
+			pj_bzero(&ice->comp[i], sizeof(ice->comp[i]));
+		}
+	}
+	ice->comp_cnt = highest_comp;
 
-    /* Prune the checklist */
-    status = prune_checklist(ice, clist);
-    if (status != PJ_SUCCESS) {
-	pj_mutex_unlock(ice->mutex);
-	return status;
-    }
+	// copy username for chrome authentication
+	if(ice->opt.is_webrtc){
+		struct pj_stun_auth_cred auth_cred;
+		pj_bzero(&auth_cred, sizeof(auth_cred));
+		auth_cred.type = PJ_STUN_AUTH_CRED_WEBRTC;
+		pj_strdup(ice->pool, &auth_cred.data.webrtc_cred.rx_username, &ice->rx_uname);
+		pj_strdup(ice->pool, &auth_cred.data.webrtc_cred.tx_username, &ice->tx_uname);
 
-    /* Disable our components which don't have matching component */
-    for (i=highest_comp; i<ice->comp_cnt; ++i) {
-	if (ice->comp[i].stun_sess) {
-	    pj_stun_session_destroy(ice->comp[i].stun_sess);
-	    pj_bzero(&ice->comp[i], sizeof(ice->comp[i]));
+		for(i = 0; i < ice->comp_cnt ; ++i){
+			pj_stun_session_set_credential(ice->comp[i].stun_sess,
+				PJ_STUN_AUTH_WEBRTC,
+				&auth_cred);
+		}
 	}
-    }
-    ice->comp_cnt = highest_comp;
 
-    /* Init timer entry in the checklist. Initially the timer ID is FALSE
-     * because timer is not running.
-     */
-    clist->timer.id = PJ_FALSE;
-    td = PJ_POOL_ZALLOC_T(ice->pool, timer_data);
-    td->ice = ice;
-    td->clist = clist;
-    clist->timer.user_data = (void*)td;
-    clist->timer.cb = &periodic_timer;
+	/* Init timer entry in the checklist. Initially the timer ID is FALSE
+	* because timer is not running.
+	*/
+	clist->timer.id = PJ_FALSE;
+	td = PJ_POOL_ZALLOC_T(ice->pool, timer_data);
+	td->ice = ice;
+	td->clist = clist;
+	clist->timer.user_data = (void*)td;
+	clist->timer.cb = &periodic_timer;
 
 
-    /* Log checklist */
-    dump_checklist("Checklist created:", ice, clist);
+	/* Log checklist */
+	dump_checklist("Checklist created:", ice, clist);
 
-    pj_mutex_unlock(ice->mutex);
+	pj_mutex_unlock(ice->mutex);
 
-    return PJ_SUCCESS;
+	return PJ_SUCCESS;
 }
 
 /* Perform check on the specified candidate pair. */
 static pj_status_t perform_check(pj_ice_sess *ice, 
-				 pj_ice_sess_checklist *clist,
-				 unsigned check_id,
-				 pj_bool_t nominate)
+								 pj_ice_sess_checklist *clist,
+								 unsigned check_id,
+								 pj_bool_t nominate)
 {
-    pj_ice_sess_comp *comp;
-    pj_ice_msg_data *msg_data;
-    pj_ice_sess_check *check;
-    const pj_ice_sess_cand *lcand;
-    const pj_ice_sess_cand *rcand;
-    pj_uint32_t prio;
-    pj_status_t status;
+	pj_ice_sess_comp *comp;
+	pj_ice_msg_data *msg_data;
+	pj_ice_sess_check *check;
+	const pj_ice_sess_cand *lcand;
+	const pj_ice_sess_cand *rcand;
+	pj_uint32_t prio;
+	pj_status_t status;
 
-    check = &clist->checks[check_id];
-    lcand = check->lcand;
-    rcand = check->rcand;
-    comp = find_comp(ice, lcand->comp_id);
+	check = &clist->checks[check_id];
+	lcand = check->lcand;
+	rcand = check->rcand;
+	comp = find_comp(ice, lcand->comp_id);
 
-    LOG5((ice->obj_name, 
-	 "Sending connectivity check for check %s", 
-	 dump_check(ice->tmp.txt, sizeof(ice->tmp.txt), clist, check)));
-    pj_log_push_indent();
+	LOG5((ice->obj_name, 
+		"Sending connectivity check for check %s", 
+		dump_check(ice->tmp.txt, sizeof(ice->tmp.txt), clist, check)));
+	pj_log_push_indent();
 
-    /* Create request */
-    status = pj_stun_session_create_req(comp->stun_sess, 
-					PJ_STUN_BINDING_REQUEST, PJ_STUN_MAGIC,
-					NULL, &check->tdata);
-    if (status != PJ_SUCCESS) {
-	pjnath_perror(ice->obj_name, "Error creating STUN request", status);
-	pj_log_pop_indent();
-	return status;
-    }
+	/* Create request */
+	status = pj_stun_session_create_req(comp->stun_sess, 
+		PJ_STUN_BINDING_REQUEST, PJ_STUN_MAGIC,
+		NULL, &check->tdata);
+	if (status != PJ_SUCCESS) {
+		pjnath_perror(ice->obj_name, "Error creating STUN request", status);
+		pj_log_pop_indent();
+		return status;
+	}
 
-    /* Attach data to be retrieved later when STUN request transaction
-     * completes and on_stun_request_complete() callback is called.
-     */
-    msg_data = PJ_POOL_ZALLOC_T(check->tdata->pool, pj_ice_msg_data);
-    msg_data->transport_id = lcand->transport_id;
-    msg_data->has_req_data = PJ_TRUE;
-    msg_data->data.req.ice = ice;
-    msg_data->data.req.clist = clist;
-    msg_data->data.req.ckid = check_id;
+	/* Attach data to be retrieved later when STUN request transaction
+	* completes and on_stun_request_complete() callback is called.
+	*/
+	msg_data = PJ_POOL_ZALLOC_T(check->tdata->pool, pj_ice_msg_data);
+	msg_data->transport_id = lcand->transport_id;
+	msg_data->has_req_data = PJ_TRUE;
+	msg_data->data.req.ice = ice;
+	msg_data->data.req.clist = clist;
+	msg_data->data.req.ckid = check_id;
 
-    /* Add PRIORITY */
+	/* Add PRIORITY */
 #if PJNATH_ICE_PRIO_STD
-    prio = CALC_CAND_PRIO(ice, PJ_ICE_CAND_TYPE_PRFLX, 65535, 
-			  lcand->comp_id);
+	prio = CALC_CAND_PRIO(ice, PJ_ICE_CAND_TYPE_PRFLX, 65535, 
+		lcand->comp_id);
 #else
-    prio = CALC_CAND_PRIO(ice, PJ_ICE_CAND_TYPE_PRFLX, 0, 
-			  lcand->comp_id);
+	prio = CALC_CAND_PRIO(ice, PJ_ICE_CAND_TYPE_PRFLX, 0, 
+		lcand->comp_id);
 #endif
-    pj_stun_msg_add_uint_attr(check->tdata->pool, check->tdata->msg, 
-			      PJ_STUN_ATTR_PRIORITY, prio);
+	pj_stun_msg_add_uint_attr(check->tdata->pool, check->tdata->msg, 
+		PJ_STUN_ATTR_PRIORITY, prio);
 
-    /* Add USE-CANDIDATE and set this check to nominated.
-     * Also add ICE-CONTROLLING or ICE-CONTROLLED
-     */
-    if (ice->role == PJ_ICE_SESS_ROLE_CONTROLLING) {
-	if (nominate) {
-	    pj_stun_msg_add_empty_attr(check->tdata->pool, check->tdata->msg,
-				       PJ_STUN_ATTR_USE_CANDIDATE);
-	    check->nominated = PJ_TRUE;
+	/* Add USE-CANDIDATE and set this check to nominated.
+	* Also add ICE-CONTROLLING or ICE-CONTROLLED
+	*/
+	if (ice->role == PJ_ICE_SESS_ROLE_CONTROLLING) {
+		if (nominate) {
+			pj_stun_msg_add_empty_attr(check->tdata->pool, check->tdata->msg,
+				PJ_STUN_ATTR_USE_CANDIDATE);
+			check->nominated = PJ_TRUE;
+		}
+
+		pj_stun_msg_add_uint64_attr(check->tdata->pool, check->tdata->msg, 
+			PJ_STUN_ATTR_ICE_CONTROLLING,
+			&ice->tie_breaker);
+
+	} else {
+		pj_stun_msg_add_uint64_attr(check->tdata->pool, check->tdata->msg, 
+			PJ_STUN_ATTR_ICE_CONTROLLED,
+			&ice->tie_breaker);
 	}
 
-	pj_stun_msg_add_uint64_attr(check->tdata->pool, check->tdata->msg, 
-				    PJ_STUN_ATTR_ICE_CONTROLLING,
-				    &ice->tie_breaker);
 
-    } else {
-	pj_stun_msg_add_uint64_attr(check->tdata->pool, check->tdata->msg, 
-				    PJ_STUN_ATTR_ICE_CONTROLLED,
-				    &ice->tie_breaker);
-    }
+	/* Note that USERNAME and MESSAGE-INTEGRITY will be added by the 
+	* STUN session.
+	*/
 
+	/* Initiate STUN transaction to send the request */
+	status = pj_stun_session_send_msg(comp->stun_sess, msg_data, PJ_FALSE, 
+		PJ_TRUE, &rcand->addr, 
+		sizeof(pj_sockaddr_in), check->tdata);
+	if (status != PJ_SUCCESS) {
+		check->tdata = NULL;
+		pjnath_perror(ice->obj_name, "Error sending STUN request", status);
+		pj_log_pop_indent();
+		return status;
+	}
 
-    /* Note that USERNAME and MESSAGE-INTEGRITY will be added by the 
-     * STUN session.
-     */
-
-    /* Initiate STUN transaction to send the request */
-    status = pj_stun_session_send_msg(comp->stun_sess, msg_data, PJ_FALSE, 
-				      PJ_TRUE, &rcand->addr, 
-				      sizeof(pj_sockaddr_in), check->tdata);
-    if (status != PJ_SUCCESS) {
-	check->tdata = NULL;
-	pjnath_perror(ice->obj_name, "Error sending STUN request", status);
+	check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_IN_PROGRESS, 
+		PJ_SUCCESS);
 	pj_log_pop_indent();
-	return status;
-    }
-
-    check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_IN_PROGRESS, 
-	            PJ_SUCCESS);
-    pj_log_pop_indent();
-    return PJ_SUCCESS;
+	return PJ_SUCCESS;
 }
 
 
 /* Start periodic check for the specified checklist.
- * This callback is called by timer on every Ta (20msec by default)
- */
+* This callback is called by timer on every Ta (20msec by default)
+*/
 static pj_status_t start_periodic_check(pj_timer_heap_t *th, 
-					pj_timer_entry *te)
+										pj_timer_entry *te)
 {
-    timer_data *td;
-    pj_ice_sess *ice;
-    pj_ice_sess_checklist *clist;
-    unsigned i, start_count=0;
-    pj_status_t status;
+	timer_data *td;
+	pj_ice_sess *ice;
+	pj_ice_sess_checklist *clist;
+	unsigned i, start_count=0;
+	pj_status_t status;
 
-    td = (struct timer_data*) te->user_data;
-    ice = td->ice;
-    clist = td->clist;
+	td = (struct timer_data*) te->user_data;
+	ice = td->ice;
+	clist = td->clist;
 
-    if (ice->is_destroying)
-	return PJ_SUCCESS;
+	if (ice->is_destroying)
+		return PJ_SUCCESS;
 
-    pj_mutex_lock(ice->mutex);
+	pj_mutex_lock(ice->mutex);
 
-    if (ice->is_destroying) {
-	pj_mutex_unlock(ice->mutex);
-	return PJ_SUCCESS;
-    }
+	if (ice->is_destroying) {
+		pj_mutex_unlock(ice->mutex);
+		return PJ_SUCCESS;
+	}
 
-    /* Set timer ID to FALSE first */
-    te->id = PJ_FALSE;
+	/* Set timer ID to FALSE first */
+	te->id = PJ_FALSE;
 
-    /* Set checklist state to Running */
-    clist_set_state(ice, clist, PJ_ICE_SESS_CHECKLIST_ST_RUNNING);
+	/* Set checklist state to Running */
+	clist_set_state(ice, clist, PJ_ICE_SESS_CHECKLIST_ST_RUNNING);
 
-    LOG5((ice->obj_name, "Starting checklist periodic check"));
-    pj_log_push_indent();
+	LOG5((ice->obj_name, "Starting checklist periodic check"));
+	pj_log_push_indent();
 
-    /* Send STUN Binding request for check with highest priority on
-     * Waiting state.
-     */
-    for (i=0; i<clist->count; ++i) {
-	pj_ice_sess_check *check = &clist->checks[i];
+	/* Send STUN Binding request for check with highest priority on
+	* Waiting state.
+	*/
+	for (i=0; i<clist->count; ++i) {
+		pj_ice_sess_check *check = &clist->checks[i];
 
-	if (check->state == PJ_ICE_SESS_CHECK_STATE_WAITING) {
-	    status = perform_check(ice, clist, i, ice->is_nominating);
-	    if (status != PJ_SUCCESS) {
-		pj_mutex_unlock(ice->mutex);
-		pj_log_pop_indent();
-		return status;
-	    }
+		if (check->state == PJ_ICE_SESS_CHECK_STATE_WAITING) {
+			status = perform_check(ice, clist, i, ice->is_nominating);
+			if (status != PJ_SUCCESS) {
+				pj_mutex_unlock(ice->mutex);
+				pj_log_pop_indent();
+				return status;
+			}
 
-	    ++start_count;
-	    break;
+			++start_count;
+			break;
+		}
 	}
-    }
 
-    /* If we don't have anything in Waiting state, perform check to
-     * highest priority pair that is in Frozen state.
-     */
-    if (start_count==0) {
-	for (i=0; i<clist->count; ++i) {
-	    pj_ice_sess_check *check = &clist->checks[i];
+	/* If we don't have anything in Waiting state, perform check to
+	* highest priority pair that is in Frozen state.
+	*/
+	if (start_count==0) {
+		for (i=0; i<clist->count; ++i) {
+			pj_ice_sess_check *check = &clist->checks[i];
 
-	    if (check->state == PJ_ICE_SESS_CHECK_STATE_FROZEN) {
-		status = perform_check(ice, clist, i, ice->is_nominating);
-		if (status != PJ_SUCCESS) {
-		    pj_mutex_unlock(ice->mutex);
-		    pj_log_pop_indent();
-		    return status;
+			if (check->state == PJ_ICE_SESS_CHECK_STATE_FROZEN) {
+				status = perform_check(ice, clist, i, ice->is_nominating);
+				if (status != PJ_SUCCESS) {
+					pj_mutex_unlock(ice->mutex);
+					pj_log_pop_indent();
+					return status;
+				}
+
+				++start_count;
+				break;
+			}
 		}
-
-		++start_count;
-		break;
-	    }
 	}
-    }
 
-    /* Cannot start check because there's no suitable candidate pair.
-     */
-    if (start_count!=0) {
-	/* Schedule for next timer */
-	pj_time_val timeout = {0, PJ_ICE_TA_VAL};
+	/* Cannot start check because there's no suitable candidate pair.
+	*/
+	if (start_count!=0) {
+		/* Schedule for next timer */
+		pj_time_val timeout = {0, PJ_ICE_TA_VAL};
 
-	te->id = PJ_TRUE;
-	pj_time_val_normalize(&timeout);
-	pj_timer_heap_schedule(th, te, &timeout);
-    }
+		te->id = PJ_TRUE;
+		pj_time_val_normalize(&timeout);
+		pj_timer_heap_schedule(th, te, &timeout);
+	}
 
-    pj_mutex_unlock(ice->mutex);
-    pj_log_pop_indent();
-    return PJ_SUCCESS;
+	pj_mutex_unlock(ice->mutex);
+	pj_log_pop_indent();
+	return PJ_SUCCESS;
 }
 
 
 /* Start sending connectivity check with USE-CANDIDATE */
 static void start_nominated_check(pj_ice_sess *ice)
 {
-    pj_time_val delay;
-    unsigned i;
-    pj_status_t status;
+	pj_time_val delay;
+	unsigned i;
+	pj_status_t status;
 
-    LOG4((ice->obj_name, "Starting nominated check.."));
-    pj_log_push_indent();
+	LOG4((ice->obj_name, "Starting nominated check.."));
+	pj_log_push_indent();
 
-    pj_assert(ice->is_nominating == PJ_FALSE);
+	pj_assert(ice->is_nominating == PJ_FALSE);
 
-    /* Stop our timer if it's active */
-    if (ice->timer.id == TIMER_START_NOMINATED_CHECK) {
-	pj_timer_heap_cancel(ice->stun_cfg.timer_heap, &ice->timer);
-	ice->timer.id = TIMER_NONE;
-    }
+	/* Stop our timer if it's active */
+	if (ice->timer.id == TIMER_START_NOMINATED_CHECK) {
+		pj_timer_heap_cancel(ice->stun_cfg.timer_heap, &ice->timer);
+		ice->timer.id = TIMER_NONE;
+	}
 
-    /* For each component, set the check state of valid check with
-     * highest priority to Waiting (it should have Success state now).
-     */
-    for (i=0; i<ice->comp_cnt; ++i) {
-	unsigned j;
-	const pj_ice_sess_check *vc = ice->comp[i].valid_check;
+	/* For each component, set the check state of valid check with
+	* highest priority to Waiting (it should have Success state now).
+	*/
+	for (i=0; i<ice->comp_cnt; ++i) {
+		unsigned j;
+		const pj_ice_sess_check *vc = ice->comp[i].valid_check;
 
-	pj_assert(ice->comp[i].nominated_check == NULL);
-	pj_assert(vc->err_code == PJ_SUCCESS);
+		pj_assert(ice->comp[i].nominated_check == NULL);
+		pj_assert(vc->err_code == PJ_SUCCESS);
 
-	for (j=0; j<ice->clist.count; ++j) {
-	    pj_ice_sess_check *c = &ice->clist.checks[j];
-	    if (c->lcand->transport_id == vc->lcand->transport_id &&
-		c->rcand == vc->rcand)
-	    {
-		pj_assert(c->err_code == PJ_SUCCESS);
-		c->state = PJ_ICE_SESS_CHECK_STATE_FROZEN;
-		check_set_state(ice, c, PJ_ICE_SESS_CHECK_STATE_WAITING, 
-			        PJ_SUCCESS);
-		break;
-	    }
+		for (j=0; j<ice->clist.count; ++j) {
+			pj_ice_sess_check *c = &ice->clist.checks[j];
+			if (c->lcand->transport_id == vc->lcand->transport_id &&
+				c->rcand == vc->rcand)
+			{
+				pj_assert(c->err_code == PJ_SUCCESS);
+				c->state = PJ_ICE_SESS_CHECK_STATE_FROZEN;
+				check_set_state(ice, c, PJ_ICE_SESS_CHECK_STATE_WAITING, 
+					PJ_SUCCESS);
+				break;
+			}
+		}
 	}
-    }
 
-    /* And (re)start the periodic check */
-    if (ice->clist.timer.id) {
-	pj_timer_heap_cancel(ice->stun_cfg.timer_heap, &ice->clist.timer);
-	ice->clist.timer.id = PJ_FALSE;
-    }
+	/* And (re)start the periodic check */
+	if (ice->clist.timer.id) {
+		pj_timer_heap_cancel(ice->stun_cfg.timer_heap, &ice->clist.timer);
+		ice->clist.timer.id = PJ_FALSE;
+	}
 
-    ice->clist.timer.id = PJ_TRUE;
-    delay.sec = delay.msec = 0;
-    status = pj_timer_heap_schedule(ice->stun_cfg.timer_heap, 
-				    &ice->clist.timer, &delay);
-    if (status != PJ_SUCCESS) {
-	ice->clist.timer.id = PJ_FALSE;
-    } else {
-	LOG5((ice->obj_name, "Periodic timer rescheduled.."));
-    }
+	ice->clist.timer.id = PJ_TRUE;
+	delay.sec = delay.msec = 0;
+	status = pj_timer_heap_schedule(ice->stun_cfg.timer_heap, 
+		&ice->clist.timer, &delay);
+	if (status != PJ_SUCCESS) {
+		ice->clist.timer.id = PJ_FALSE;
+	} else {
+		LOG5((ice->obj_name, "Periodic timer rescheduled.."));
+	}
 
-    ice->is_nominating = PJ_TRUE;
-    pj_log_pop_indent();
+	ice->is_nominating = PJ_TRUE;
+	pj_log_pop_indent();
 }
 
 /* Timer callback to perform periodic check */
 static void periodic_timer(pj_timer_heap_t *th, 
-			   pj_timer_entry *te)
+						   pj_timer_entry *te)
 {
-    start_periodic_check(th, te);
+	start_periodic_check(th, te);
 }
 
 
 /* Utility: find string in string array */
 const pj_str_t *find_str(const pj_str_t *strlist[], unsigned count,
-			 const pj_str_t *str)
+						 const pj_str_t *str)
 {
-    unsigned i;
-    for (i=0; i<count; ++i) {
-	if (pj_strcmp(strlist[i], str)==0)
-	    return strlist[i];
-    }
-    return NULL;
+	unsigned i;
+	for (i=0; i<count; ++i) {
+		if (pj_strcmp(strlist[i], str)==0)
+			return strlist[i];
+	}
+	return NULL;
 }
 
 
 /*
- * Start ICE periodic check. This function will return immediately, and
- * application will be notified about the connectivity check status in
- * #pj_ice_sess_cb callback.
- */
+* Start ICE periodic check. This function will return immediately, and
+* application will be notified about the connectivity check status in
+* #pj_ice_sess_cb callback.
+*/
 PJ_DEF(pj_status_t) pj_ice_sess_start_check(pj_ice_sess *ice)
 {
-    pj_ice_sess_checklist *clist;
-    const pj_ice_sess_cand *cand0;
-    const pj_str_t *flist[PJ_ICE_MAX_CAND]; // XXX
-    pj_ice_rx_check *rcheck;
-    unsigned i, flist_cnt = 0;
-    pj_time_val delay;
-    pj_status_t status;
+	pj_ice_sess_checklist *clist;
+	const pj_ice_sess_cand *cand0;
+	const pj_str_t *flist[PJ_ICE_MAX_CAND]; // XXX
+	pj_ice_rx_check *rcheck;
+	unsigned i, flist_cnt = 0;
+	pj_time_val delay;
+	pj_status_t status;
 
-    PJ_ASSERT_RETURN(ice, PJ_EINVAL);
+	PJ_ASSERT_RETURN(ice, PJ_EINVAL);
 
-    /* Checklist must have been created */
-    PJ_ASSERT_RETURN(ice->clist.count > 0, PJ_EINVALIDOP);
+	/* Checklist must have been created */
+	PJ_ASSERT_RETURN(ice->clist.count > 0, PJ_EINVALIDOP);
 
-    /* Lock session */
-    pj_mutex_lock(ice->mutex);
+	/* Lock session */
+	pj_mutex_lock(ice->mutex);
 
-    LOG4((ice->obj_name, "Starting ICE check.."));
-    pj_log_push_indent();
+	LOG4((ice->obj_name, "Starting ICE check.."));
+	pj_log_push_indent();
 
-    /* If we are using aggressive nomination, set the is_nominating state */
-    if (ice->opt.aggressive)
-	ice->is_nominating = PJ_TRUE;
+	/* If we are using aggressive nomination, set the is_nominating state */
+	if (ice->opt.aggressive)
+		ice->is_nominating = PJ_TRUE;
 
-    /* The agent examines the check list for the first media stream (a
-     * media stream is the first media stream when it is described by
-     * the first m-line in the SDP offer and answer).  For that media
-     * stream, it:
-     * 
-     * -  Groups together all of the pairs with the same foundation,
-     * 
-     * -  For each group, sets the state of the pair with the lowest
-     *    component ID to Waiting.  If there is more than one such pair,
-     *    the one with the highest priority is used.
-     */
+	/* The agent examines the check list for the first media stream (a
+	* media stream is the first media stream when it is described by
+	* the first m-line in the SDP offer and answer).  For that media
+	* stream, it:
+	* 
+	* -  Groups together all of the pairs with the same foundation,
+	* 
+	* -  For each group, sets the state of the pair with the lowest
+	*    component ID to Waiting.  If there is more than one such pair,
+	*    the one with the highest priority is used.
+	*/
 
-    clist = &ice->clist;
+	clist = &ice->clist;
 
-    /* Pickup the first pair for component 1. */
-    for (i=0; i<clist->count; ++i) {
-	if (clist->checks[i].lcand->comp_id == 1)
-	    break;
-    }
-    if (i == clist->count) {
-	pj_assert(!"Unable to find checklist for component 1");
-	pj_mutex_unlock(ice->mutex);
-	pj_log_pop_indent();
-	return PJNATH_EICEINCOMPID;
-    }
+	/* Pickup the first pair for component 1. */
+	for (i=0; i<clist->count; ++i) {
+		if (clist->checks[i].lcand->comp_id == 1)
+			break;
+	}
+	if (i == clist->count) {
+		pj_assert(!"Unable to find checklist for component 1");
+		pj_mutex_unlock(ice->mutex);
+		pj_log_pop_indent();
+		return PJNATH_EICEINCOMPID;
+	}
 
-    /* Set this check to WAITING only if state is frozen. It may be possible
-     * that this check has already been started by a trigger check
-     */
-    if (clist->checks[i].state == PJ_ICE_SESS_CHECK_STATE_FROZEN) {
-	check_set_state(ice, &clist->checks[i], 
+	/* Set this check to WAITING only if state is frozen. It may be possible
+	* that this check has already been started by a trigger check
+	*/
+	if (clist->checks[i].state == PJ_ICE_SESS_CHECK_STATE_FROZEN) {
+		check_set_state(ice, &clist->checks[i], 
 			PJ_ICE_SESS_CHECK_STATE_WAITING, PJ_SUCCESS);
-    }
+	}
 
-    cand0 = clist->checks[i].lcand;
-    flist[flist_cnt++] = &clist->checks[i].lcand->foundation;
+	cand0 = clist->checks[i].lcand;
+	flist[flist_cnt++] = &clist->checks[i].lcand->foundation;
 
-    /* Find all of the other pairs in that check list with the same
-     * component ID, but different foundations, and sets all of their
-     * states to Waiting as well.
-     */
-    for (++i; i<clist->count; ++i) {
-	const pj_ice_sess_cand *cand1;
+	/* Find all of the other pairs in that check list with the same
+	* component ID, but different foundations, and sets all of their
+	* states to Waiting as well.
+	*/
+	for (++i; i<clist->count; ++i) {
+		const pj_ice_sess_cand *cand1;
 
-	cand1 = clist->checks[i].lcand;
+		cand1 = clist->checks[i].lcand;
 
-	if (cand1->comp_id==cand0->comp_id &&
-	    find_str(flist, flist_cnt, &cand1->foundation)==NULL)
-	{
-	    if (clist->checks[i].state == PJ_ICE_SESS_CHECK_STATE_FROZEN) {
-		check_set_state(ice, &clist->checks[i], 
-				PJ_ICE_SESS_CHECK_STATE_WAITING, PJ_SUCCESS);
-	    }
-	    flist[flist_cnt++] = &cand1->foundation;
+		if (cand1->comp_id==cand0->comp_id &&
+			find_str(flist, flist_cnt, &cand1->foundation)==NULL)
+		{
+			if (clist->checks[i].state == PJ_ICE_SESS_CHECK_STATE_FROZEN) {
+				check_set_state(ice, &clist->checks[i], 
+					PJ_ICE_SESS_CHECK_STATE_WAITING, PJ_SUCCESS);
+			}
+			flist[flist_cnt++] = &cand1->foundation;
+		}
 	}
-    }
 
-    /* First, perform all pending triggered checks, simultaneously. */
-    rcheck = ice->early_check.next;
-    while (rcheck != &ice->early_check) {
-	LOG4((ice->obj_name, 
-	      "Performing delayed triggerred check for component %d",
-	      rcheck->comp_id));
-	pj_log_push_indent();
-	handle_incoming_check(ice, rcheck);
-	rcheck = rcheck->next;
-	pj_log_pop_indent();
-    }
-    pj_list_init(&ice->early_check);
+	/* First, perform all pending triggered checks, simultaneously. */
+	rcheck = ice->early_check.next;
+	while (rcheck != &ice->early_check) {
+		LOG4((ice->obj_name, 
+			"Performing delayed triggerred check for component %d",
+			rcheck->comp_id));
+		pj_log_push_indent();
+		handle_incoming_check(ice, rcheck);
+		rcheck = rcheck->next;
+		pj_log_pop_indent();
+	}
+	pj_list_init(&ice->early_check);
 
-    /* Start periodic check */
-    /* We could start it immediately like below, but lets schedule timer 
-     * instead to reduce stack usage:
-     * return start_periodic_check(ice->stun_cfg.timer_heap, &clist->timer);
-     */
-    clist->timer.id = PJ_TRUE;
-    delay.sec = delay.msec = 0;
-    status = pj_timer_heap_schedule(ice->stun_cfg.timer_heap, 
-				    &clist->timer, &delay);
-    if (status != PJ_SUCCESS) {
-	clist->timer.id = PJ_FALSE;
-    }
+	/* Start periodic check */
+	/* We could start it immediately like below, but lets schedule timer 
+	* instead to reduce stack usage:
+	* return start_periodic_check(ice->stun_cfg.timer_heap, &clist->timer);
+	*/
+	clist->timer.id = PJ_TRUE;
+	delay.sec = delay.msec = 0;
+	status = pj_timer_heap_schedule(ice->stun_cfg.timer_heap, 
+		&clist->timer, &delay);
+	if (status != PJ_SUCCESS) {
+		clist->timer.id = PJ_FALSE;
+	}
 
-    pj_mutex_unlock(ice->mutex);
-    pj_log_pop_indent();
-    return status;
+	pj_mutex_unlock(ice->mutex);
+	pj_log_pop_indent();
+	return status;
 }
 
 
 //////////////////////////////////////////////////////////////////////////////
 
 /* Callback called by STUN session to send the STUN message.
- * STUN session also doesn't have a transport, remember?!
- */
+* STUN session also doesn't have a transport, remember?!
+*/
 static pj_status_t on_stun_send_msg(pj_stun_session *sess,
-				    void *token,
-				    const void *pkt,
-				    pj_size_t pkt_size,
-				    const pj_sockaddr_t *dst_addr,
-				    unsigned addr_len)
+									void *token,
+									const void *pkt,
+									pj_size_t pkt_size,
+									const pj_sockaddr_t *dst_addr,
+									unsigned addr_len)
 {
-    stun_data *sd = (stun_data*) pj_stun_session_get_user_data(sess);
-    pj_ice_sess *ice = sd->ice;
-    pj_ice_msg_data *msg_data = (pj_ice_msg_data*) token;
-    
-    return (*ice->cb.on_tx_pkt)(ice, sd->comp_id, msg_data->transport_id,
-				pkt, pkt_size, dst_addr, addr_len);
+	stun_data *sd = (stun_data*) pj_stun_session_get_user_data(sess);
+	pj_ice_sess *ice = sd->ice;
+	pj_ice_msg_data *msg_data = (pj_ice_msg_data*) token;
+
+	return (*ice->cb.on_tx_pkt)(ice, sd->comp_id, msg_data->transport_id,
+		pkt, pkt_size, dst_addr, addr_len);
 }
 
 
 /* This callback is called when outgoing STUN request completed */
 static void on_stun_request_complete(pj_stun_session *stun_sess,
-				     pj_status_t status,
-				     void *token,
-				     pj_stun_tx_data *tdata,
-				     const pj_stun_msg *response,
-				     const pj_sockaddr_t *src_addr,
-				     unsigned src_addr_len)
+									 pj_status_t status,
+									 void *token,
+									 pj_stun_tx_data *tdata,
+									 const pj_stun_msg *response,
+									 const pj_sockaddr_t *src_addr,
+									 unsigned src_addr_len)
 {
-    pj_ice_msg_data *msg_data = (pj_ice_msg_data*) token;
-    pj_ice_sess *ice;
-    pj_ice_sess_check *check, *new_check;
-    pj_ice_sess_cand *lcand;
-    pj_ice_sess_checklist *clist;
-    pj_stun_xor_mapped_addr_attr *xaddr;
-    unsigned i;
+	pj_ice_msg_data *msg_data = (pj_ice_msg_data*) token;
+	pj_ice_sess *ice;
+	pj_ice_sess_check *check, *new_check;
+	pj_ice_sess_cand *lcand;
+	pj_ice_sess_checklist *clist;
+	pj_stun_xor_mapped_addr_attr *xaddr;
+	pj_stun_mapped_addr_attr *addr = 0;
+	unsigned i;
 
-    PJ_UNUSED_ARG(stun_sess);
-    PJ_UNUSED_ARG(src_addr_len);
+	PJ_UNUSED_ARG(stun_sess);
+	PJ_UNUSED_ARG(src_addr_len);
 
-    pj_assert(msg_data->has_req_data);
+	pj_assert(msg_data->has_req_data);
 
-    ice = msg_data->data.req.ice;
-    clist = msg_data->data.req.clist;
-    check = &clist->checks[msg_data->data.req.ckid];
-    
+	ice = msg_data->data.req.ice;
+	clist = msg_data->data.req.clist;
+	check = &clist->checks[msg_data->data.req.ckid];
 
-    /* Mark STUN transaction as complete */
-    pj_assert(tdata == check->tdata);
-    check->tdata = NULL;
+	//FIXME: Find why WebRTC keepalive requests cause tdata mismatch
+	if(tdata != check->tdata){
+		return;
+	}
 
-    pj_mutex_lock(ice->mutex);
+	/* Mark STUN transaction as complete */
+	pj_assert(tdata == check->tdata);
+	check->tdata = NULL;
 
-    /* Init lcand to NULL. lcand will be found from the mapped address
-     * found in the response.
-     */
-    lcand = NULL;
+	pj_mutex_lock(ice->mutex);
 
-    if (status != PJ_SUCCESS) {
-	char errmsg[PJ_ERR_MSG_SIZE];
+	/* Init lcand to NULL. lcand will be found from the mapped address
+	* found in the response.
+	*/
+	lcand = NULL;
 
-	if (status==PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_ROLE_CONFLICT)) {
+	if (status != PJ_SUCCESS) {
+		char errmsg[PJ_ERR_MSG_SIZE];
 
-	    /* Role conclict response.
-	     *
-	     * 7.1.2.1.  Failure Cases:
-	     *
-	     * If the request had contained the ICE-CONTROLLED attribute, 
-	     * the agent MUST switch to the controlling role if it has not
-	     * already done so.  If the request had contained the 
-	     * ICE-CONTROLLING attribute, the agent MUST switch to the 
-	     * controlled role if it has not already done so.  Once it has
-	     * switched, the agent MUST immediately retry the request with
-	     * the ICE-CONTROLLING or ICE-CONTROLLED attribute reflecting 
-	     * its new role.
-	     */
-	    pj_ice_sess_role new_role = PJ_ICE_SESS_ROLE_UNKNOWN;
-	    pj_stun_msg *req = tdata->msg;
+		if (status==PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_ROLE_CONFLICT)) {
 
-	    if (pj_stun_msg_find_attr(req, PJ_STUN_ATTR_ICE_CONTROLLING, 0)) {
-		new_role = PJ_ICE_SESS_ROLE_CONTROLLED;
-	    } else if (pj_stun_msg_find_attr(req, PJ_STUN_ATTR_ICE_CONTROLLED, 
-					     0)) {
-		new_role = PJ_ICE_SESS_ROLE_CONTROLLING;
-	    } else {
-		pj_assert(!"We should have put CONTROLLING/CONTROLLED attr!");
-		new_role = PJ_ICE_SESS_ROLE_CONTROLLED;
-	    }
+			/* Role conclict response.
+			*
+			* 7.1.2.1.  Failure Cases:
+			*
+			* If the request had contained the ICE-CONTROLLED attribute, 
+			* the agent MUST switch to the controlling role if it has not
+			* already done so.  If the request had contained the 
+			* ICE-CONTROLLING attribute, the agent MUST switch to the 
+			* controlled role if it has not already done so.  Once it has
+			* switched, the agent MUST immediately retry the request with
+			* the ICE-CONTROLLING or ICE-CONTROLLED attribute reflecting 
+			* its new role.
+			*/
+			pj_ice_sess_role new_role = PJ_ICE_SESS_ROLE_UNKNOWN;
+			pj_stun_msg *req = tdata->msg;
 
-	    if (new_role != ice->role) {
-		LOG4((ice->obj_name, 
-		      "Changing role because of role conflict response"));
-		pj_ice_sess_change_role(ice, new_role);
-	    }
+			if (pj_stun_msg_find_attr(req, PJ_STUN_ATTR_ICE_CONTROLLING, 0)) {
+				new_role = PJ_ICE_SESS_ROLE_CONTROLLED;
+			} else if (pj_stun_msg_find_attr(req, PJ_STUN_ATTR_ICE_CONTROLLED, 
+				0)) {
+					new_role = PJ_ICE_SESS_ROLE_CONTROLLING;
+			} else {
+				pj_assert(!"We should have put CONTROLLING/CONTROLLED attr!");
+				new_role = PJ_ICE_SESS_ROLE_CONTROLLED;
+			}
 
-	    /* Resend request */
-	    LOG4((ice->obj_name, "Resending check because of role conflict"));
-	    pj_log_push_indent();
-	    check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_WAITING, 0);
-	    perform_check(ice, clist, msg_data->data.req.ckid, 
-			  check->nominated || ice->is_nominating);
-	    pj_log_pop_indent();
-	    pj_mutex_unlock(ice->mutex);
-	    return;
-	}
+			if (new_role != ice->role) {
+				LOG4((ice->obj_name, 
+					"Changing role because of role conflict response"));
+				pj_ice_sess_change_role(ice, new_role);
+			}
 
-	pj_strerror(status, errmsg, sizeof(errmsg));
-	LOG4((ice->obj_name, 
-	     "Check %s%s: connectivity check FAILED: %s",
-	     dump_check(ice->tmp.txt, sizeof(ice->tmp.txt), 
+			/* Resend request */
+			LOG4((ice->obj_name, "Resending check because of role conflict"));
+			pj_log_push_indent();
+			check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_WAITING, 0);
+			perform_check(ice, clist, msg_data->data.req.ckid, 
+				check->nominated || ice->is_nominating);
+			pj_log_pop_indent();
+			pj_mutex_unlock(ice->mutex);
+			return;
+		}
+
+		pj_strerror(status, errmsg, sizeof(errmsg));
+		LOG4((ice->obj_name, 
+			"Check %s%s: connectivity check FAILED: %s",
+			dump_check(ice->tmp.txt, sizeof(ice->tmp.txt), 
 			&ice->clist, check),
-	     (check->nominated ? " (nominated)" : " (not nominated)"),
-	     errmsg));
-	pj_log_push_indent();
-	check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_FAILED, status);
-	on_check_complete(ice, check);
-	pj_log_pop_indent();
-	pj_mutex_unlock(ice->mutex);
-	return;
-    }
+			(check->nominated ? " (nominated)" : " (not nominated)"),
+			errmsg));
+		pj_log_push_indent();
+		check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_FAILED, status);
+		on_check_complete(ice, check);
+		pj_log_pop_indent();
+		pj_mutex_unlock(ice->mutex);
+		return;
+	}
 
 
-    /* 7.1.2.1.  Failure Cases
-     *
-     * The agent MUST check that the source IP address and port of the
-     * response equals the destination IP address and port that the Binding
-     * Request was sent to, and that the destination IP address and port of
-     * the response match the source IP address and port that the Binding
-     * Request was sent from.
-     */
-    if (sockaddr_cmp(&check->rcand->addr, (const pj_sockaddr*)src_addr) != 0) {
-	status = PJNATH_EICEINSRCADDR;
-	LOG4((ice->obj_name, 
-	     "Check %s%s: connectivity check FAILED: source address mismatch",
-	     dump_check(ice->tmp.txt, sizeof(ice->tmp.txt), 
+	/* 7.1.2.1.  Failure Cases
+	*
+	* The agent MUST check that the source IP address and port of the
+	* response equals the destination IP address and port that the Binding
+	* Request was sent to, and that the destination IP address and port of
+	* the response match the source IP address and port that the Binding
+	* Request was sent from.
+	*/
+	if (sockaddr_cmp(&check->rcand->addr, (const pj_sockaddr*)src_addr) != 0) {
+		status = PJNATH_EICEINSRCADDR;
+		LOG4((ice->obj_name, 
+			"Check %s%s: connectivity check FAILED: source address mismatch",
+			dump_check(ice->tmp.txt, sizeof(ice->tmp.txt), 
 			&ice->clist, check),
-	     (check->nominated ? " (nominated)" : " (not nominated)")));
-	pj_log_push_indent();
-	check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_FAILED, status);
-	on_check_complete(ice, check);
-	pj_log_pop_indent();
-	pj_mutex_unlock(ice->mutex);
-	return;
-    }
+			(check->nominated ? " (nominated)" : " (not nominated)")));
+		pj_log_push_indent();
+		check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_FAILED, status);
+		on_check_complete(ice, check);
+		pj_log_pop_indent();
+		pj_mutex_unlock(ice->mutex);
+		return;
+	}
 
-    /* 7.1.2.2.  Success Cases
-     * 
-     * A check is considered to be a success if all of the following are
-     * true:
-     * 
-     * o  the STUN transaction generated a success response
-     * 
-     * o  the source IP address and port of the response equals the
-     *    destination IP address and port that the Binding Request was sent
-     *    to
-     * 
-     * o  the destination IP address and port of the response match the
-     *    source IP address and port that the Binding Request was sent from
-     */
+	/* 7.1.2.2.  Success Cases
+	* 
+	* A check is considered to be a success if all of the following are
+	* true:
+	* 
+	* o  the STUN transaction generated a success response
+	* 
+	* o  the source IP address and port of the response equals the
+	*    destination IP address and port that the Binding Request was sent
+	*    to
+	* 
+	* o  the destination IP address and port of the response match the
+	*    source IP address and port that the Binding Request was sent from
+	*/
 
 
-    LOG4((ice->obj_name, 
-	 "Check %s%s: connectivity check SUCCESS",
-	 dump_check(ice->tmp.txt, sizeof(ice->tmp.txt), 
-		    &ice->clist, check),
-	 (check->nominated ? " (nominated)" : " (not nominated)")));
+	LOG4((ice->obj_name, 
+		"Check %s%s: connectivity check SUCCESS",
+		dump_check(ice->tmp.txt, sizeof(ice->tmp.txt), 
+		&ice->clist, check),
+		(check->nominated ? " (nominated)" : " (not nominated)")));
 
-    /* Get the STUN XOR-MAPPED-ADDRESS attribute. */
-    xaddr = (pj_stun_xor_mapped_addr_attr*)
-	    pj_stun_msg_find_attr(response, PJ_STUN_ATTR_XOR_MAPPED_ADDR,0);
-    if (!xaddr) {
-	check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_FAILED, 
+	/* Get the STUN XOR-MAPPED-ADDRESS attribute. */
+	xaddr = (pj_stun_xor_mapped_addr_attr*)
+		pj_stun_msg_find_attr(response, PJ_STUN_ATTR_XOR_MAPPED_ADDR,0);
+	/* Chrome returns mapped address only */
+	if (!xaddr && pj_stun_session_get_auth_type(stun_sess) == PJ_STUN_AUTH_WEBRTC) {
+		addr = (pj_stun_mapped_addr_attr*) pj_stun_msg_find_attr(response, PJ_STUN_ATTR_MAPPED_ADDR, 0);
+	}
+
+	if (!xaddr && !addr) {
+		check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_FAILED, 
 			PJNATH_ESTUNNOMAPPEDADDR);
-	on_check_complete(ice, check);
-	pj_mutex_unlock(ice->mutex);
-	return;
-    }
+		on_check_complete(ice, check);
+		pj_mutex_unlock(ice->mutex);
+		return;
+	}
 
-    /* Find local candidate that matches the XOR-MAPPED-ADDRESS */
-    pj_assert(lcand == NULL);
-    for (i=0; i<ice->lcand_cnt; ++i) {
-	if (sockaddr_cmp(&xaddr->sockaddr, &ice->lcand[i].addr) == 0) {
-	    /* Match */
-	    lcand = &ice->lcand[i];
-	    break;
+	/* Find local candidate that matches the XOR-MAPPED-ADDRESS */
+	pj_assert(lcand == NULL);
+	for (i=0; i<ice->lcand_cnt; ++i) {
+		if ((xaddr && sockaddr_cmp(&xaddr->sockaddr, &ice->lcand[i].addr) == 0) || (addr && sockaddr_cmp(&addr->sockaddr, &ice->lcand[i].addr) == 0)) {
+			/* Match */
+			lcand = &ice->lcand[i];
+			break;
+		}
 	}
-    }
 
-    /* 7.1.2.2.1.  Discovering Peer Reflexive Candidates
-     * If the transport address returned in XOR-MAPPED-ADDRESS does not match
-     * any of the local candidates that the agent knows about, the mapped 
-     * address represents a new candidate - a peer reflexive candidate.
-     */
-    if (lcand == NULL) {
-	unsigned cand_id;
-	pj_str_t foundation;
+	/* 7.1.2.2.1.  Discovering Peer Reflexive Candidates
+	* If the transport address returned in XOR-MAPPED-ADDRESS does not match
+	* any of the local candidates that the agent knows about, the mapped 
+	* address represents a new candidate - a peer reflexive candidate.
+	*/
+	if (lcand == NULL) {
+		unsigned cand_id;
+		pj_str_t foundation;
 
-	pj_ice_calc_foundation(ice->pool, &foundation, PJ_ICE_CAND_TYPE_PRFLX,
-			       &check->lcand->base_addr);
+		pj_ice_calc_foundation(ice->pool, &foundation, PJ_ICE_CAND_TYPE_PRFLX,
+			&check->lcand->base_addr);
 
-	/* Still in 7.1.2.2.1.  Discovering Peer Reflexive Candidates
-	 * Its priority is set equal to the value of the PRIORITY attribute
-         * in the Binding Request.
-	 *
-	 * I think the priority calculated by add_cand() should be the same
-	 * as the one calculated in perform_check(), so there's no need to
-	 * get the priority from the PRIORITY attribute.
-	 */
+		/* Still in 7.1.2.2.1.  Discovering Peer Reflexive Candidates
+		* Its priority is set equal to the value of the PRIORITY attribute
+		* in the Binding Request.
+		*
+		* I think the priority calculated by add_cand() should be the same
+		* as the one calculated in perform_check(), so there's no need to
+		* get the priority from the PRIORITY attribute.
+		*/
 
-	/* Add new peer reflexive candidate */
-	status = pj_ice_sess_add_cand(ice, check->lcand->comp_id, 
-				      msg_data->transport_id,
-				      PJ_ICE_CAND_TYPE_PRFLX,
-				      65535, &foundation,
-				      &xaddr->sockaddr, 
-				      &check->lcand->base_addr, 
-				      &check->lcand->base_addr,
-				      sizeof(pj_sockaddr_in), &cand_id);
-	if (status != PJ_SUCCESS) {
-	    check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_FAILED, 
-			    status);
-	    on_check_complete(ice, check);
-	    pj_mutex_unlock(ice->mutex);
-	    return;
+		/* Add new peer reflexive candidate */
+		status = pj_ice_sess_add_cand(ice, check->lcand->comp_id, 
+			msg_data->transport_id,
+			PJ_ICE_CAND_TYPE_PRFLX,
+			65535, &foundation,
+			xaddr ? &xaddr->sockaddr : &addr->sockaddr, 
+			&check->lcand->base_addr, 
+			&check->lcand->base_addr,
+			sizeof(pj_sockaddr_in), &cand_id);
+		if (status != PJ_SUCCESS) {
+			check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_FAILED, 
+				status);
+			on_check_complete(ice, check);
+			pj_mutex_unlock(ice->mutex);
+			return;
+		}
+
+		/* Update local candidate */
+		lcand = &ice->lcand[cand_id];
+
 	}
 
-	/* Update local candidate */
-	lcand = &ice->lcand[cand_id];
+	/* 7.1.2.2.3.  Constructing a Valid Pair
+	* Next, the agent constructs a candidate pair whose local candidate
+	* equals the mapped address of the response, and whose remote candidate
+	* equals the destination address to which the request was sent.    
+	*/
 
-    }
+	/* Add pair to valid list, if it's not there, otherwise just update
+	* nominated flag
+	*/
+	for (i=0; i<ice->valid_list.count; ++i) {
+		if (ice->valid_list.checks[i].lcand == lcand &&
+			ice->valid_list.checks[i].rcand == check->rcand)
+			break;
+	}
 
-    /* 7.1.2.2.3.  Constructing a Valid Pair
-     * Next, the agent constructs a candidate pair whose local candidate
-     * equals the mapped address of the response, and whose remote candidate
-     * equals the destination address to which the request was sent.    
-     */
+	if (i==ice->valid_list.count) {
+		pj_assert(ice->valid_list.count < PJ_ICE_MAX_CHECKS);
+		new_check = &ice->valid_list.checks[ice->valid_list.count++];
+		new_check->lcand = lcand;
+		new_check->rcand = check->rcand;
+		new_check->prio = CALC_CHECK_PRIO(ice, lcand, check->rcand);
+		new_check->state = PJ_ICE_SESS_CHECK_STATE_SUCCEEDED;
+		new_check->nominated = check->nominated;
+		new_check->err_code = PJ_SUCCESS;
+	} else {
+		new_check = &ice->valid_list.checks[i];
+		ice->valid_list.checks[i].nominated = check->nominated;
+	}
 
-    /* Add pair to valid list, if it's not there, otherwise just update
-     * nominated flag
-     */
-    for (i=0; i<ice->valid_list.count; ++i) {
-	if (ice->valid_list.checks[i].lcand == lcand &&
-	    ice->valid_list.checks[i].rcand == check->rcand)
-	    break;
-    }
+	/* Update valid check and nominated check for the component */
+	update_comp_check(ice, new_check->lcand->comp_id, new_check);
 
-    if (i==ice->valid_list.count) {
-	pj_assert(ice->valid_list.count < PJ_ICE_MAX_CHECKS);
-	new_check = &ice->valid_list.checks[ice->valid_list.count++];
-	new_check->lcand = lcand;
-	new_check->rcand = check->rcand;
-	new_check->prio = CALC_CHECK_PRIO(ice, lcand, check->rcand);
-	new_check->state = PJ_ICE_SESS_CHECK_STATE_SUCCEEDED;
-	new_check->nominated = check->nominated;
-	new_check->err_code = PJ_SUCCESS;
-    } else {
-	new_check = &ice->valid_list.checks[i];
-	ice->valid_list.checks[i].nominated = check->nominated;
-    }
+	/* Sort valid_list (must do so after update_comp_check(), otherwise
+	* new_check will point to something else (#953)
+	*/
+	sort_checklist(ice, &ice->valid_list);
 
-    /* Update valid check and nominated check for the component */
-    update_comp_check(ice, new_check->lcand->comp_id, new_check);
+	/* 7.1.2.2.2.  Updating Pair States
+	* 
+	* The agent sets the state of the pair that generated the check to
+	* Succeeded.  The success of this check might also cause the state of
+	* other checks to change as well.
+	*/
+	check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_SUCCEEDED, 
+		PJ_SUCCESS);
 
-    /* Sort valid_list (must do so after update_comp_check(), otherwise
-     * new_check will point to something else (#953)
-     */
-    sort_checklist(ice, &ice->valid_list);
+	/* Perform 7.1.2.2.2.  Updating Pair States.
+	* This may terminate ICE processing.
+	*/
+	if (on_check_complete(ice, check)) {
+		/* ICE complete! */
+		pj_mutex_unlock(ice->mutex);
+		return;
+	}
 
-    /* 7.1.2.2.2.  Updating Pair States
-     * 
-     * The agent sets the state of the pair that generated the check to
-     * Succeeded.  The success of this check might also cause the state of
-     * other checks to change as well.
-     */
-    check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_SUCCEEDED, 
-		    PJ_SUCCESS);
-
-    /* Perform 7.1.2.2.2.  Updating Pair States.
-     * This may terminate ICE processing.
-     */
-    if (on_check_complete(ice, check)) {
-	/* ICE complete! */
 	pj_mutex_unlock(ice->mutex);
-	return;
-    }
-
-    pj_mutex_unlock(ice->mutex);
 }
 
 
 /* This callback is called by the STUN session associated with a candidate
- * when it receives incoming request.
- */
+* when it receives incoming request.
+*/
 static pj_status_t on_stun_rx_request(pj_stun_session *sess,
-				      const pj_uint8_t *pkt,
-				      unsigned pkt_len,
-				      const pj_stun_rx_data *rdata,
-				      void *token,
-				      const pj_sockaddr_t *src_addr,
-				      unsigned src_addr_len)
+									  const pj_uint8_t *pkt,
+									  unsigned pkt_len,
+									  const pj_stun_rx_data *rdata,
+									  void *token,
+									  const pj_sockaddr_t *src_addr,
+									  unsigned src_addr_len)
 {
-    stun_data *sd;
-    const pj_stun_msg *msg = rdata->msg;
-    pj_ice_msg_data *msg_data;
-    pj_ice_sess *ice;
-    pj_stun_priority_attr *prio_attr;
-    pj_stun_use_candidate_attr *uc_attr;
-    pj_stun_uint64_attr *role_attr;
-    pj_stun_tx_data *tdata;
-    pj_ice_rx_check *rcheck, tmp_rcheck;
-    pj_status_t status;
+	stun_data *sd;
+	const pj_stun_msg *msg = rdata->msg;
+	pj_ice_msg_data *msg_data;
+	pj_ice_sess *ice;
+	pj_stun_priority_attr *prio_attr;
+	pj_stun_use_candidate_attr *uc_attr;
+	pj_stun_uint64_attr *role_attr;
+	pj_stun_tx_data *tdata;
+	pj_ice_rx_check *rcheck, tmp_rcheck;
+	pj_status_t status;
 
-    PJ_UNUSED_ARG(pkt);
-    PJ_UNUSED_ARG(pkt_len);
-    
-    /* Reject any requests except Binding request */
-    if (msg->hdr.type != PJ_STUN_BINDING_REQUEST) {
-	pj_stun_session_respond(sess, rdata, PJ_STUN_SC_BAD_REQUEST, 
-				NULL, token, PJ_TRUE, 
-				src_addr, src_addr_len);
-	return PJ_SUCCESS;
-    }
+	PJ_UNUSED_ARG(pkt);
+	PJ_UNUSED_ARG(pkt_len);
 
+	/* Reject any requests except Binding request */
+	if (msg->hdr.type != PJ_STUN_BINDING_REQUEST) {
+		pj_stun_session_respond(sess, rdata, PJ_STUN_SC_BAD_REQUEST, 
+			NULL, token, PJ_TRUE, 
+			src_addr, src_addr_len);
+		return PJ_SUCCESS;
+	}
 
-    sd = (stun_data*) pj_stun_session_get_user_data(sess);
-    ice = sd->ice;
 
-    pj_mutex_lock(ice->mutex);
+	sd = (stun_data*) pj_stun_session_get_user_data(sess);
+	ice = sd->ice;
 
-    /*
-     * Note:
-     *  Be aware that when STUN request is received, we might not get
-     *  SDP answer yet, so we might not have remote candidates and
-     *  checklist yet. This case will be handled after we send
-     *  a response.
-     */
+	pj_mutex_lock(ice->mutex);
 
-    /* Get PRIORITY attribute */
-    prio_attr = (pj_stun_priority_attr*)
-	        pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_PRIORITY, 0);
-    if (prio_attr == NULL) {
-	LOG5((ice->obj_name, "Received Binding request with no PRIORITY"));
-	pj_mutex_unlock(ice->mutex);
-	return PJ_SUCCESS;
-    }
+	/*
+	* Note:
+	*  Be aware that when STUN request is received, we might not get
+	*  SDP answer yet, so we might not have remote candidates and
+	*  checklist yet. This case will be handled after we send
+	*  a response.
+	*/
 
-    /* Get USE-CANDIDATE attribute */
-    uc_attr = (pj_stun_use_candidate_attr*)
-	      pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_USE_CANDIDATE, 0);
+	/* Get PRIORITY attribute */
+	prio_attr = (pj_stun_priority_attr*)
+		pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_PRIORITY, 0);
+	if (prio_attr == NULL && pj_stun_session_get_auth_type(sess) != PJ_STUN_AUTH_WEBRTC) {
+		LOG5((ice->obj_name, "Received Binding request with no PRIORITY"));
+		pj_mutex_unlock(ice->mutex);
+		return PJ_SUCCESS;
+	}
 
+	/* Get USE-CANDIDATE attribute */
+	uc_attr = (pj_stun_use_candidate_attr*)
+		pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_USE_CANDIDATE, 0);
 
-    /* Get ICE-CONTROLLING or ICE-CONTROLLED */
-    role_attr = (pj_stun_uint64_attr*)
-	        pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_ICE_CONTROLLING, 0);
-    if (role_attr == NULL) {
+
+	/* Get ICE-CONTROLLING or ICE-CONTROLLED */
 	role_attr = (pj_stun_uint64_attr*)
-	            pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_ICE_CONTROLLED, 0);
-    }
+		pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_ICE_CONTROLLING, 0);
+	if (role_attr == NULL) {
+		role_attr = (pj_stun_uint64_attr*)
+			pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_ICE_CONTROLLED, 0);
+	}
 
-    /* Handle the case when request comes before answer is received.
-     * We need to put credential in the response, and since we haven't
-     * got the response, copy the username from the request.
-     */
-    if (ice->rcand_cnt == 0) {
-	pj_stun_string_attr *uname_attr;
+	/* Handle the case when request comes before answer is received.
+	* We need to put credential in the response, and since we haven't
+	* got the response, copy the username from the request.
+	*/
+	if (ice->rcand_cnt == 0) {
+		pj_stun_string_attr *uname_attr;
 
-	uname_attr = (pj_stun_string_attr*)
-		     pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_USERNAME, 0);
-	pj_assert(uname_attr != NULL);
-	pj_strdup(ice->pool, &ice->rx_uname, &uname_attr->value);
-    }
+		uname_attr = (pj_stun_string_attr*)
+			pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_USERNAME, 0);
+		pj_assert(uname_attr != NULL);
+		pj_strdup(ice->pool, &ice->rx_uname, &uname_attr->value);
+	}
 
-    /* 7.2.1.1.  Detecting and Repairing Role Conflicts
-     */
-    if (ice->role == PJ_ICE_SESS_ROLE_CONTROLLING &&
-	role_attr && role_attr->hdr.type == PJ_STUN_ATTR_ICE_CONTROLLING)
-    {
-	if (pj_cmp_timestamp(&ice->tie_breaker, &role_attr->value) < 0) {
-	    /* Switch role to controlled */
-	    LOG4((ice->obj_name, 
-		  "Changing role because of ICE-CONTROLLING attribute"));
-	    pj_ice_sess_change_role(ice, PJ_ICE_SESS_ROLE_CONTROLLED);
-	} else {
-	    /* Generate 487 response */
-	    pj_stun_session_respond(sess, rdata, PJ_STUN_SC_ROLE_CONFLICT, 
-				    NULL, token, PJ_TRUE, 
-				    src_addr, src_addr_len);
-	    pj_mutex_unlock(ice->mutex);
-	    return PJ_SUCCESS;
+	/* 7.2.1.1.  Detecting and Repairing Role Conflicts
+	*/
+	if (ice->role == PJ_ICE_SESS_ROLE_CONTROLLING &&
+		role_attr && role_attr->hdr.type == PJ_STUN_ATTR_ICE_CONTROLLING)
+	{
+		if (pj_cmp_timestamp(&ice->tie_breaker, &role_attr->value) < 0) {
+			/* Switch role to controlled */
+			LOG4((ice->obj_name, 
+				"Changing role because of ICE-CONTROLLING attribute"));
+			pj_ice_sess_change_role(ice, PJ_ICE_SESS_ROLE_CONTROLLED);
+		} else {
+			/* Generate 487 response */
+			pj_stun_session_respond(sess, rdata, PJ_STUN_SC_ROLE_CONFLICT, 
+				NULL, token, PJ_TRUE, 
+				src_addr, src_addr_len);
+			pj_mutex_unlock(ice->mutex);
+			return PJ_SUCCESS;
+		}
+
+	} else if (ice->role == PJ_ICE_SESS_ROLE_CONTROLLED &&
+		role_attr && role_attr->hdr.type == PJ_STUN_ATTR_ICE_CONTROLLED)
+	{
+		if (pj_cmp_timestamp(&ice->tie_breaker, &role_attr->value) < 0) {
+			/* Generate 487 response */
+			pj_stun_session_respond(sess, rdata, PJ_STUN_SC_ROLE_CONFLICT, 
+				NULL, token, PJ_TRUE, 
+				src_addr, src_addr_len);
+			pj_mutex_unlock(ice->mutex);
+			return PJ_SUCCESS;
+		} else {
+			/* Switch role to controlled */
+			LOG4((ice->obj_name, 
+				"Changing role because of ICE-CONTROLLED attribute"));
+			pj_ice_sess_change_role(ice, PJ_ICE_SESS_ROLE_CONTROLLING);
+		}
 	}
 
-    } else if (ice->role == PJ_ICE_SESS_ROLE_CONTROLLED &&
-	       role_attr && role_attr->hdr.type == PJ_STUN_ATTR_ICE_CONTROLLED)
-    {
-	if (pj_cmp_timestamp(&ice->tie_breaker, &role_attr->value) < 0) {
-	    /* Generate 487 response */
-	    pj_stun_session_respond(sess, rdata, PJ_STUN_SC_ROLE_CONFLICT, 
-				    NULL, token, PJ_TRUE, 
-				    src_addr, src_addr_len);
-	    pj_mutex_unlock(ice->mutex);
-	    return PJ_SUCCESS;
-	} else {
-	    /* Switch role to controlled */
-	    LOG4((ice->obj_name, 
-		  "Changing role because of ICE-CONTROLLED attribute"));
-	    pj_ice_sess_change_role(ice, PJ_ICE_SESS_ROLE_CONTROLLING);
+	/* 
+	* First send response to this request 
+	*/
+	status = pj_stun_session_create_res(sess, rdata, 0, NULL, &tdata);
+	if (status != PJ_SUCCESS) {
+		pj_mutex_unlock(ice->mutex);
+		return status;
 	}
-    }
 
-    /* 
-     * First send response to this request 
-     */
-    status = pj_stun_session_create_res(sess, rdata, 0, NULL, &tdata);
-    if (status != PJ_SUCCESS) {
-	pj_mutex_unlock(ice->mutex);
-	return status;
-    }
+	/* Add XOR-MAPPED-ADDRESS attribute */
+	status = pj_stun_msg_add_sockaddr_attr(tdata->pool, tdata->msg, 
+		PJ_STUN_ATTR_XOR_MAPPED_ADDR,
+		PJ_TRUE, src_addr, src_addr_len);
 
-    /* Add XOR-MAPPED-ADDRESS attribute */
-    status = pj_stun_msg_add_sockaddr_attr(tdata->pool, tdata->msg, 
-					   PJ_STUN_ATTR_XOR_MAPPED_ADDR,
-					   PJ_TRUE, src_addr, src_addr_len);
+	/* Add MAPPED-ADDRESS attribute */
+	status = pj_stun_msg_add_sockaddr_attr(tdata->pool, tdata->msg, 
+		PJ_STUN_ATTR_MAPPED_ADDR,
+		PJ_FALSE, src_addr, src_addr_len);
 
-    /* Create a msg_data to be associated with this response */
-    msg_data = PJ_POOL_ZALLOC_T(tdata->pool, pj_ice_msg_data);
-    msg_data->transport_id = ((pj_ice_msg_data*)token)->transport_id;
-    msg_data->has_req_data = PJ_FALSE;
+	/* Create a msg_data to be associated with this response */
+	msg_data = PJ_POOL_ZALLOC_T(tdata->pool, pj_ice_msg_data);
+	msg_data->transport_id = ((pj_ice_msg_data*)token)->transport_id;
+	msg_data->has_req_data = PJ_FALSE;
 
-    /* Send the response */
-    status = pj_stun_session_send_msg(sess, msg_data, PJ_TRUE, PJ_TRUE,
-				      src_addr, src_addr_len, tdata);
+	/* Send the response */
+	status = pj_stun_session_send_msg(sess, msg_data, PJ_TRUE, PJ_TRUE,
+		src_addr, src_addr_len, tdata);
 
 
-    /* 
-     * Handling early check.
-     *
-     * It's possible that we receive this request before we receive SDP
-     * answer. In this case, we can't perform trigger check since we
-     * don't have checklist yet, so just save this check in a pending
-     * triggered check array to be acted upon later.
-     */
-    if (ice->rcand_cnt == 0) {
-	rcheck = PJ_POOL_ZALLOC_T(ice->pool, pj_ice_rx_check);
-    } else {
-	rcheck = &tmp_rcheck;
-    }
+	/* 
+	* Handling early check.
+	*
+	* It's possible that we receive this request before we receive SDP
+	* answer. In this case, we can't perform trigger check since we
+	* don't have checklist yet, so just save this check in a pending
+	* triggered check array to be acted upon later.
+	*/
+	if (ice->rcand_cnt == 0) {
+		rcheck = PJ_POOL_ZALLOC_T(ice->pool, pj_ice_rx_check);
+	} else {
+		rcheck = &tmp_rcheck;
+	}
 
-    /* Init rcheck */
-    rcheck->comp_id = sd->comp_id;
-    rcheck->transport_id = ((pj_ice_msg_data*)token)->transport_id;
-    rcheck->src_addr_len = src_addr_len;
-    pj_memcpy(&rcheck->src_addr, src_addr, src_addr_len);
-    rcheck->use_candidate = (uc_attr != NULL);
-    rcheck->priority = prio_attr->value;
-    rcheck->role_attr = role_attr;
+	/* Init rcheck */
+	rcheck->comp_id = sd->comp_id;
+	rcheck->transport_id = ((pj_ice_msg_data*)token)->transport_id;
+	rcheck->src_addr_len = src_addr_len;
+	pj_memcpy(&rcheck->src_addr, src_addr, src_addr_len);
+	rcheck->use_candidate = (uc_attr != NULL);
+	if(prio_attr){
+		rcheck->priority = prio_attr->value;
+	}
+	rcheck->role_attr = role_attr;
 
-    if (ice->rcand_cnt == 0) {
-	/* We don't have answer yet, so keep this request for later */
-	LOG4((ice->obj_name, "Received an early check for comp %d",
-	      rcheck->comp_id));
-	pj_list_push_back(&ice->early_check, rcheck);
-    } else {
-	/* Handle this check */
-	handle_incoming_check(ice, rcheck);
-    }
+	if (ice->rcand_cnt == 0) {
+		/* We don't have answer yet, so keep this request for later */
+		LOG4((ice->obj_name, "Received an early check for comp %d",
+			rcheck->comp_id));
+		pj_list_push_back(&ice->early_check, rcheck);
+	} else {
+		/* Handle this check */
+		handle_incoming_check(ice, rcheck);
+	}
 
-    pj_mutex_unlock(ice->mutex);
-    return PJ_SUCCESS;
+	pj_mutex_unlock(ice->mutex);
+	return PJ_SUCCESS;
 }
 
 
 /* Handle incoming Binding request and perform triggered check.
- * This function may be called by on_stun_rx_request(), or when
- * SDP answer is received and we have received early checks.
- */
+* This function may be called by on_stun_rx_request(), or when
+* SDP answer is received and we have received early checks.
+*/
 static void handle_incoming_check(pj_ice_sess *ice,
-				  const pj_ice_rx_check *rcheck)
+								  const pj_ice_rx_check *rcheck)
 {
-    pj_ice_sess_comp *comp;
-    pj_ice_sess_cand *lcand = NULL;
-    pj_ice_sess_cand *rcand;
-    unsigned i;
+	pj_ice_sess_comp *comp;
+	pj_ice_sess_cand *lcand = NULL;
+	pj_ice_sess_cand *rcand;
+	unsigned i;
 
-    comp = find_comp(ice, rcheck->comp_id);
+	comp = find_comp(ice, rcheck->comp_id);
 
-    /* Find remote candidate based on the source transport address of 
-     * the request.
-     */
-    for (i=0; i<ice->rcand_cnt; ++i) {
-	if (sockaddr_cmp(&rcheck->src_addr, &ice->rcand[i].addr)==0)
-	    break;
-    }
-
-    /* 7.2.1.3.  Learning Peer Reflexive Candidates
-     * If the source transport address of the request does not match any
-     * existing remote candidates, it represents a new peer reflexive remote
-     * candidate.
-     */
-    if (i == ice->rcand_cnt) {
-	if (ice->rcand_cnt >= PJ_ICE_MAX_CAND) {
-	    LOG4((ice->obj_name, 
-	          "Unable to add new peer reflexive candidate: too many "
-		  "candidates already (%d)", PJ_ICE_MAX_CAND));
-	    return;
+	/* Find remote candidate based on the source transport address of 
+	* the request.
+	*/
+	for (i=0; i<ice->rcand_cnt; ++i) {
+		if (sockaddr_cmp(&rcheck->src_addr, &ice->rcand[i].addr)==0)
+			break;
 	}
 
-	rcand = &ice->rcand[ice->rcand_cnt++];
-	rcand->comp_id = (pj_uint8_t)rcheck->comp_id;
-	rcand->type = PJ_ICE_CAND_TYPE_PRFLX;
-	rcand->prio = rcheck->priority;
-	pj_memcpy(&rcand->addr, &rcheck->src_addr, rcheck->src_addr_len);
+	/* 7.2.1.3.  Learning Peer Reflexive Candidates
+	* If the source transport address of the request does not match any
+	* existing remote candidates, it represents a new peer reflexive remote
+	* candidate.
+	*/
+	if (i == ice->rcand_cnt) {
+		if (ice->rcand_cnt >= PJ_ICE_MAX_CAND) {
+			LOG4((ice->obj_name, 
+				"Unable to add new peer reflexive candidate: too many "
+				"candidates already (%d)", PJ_ICE_MAX_CAND));
+			return;
+		}
 
-	/* Foundation is random, unique from other foundation */
-	rcand->foundation.ptr = (char*) pj_pool_alloc(ice->pool, 36);
-	rcand->foundation.slen = pj_ansi_snprintf(rcand->foundation.ptr, 36,
-						  "f%p", 
-						  rcand->foundation.ptr);
+		rcand = &ice->rcand[ice->rcand_cnt++];
+		rcand->comp_id = (pj_uint8_t)rcheck->comp_id;
+		rcand->type = PJ_ICE_CAND_TYPE_PRFLX;
+		rcand->prio = rcheck->priority;
+		pj_memcpy(&rcand->addr, &rcheck->src_addr, rcheck->src_addr_len);
 
-	LOG4((ice->obj_name, 
-	     "Added new remote candidate from the request: %s:%d",
-	     pj_inet_ntoa(rcand->addr.ipv4.sin_addr),
-	     (int)pj_ntohs(rcand->addr.ipv4.sin_port)));
+		/* Foundation is random, unique from other foundation */
+		rcand->foundation.ptr = (char*) pj_pool_alloc(ice->pool, 36);
+		rcand->foundation.slen = pj_ansi_snprintf(rcand->foundation.ptr, 36,
+			"f%p", 
+			rcand->foundation.ptr);
 
-    } else {
-	/* Remote candidate found */
-	rcand = &ice->rcand[i];
-    }
+		LOG4((ice->obj_name, 
+			"Added new remote candidate from the request: %s:%d",
+			pj_inet_ntoa(rcand->addr.ipv4.sin_addr),
+			(int)pj_ntohs(rcand->addr.ipv4.sin_port)));
 
+	} else {
+		/* Remote candidate found */
+		rcand = &ice->rcand[i];
+	}
+
 #if 0
-    /* Find again the local candidate by matching the base address
-     * with the local candidates in the checklist. Checks may have
-     * been pruned before, so it's possible that if we use the lcand
-     * as it is, we wouldn't be able to find the check in the checklist
-     * and we will end up creating a new check unnecessarily.
-     */
-    for (i=0; i<ice->clist.count; ++i) {
-	pj_ice_sess_check *c = &ice->clist.checks[i];
-	if (/*c->lcand == lcand ||*/
-	    sockaddr_cmp(&c->lcand->base_addr, &lcand->base_addr)==0)
-	{
-	    lcand = c->lcand;
-	    break;
+	/* Find again the local candidate by matching the base address
+	* with the local candidates in the checklist. Checks may have
+	* been pruned before, so it's possible that if we use the lcand
+	* as it is, we wouldn't be able to find the check in the checklist
+	* and we will end up creating a new check unnecessarily.
+	*/
+	for (i=0; i<ice->clist.count; ++i) {
+		pj_ice_sess_check *c = &ice->clist.checks[i];
+		if (/*c->lcand == lcand ||*/
+			sockaddr_cmp(&c->lcand->base_addr, &lcand->base_addr)==0)
+		{
+			lcand = c->lcand;
+			break;
+		}
 	}
-    }
 #else
-    /* Just get candidate with the highest priority and same transport ID
-     * for the specified  component ID in the checklist.
-     */
-    for (i=0; i<ice->clist.count; ++i) {
-	pj_ice_sess_check *c = &ice->clist.checks[i];
-	if (c->lcand->comp_id == rcheck->comp_id &&
-	    c->lcand->transport_id == rcheck->transport_id) 
-	{
-	    lcand = c->lcand;
-	    break;
+	/* Just get candidate with the highest priority and same transport ID
+	* for the specified  component ID in the checklist.
+	*/
+	for (i=0; i<ice->clist.count; ++i) {
+		pj_ice_sess_check *c = &ice->clist.checks[i];
+		if (c->lcand->comp_id == rcheck->comp_id &&
+			c->lcand->transport_id == rcheck->transport_id) 
+		{
+			lcand = c->lcand;
+			break;
+		}
 	}
-    }
-    if (lcand == NULL) {
-	/* Should not happen, but just in case remote is sending a
-	 * Binding request for a component which it doesn't have.
-	 */
-	LOG4((ice->obj_name, 
-	     "Received Binding request but no local candidate is found!"));
-	return;
-    }
+	if (lcand == NULL) {
+		/* Should not happen, but just in case remote is sending a
+		* Binding request for a component which it doesn't have.
+		*/
+		LOG4((ice->obj_name, 
+			"Received Binding request but no local candidate is found!"));
+		return;
+	}
 #endif
 
-    /* 
-     * Create candidate pair for this request. 
-     */
+	/* 
+	* Create candidate pair for this request. 
+	*/
 
-    /* 
-     * 7.2.1.4.  Triggered Checks
-     *
-     * Now that we have local and remote candidate, check if we already
-     * have this pair in our checklist.
-     */
-    for (i=0; i<ice->clist.count; ++i) {
-	pj_ice_sess_check *c = &ice->clist.checks[i];
-	if (c->lcand == lcand && c->rcand == rcand)
-	    break;
-    }
+	/* 
+	* 7.2.1.4.  Triggered Checks
+	*
+	* Now that we have local and remote candidate, check if we already
+	* have this pair in our checklist.
+	*/
+	for (i=0; i<ice->clist.count; ++i) {
+		pj_ice_sess_check *c = &ice->clist.checks[i];
+		if (c->lcand == lcand && c->rcand == rcand)
+			break;
+	}
 
-    /* If the pair is already on the check list:
-     * - If the state of that pair is Waiting or Frozen, its state is
-     *   changed to In-Progress and a check for that pair is performed
-     *   immediately.  This is called a triggered check.
-     *
-     * - If the state of that pair is In-Progress, the agent SHOULD
-     *   generate an immediate retransmit of the Binding Request for the
-     *   check in progress.  This is to facilitate rapid completion of
-     *   ICE when both agents are behind NAT.
-     * 
-     * - If the state of that pair is Failed or Succeeded, no triggered
-     *   check is sent.
-     */
-    if (i != ice->clist.count) {
-	pj_ice_sess_check *c = &ice->clist.checks[i];
+	/* If the pair is already on the check list:
+	* - If the state of that pair is Waiting or Frozen, its state is
+	*   changed to In-Progress and a check for that pair is performed
+	*   immediately.  This is called a triggered check.
+	*
+	* - If the state of that pair is In-Progress, the agent SHOULD
+	*   generate an immediate retransmit of the Binding Request for the
+	*   check in progress.  This is to facilitate rapid completion of
+	*   ICE when both agents are behind NAT.
+	* 
+	* - If the state of that pair is Failed or Succeeded, no triggered
+	*   check is sent.
+	*/
+	if (i != ice->clist.count) {
+		pj_ice_sess_check *c = &ice->clist.checks[i];
 
-	/* If USE-CANDIDATE is present, set nominated flag 
-	 * Note: DO NOT overwrite nominated flag if one is already set.
-	 */
-	c->nominated = ((rcheck->use_candidate) || c->nominated);
+		/* If USE-CANDIDATE is present, set nominated flag 
+		* Note: DO NOT overwrite nominated flag if one is already set.
+		*/
+		c->nominated = ((rcheck->use_candidate) || c->nominated);
 
-	if (c->state == PJ_ICE_SESS_CHECK_STATE_FROZEN ||
-	    c->state == PJ_ICE_SESS_CHECK_STATE_WAITING)
-	{
-	    /* See if we shall nominate this check */
-	    pj_bool_t nominate = (c->nominated || ice->is_nominating);
+		if (c->state == PJ_ICE_SESS_CHECK_STATE_FROZEN ||
+			c->state == PJ_ICE_SESS_CHECK_STATE_WAITING)
+		{
+			/* See if we shall nominate this check */
+			pj_bool_t nominate = (c->nominated || ice->is_nominating);
 
-	    LOG5((ice->obj_name, "Performing triggered check for check %d",i));
-	    pj_log_push_indent();
-	    perform_check(ice, &ice->clist, i, nominate);
-	    pj_log_pop_indent();
+			LOG5((ice->obj_name, "Performing triggered check for check %d",i));
+			pj_log_push_indent();
+			perform_check(ice, &ice->clist, i, nominate);
+			pj_log_pop_indent();
 
-	} else if (c->state == PJ_ICE_SESS_CHECK_STATE_IN_PROGRESS) {
-	    /* Should retransmit immediately
-	     */
-	    LOG5((ice->obj_name, "Triggered check for check %d not performed "
-		  "because it's in progress. Retransmitting", i));
-	    pj_log_push_indent();
-	    pj_stun_session_retransmit_req(comp->stun_sess, c->tdata);
-	    pj_log_pop_indent();
+		} else if (c->state == PJ_ICE_SESS_CHECK_STATE_IN_PROGRESS) {
+			/* Should retransmit immediately
+			*/
+			LOG5((ice->obj_name, "Triggered check for check %d not performed "
+				"because it's in progress. Retransmitting", i));
+			pj_log_push_indent();
+			pj_stun_session_retransmit_req(comp->stun_sess, c->tdata);
+			pj_log_pop_indent();
 
-	} else if (c->state == PJ_ICE_SESS_CHECK_STATE_SUCCEEDED) {
-	    /* Check complete for this component.
-	     * Note this may end ICE process.
-	     */
-	    pj_bool_t complete;
-	    unsigned j;
+		} else if (c->state == PJ_ICE_SESS_CHECK_STATE_SUCCEEDED) {
+			/* Check complete for this component.
+			* Note this may end ICE process.
+			*/
+			pj_bool_t complete;
+			unsigned j;
 
-	    /* If this check is nominated, scan the valid_list for the
-	     * same check and update the nominated flag. A controlled 
-	     * agent might have finished the check earlier.
-	     */
-	    if (rcheck->use_candidate) {
-		for (j=0; j<ice->valid_list.count; ++j) {
-		    pj_ice_sess_check *vc = &ice->valid_list.checks[j];
-		    if (vc->lcand->transport_id == c->lcand->transport_id && 
-			vc->rcand == c->rcand) 
-		    {
-			/* Set nominated flag */
-			vc->nominated = PJ_TRUE;
+			// WebRTC STUN refreshness
+			if(ice->opt.is_webrtc){
+				pj_ice_sess_check *_c;
+				pj_ice_sess_comp *_comp;
 
-			/* Update valid check and nominated check for the component */
-			update_comp_check(ice, vc->lcand->comp_id, vc);
+				if ((_comp = &ice->comp[0]) && ((_c = _comp->nominated_check) || (_c = _comp->valid_check)) && _c->rcand){
+					pj_status_t status;
+					pj_ice_msg_data* msg_data;
 
-			LOG5((ice->obj_name, "Valid check %s is nominated", 
-			      dump_check(ice->tmp.txt, sizeof(ice->tmp.txt), 
-					 &ice->valid_list, vc)));
-		    }
+					status = pj_stun_session_create_req(_comp->stun_sess, 
+						PJ_STUN_BINDING_REQUEST, PJ_STUN_MAGIC,
+						NULL, &_c->tdata);
+					if(status == PJ_SUCCESS){
+						msg_data = PJ_POOL_ZALLOC_T(_c->tdata->pool, pj_ice_msg_data);
+						if(msg_data){
+							msg_data->transport_id = lcand->transport_id;
+							msg_data->has_req_data = PJ_TRUE;
+							msg_data->data.req.ice = ice;
+							msg_data->data.req.clist = &ice->clist;
+							msg_data->data.req.ckid = i;
+							status = pj_stun_session_send_msg(_comp->stun_sess, msg_data, PJ_FALSE, 
+								PJ_TRUE, &_c->rcand->addr, 
+								sizeof(pj_sockaddr_in), _c->tdata);
+						}
+					}
+				}
+			}
+
+			/* If this check is nominated, scan the valid_list for the
+			* same check and update the nominated flag. A controlled 
+			* agent might have finished the check earlier.
+			*/
+			if (rcheck->use_candidate) {
+				for (j=0; j<ice->valid_list.count; ++j) {
+					pj_ice_sess_check *vc = &ice->valid_list.checks[j];
+					if (vc->lcand->transport_id == c->lcand->transport_id && 
+						vc->rcand == c->rcand) 
+					{
+						/* Set nominated flag */
+						vc->nominated = PJ_TRUE;
+
+						/* Update valid check and nominated check for the component */
+						update_comp_check(ice, vc->lcand->comp_id, vc);
+
+						LOG5((ice->obj_name, "Valid check %s is nominated", 
+							dump_check(ice->tmp.txt, sizeof(ice->tmp.txt), 
+							&ice->valid_list, vc)));
+					}
+				}
+			}
+
+			LOG5((ice->obj_name, "Triggered check for check %d not performed "
+				"because it's completed", i));
+			pj_log_push_indent();
+			complete = on_check_complete(ice, c);
+			pj_log_pop_indent();
+			if (complete) {
+				return;
+			}
 		}
-	    }
 
-	    LOG5((ice->obj_name, "Triggered check for check %d not performed "
-				"because it's completed", i));
-	    pj_log_push_indent();
-	    complete = on_check_complete(ice, c);
-	    pj_log_pop_indent();
-	    if (complete) {
-		return;
-	    }
 	}
+	/* If the pair is not already on the check list:
+	* - The pair is inserted into the check list based on its priority.
+	* - Its state is set to In-Progress
+	* - A triggered check for that pair is performed immediately.
+	*/
+	/* Note: only do this if we don't have too many checks in checklist */
+	else if (ice->clist.count < PJ_ICE_MAX_CHECKS) {
 
-    }
-    /* If the pair is not already on the check list:
-     * - The pair is inserted into the check list based on its priority.
-     * - Its state is set to In-Progress
-     * - A triggered check for that pair is performed immediately.
-     */
-    /* Note: only do this if we don't have too many checks in checklist */
-    else if (ice->clist.count < PJ_ICE_MAX_CHECKS) {
+		pj_ice_sess_check *c = &ice->clist.checks[ice->clist.count];
+		pj_bool_t nominate;
 
-	pj_ice_sess_check *c = &ice->clist.checks[ice->clist.count];
-	pj_bool_t nominate;
+		c->lcand = lcand;
+		c->rcand = rcand;
+		c->prio = CALC_CHECK_PRIO(ice, lcand, rcand);
+		c->state = PJ_ICE_SESS_CHECK_STATE_WAITING;
+		c->nominated = rcheck->use_candidate;
+		c->err_code = PJ_SUCCESS;
 
-	c->lcand = lcand;
-	c->rcand = rcand;
-	c->prio = CALC_CHECK_PRIO(ice, lcand, rcand);
-	c->state = PJ_ICE_SESS_CHECK_STATE_WAITING;
-	c->nominated = rcheck->use_candidate;
-	c->err_code = PJ_SUCCESS;
+		nominate = (c->nominated || ice->is_nominating);
 
-	nominate = (c->nominated || ice->is_nominating);
+		LOG4((ice->obj_name, "New triggered check added: %d", 
+			ice->clist.count));
+		pj_log_push_indent();
+		perform_check(ice, &ice->clist, ice->clist.count++, nominate);
+		pj_log_pop_indent();
 
-	LOG4((ice->obj_name, "New triggered check added: %d", 
-	     ice->clist.count));
-	pj_log_push_indent();
-	perform_check(ice, &ice->clist, ice->clist.count++, nominate);
-	pj_log_pop_indent();
-
-    } else {
-	LOG4((ice->obj_name, "Error: unable to perform triggered check: "
-	     "TOO MANY CHECKS IN CHECKLIST!"));
-    }
+	} else {
+		LOG4((ice->obj_name, "Error: unable to perform triggered check: "
+			"TOO MANY CHECKS IN CHECKLIST!"));
+	}
 }
 
 
 static pj_status_t on_stun_rx_indication(pj_stun_session *sess,
-					 const pj_uint8_t *pkt,
-					 unsigned pkt_len,
-					 const pj_stun_msg *msg,
-					 void *token,
-					 const pj_sockaddr_t *src_addr,
-					 unsigned src_addr_len)
+										 const pj_uint8_t *pkt,
+										 unsigned pkt_len,
+										 const pj_stun_msg *msg,
+										 void *token,
+										 const pj_sockaddr_t *src_addr,
+										 unsigned src_addr_len)
 {
-    struct stun_data *sd;
+	struct stun_data *sd;
 
-    PJ_UNUSED_ARG(sess);
-    PJ_UNUSED_ARG(pkt);
-    PJ_UNUSED_ARG(pkt_len);
-    PJ_UNUSED_ARG(msg);
-    PJ_UNUSED_ARG(token);
-    PJ_UNUSED_ARG(src_addr);
-    PJ_UNUSED_ARG(src_addr_len);
+	PJ_UNUSED_ARG(sess);
+	PJ_UNUSED_ARG(pkt);
+	PJ_UNUSED_ARG(pkt_len);
+	PJ_UNUSED_ARG(msg);
+	PJ_UNUSED_ARG(token);
+	PJ_UNUSED_ARG(src_addr);
+	PJ_UNUSED_ARG(src_addr_len);
 
-    sd = (struct stun_data*) pj_stun_session_get_user_data(sess);
+	sd = (struct stun_data*) pj_stun_session_get_user_data(sess);
 
-    pj_log_push_indent();
+	pj_log_push_indent();
 
-    if (msg->hdr.type == PJ_STUN_BINDING_INDICATION) {
-	LOG5((sd->ice->obj_name, "Received Binding Indication keep-alive "
-	      "for component %d", sd->comp_id));
-    } else {
-	LOG4((sd->ice->obj_name, "Received unexpected %s indication "
-	      "for component %d", pj_stun_get_method_name(msg->hdr.type), 
-	      sd->comp_id));
-    }
+	if (msg->hdr.type == PJ_STUN_BINDING_INDICATION) {
+		LOG5((sd->ice->obj_name, "Received Binding Indication keep-alive "
+			"for component %d", sd->comp_id));
+	} else {
+		LOG4((sd->ice->obj_name, "Received unexpected %s indication "
+			"for component %d", pj_stun_get_method_name(msg->hdr.type), 
+			sd->comp_id));
+	}
 
-    pj_log_pop_indent();
+	pj_log_pop_indent();
 
-    return PJ_SUCCESS;
+	return PJ_SUCCESS;
 }
 
 
 PJ_DEF(pj_status_t) pj_ice_sess_send_data(pj_ice_sess *ice,
-					  unsigned comp_id,
-					  const void *data,
-					  pj_size_t data_len)
+										  unsigned comp_id,
+										  const void *data,
+										  pj_size_t data_len)
 {
-    pj_status_t status = PJ_SUCCESS;
-    pj_ice_sess_comp *comp;
-    pj_ice_sess_cand *cand;
-    pj_uint8_t transport_id;
-    pj_sockaddr addr;
+	pj_status_t status = PJ_SUCCESS;
+	pj_ice_sess_comp *comp;
+	pj_ice_sess_cand *cand;
+	pj_uint8_t transport_id;
+	pj_sockaddr addr;
 
-    PJ_ASSERT_RETURN(ice && comp_id, PJ_EINVAL);
-    
-    /* It is possible that comp_cnt is less than comp_id, when remote
-     * doesn't support all the components that we have.
-     */
-    if (comp_id > ice->comp_cnt) {
-	return PJNATH_EICEINCOMPID;
-    }
+	PJ_ASSERT_RETURN(ice && comp_id, PJ_EINVAL);
 
-    pj_mutex_lock(ice->mutex);
+	/* It is possible that comp_cnt is less than comp_id, when remote
+	* doesn't support all the components that we have.
+	*/
+	if (comp_id > ice->comp_cnt) {
+		return PJNATH_EICEINCOMPID;
+	}
 
-    comp = find_comp(ice, comp_id);
-    if (comp == NULL) {
-	status = PJNATH_EICEINCOMPID;
-	pj_mutex_unlock(ice->mutex);
-	goto on_return;
-    }
+	pj_mutex_lock(ice->mutex);
 
-    if (comp->valid_check == NULL) {
-	status = PJNATH_EICEINPROGRESS;
-	pj_mutex_unlock(ice->mutex);
-	goto on_return;
-    }
+	comp = find_comp(ice, comp_id);
+	if (comp == NULL) {
+		status = PJNATH_EICEINCOMPID;
+		pj_mutex_unlock(ice->mutex);
+		goto on_return;
+	}
 
-    cand = comp->valid_check->lcand;
-    transport_id = cand->transport_id;
-    pj_sockaddr_cp(&addr, &comp->valid_check->rcand->addr);
+	if (comp->valid_check == NULL) {
+		status = PJNATH_EICEINPROGRESS;
+		pj_mutex_unlock(ice->mutex);
+		goto on_return;
+	}
 
-    /* Release the mutex now to avoid deadlock (see ticket #1451). */
-    pj_mutex_unlock(ice->mutex);
+	cand = comp->valid_check->lcand;
+	transport_id = cand->transport_id;
+	pj_sockaddr_cp(&addr, &comp->valid_check->rcand->addr);
 
-    status = (*ice->cb.on_tx_pkt)(ice, comp_id, transport_id, 
-				  data, data_len, 
-				  &addr, 
-				  sizeof(pj_sockaddr_in));
+	/* Release the mutex now to avoid deadlock (see ticket #1451). */
+	pj_mutex_unlock(ice->mutex);
 
+	status = (*ice->cb.on_tx_pkt)(ice, comp_id, transport_id, 
+		data, data_len, 
+		&addr, 
+		sizeof(pj_sockaddr_in));
+
 on_return:
-    return status;
+	return status;
 }
 
 
 PJ_DEF(pj_status_t) pj_ice_sess_on_rx_pkt(pj_ice_sess *ice,
-					  unsigned comp_id,
-					  unsigned transport_id,
-					  void *pkt,
-					  pj_size_t pkt_size,
-					  const pj_sockaddr_t *src_addr,
-					  int src_addr_len)
+										  unsigned comp_id,
+										  unsigned transport_id,
+										  void *pkt,
+										  pj_size_t pkt_size,
+										  const pj_sockaddr_t *src_addr,
+										  int src_addr_len)
 {
-    pj_status_t status = PJ_SUCCESS;
-    pj_ice_sess_comp *comp;
-    pj_ice_msg_data *msg_data = NULL;
-    unsigned i;
+	pj_status_t status = PJ_SUCCESS;
+	pj_ice_sess_comp *comp;
+	pj_ice_msg_data *msg_data = NULL;
+	unsigned i;
 
-    PJ_ASSERT_RETURN(ice, PJ_EINVAL);
+	PJ_ASSERT_RETURN(ice, PJ_EINVAL);
 
-    pj_mutex_lock(ice->mutex);
+	pj_mutex_lock(ice->mutex);
 
-    comp = find_comp(ice, comp_id);
-    if (comp == NULL) {
-	pj_mutex_unlock(ice->mutex);
-	return PJNATH_EICEINCOMPID;
-    }
+	comp = find_comp(ice, comp_id);
+	if (comp == NULL) {
+		pj_mutex_unlock(ice->mutex);
+		return PJNATH_EICEINCOMPID;
+	}
 
-    /* Find transport */
-    for (i=0; i<PJ_ARRAY_SIZE(ice->tp_data); ++i) {
-	if (ice->tp_data[i].transport_id == transport_id) {
-	    msg_data = &ice->tp_data[i];
-	    break;
+	/* Find transport */
+	for (i=0; i<PJ_ARRAY_SIZE(ice->tp_data); ++i) {
+		if (ice->tp_data[i].transport_id == transport_id) {
+			msg_data = &ice->tp_data[i];
+			break;
+		}
 	}
-    }
-    if (msg_data == NULL) {
-	pj_assert(!"Invalid transport ID");
-	pj_mutex_unlock(ice->mutex);
-	return PJ_EINVAL;
-    }
+	if (msg_data == NULL) {
+		pj_assert(!"Invalid transport ID");
+		pj_mutex_unlock(ice->mutex);
+		return PJ_EINVAL;
+	}
 
-    /* Don't check fingerprint. We only need to distinguish STUN and non-STUN
-     * packets. We don't need to verify the STUN packet too rigorously, that
-     * will be done by the user.
-     */
-    status = pj_stun_msg_check((const pj_uint8_t*)pkt, pkt_size, 
-    			       PJ_STUN_IS_DATAGRAM |
-    			         PJ_STUN_NO_FINGERPRINT_CHECK);
-    if (status == PJ_SUCCESS) {
-	status = pj_stun_session_on_rx_pkt(comp->stun_sess, pkt, pkt_size,
-					   PJ_STUN_IS_DATAGRAM, msg_data,
-					   NULL, src_addr, src_addr_len);
-	if (status != PJ_SUCCESS) {
-	    pj_strerror(status, ice->tmp.errmsg, sizeof(ice->tmp.errmsg));
-	    LOG4((ice->obj_name, "Error processing incoming message: %s",
-		  ice->tmp.errmsg));
+	/* Don't check fingerprint. We only need to distinguish STUN and non-STUN
+	* packets. We don't need to verify the STUN packet too rigorously, that
+	* will be done by the user.
+	*/
+	status = pj_stun_msg_check((const pj_uint8_t*)pkt, pkt_size, 
+		PJ_STUN_IS_DATAGRAM |
+		PJ_STUN_NO_FINGERPRINT_CHECK);
+	if (status == PJ_SUCCESS) {
+		status = pj_stun_session_on_rx_pkt(comp->stun_sess, pkt, pkt_size,
+			PJ_STUN_IS_DATAGRAM, msg_data,
+			NULL, src_addr, src_addr_len);
+		if (status != PJ_SUCCESS) {
+			pj_strerror(status, ice->tmp.errmsg, sizeof(ice->tmp.errmsg));
+			LOG4((ice->obj_name, "Error processing incoming message: %s",
+				ice->tmp.errmsg));
+		}
+		pj_mutex_unlock(ice->mutex);
+	} else {
+		/* Not a STUN packet. Call application's callback instead, but release
+		* the mutex now or otherwise we may get deadlock.
+		*/
+		pj_mutex_unlock(ice->mutex);
+
+		(*ice->cb.on_rx_data)(ice, comp_id, transport_id, pkt, pkt_size, 
+			src_addr, src_addr_len);
+		status = PJ_SUCCESS;
 	}
-	pj_mutex_unlock(ice->mutex);
-    } else {
-	/* Not a STUN packet. Call application's callback instead, but release
-	 * the mutex now or otherwise we may get deadlock.
-	 */
-	pj_mutex_unlock(ice->mutex);
 
-	(*ice->cb.on_rx_data)(ice, comp_id, transport_id, pkt, pkt_size, 
-			      src_addr, src_addr_len);
-	status = PJ_SUCCESS;
-    }
-
-    return status;
+	return status;
 }
 
 
Index: res/pjproject/pjnath/src/pjnath/turn_sock.c
===================================================================
--- res/pjproject/pjnath/src/pjnath/turn_sock.c	(revision 373380)
+++ res/pjproject/pjnath/src/pjnath/turn_sock.c	(working copy)
@@ -97,6 +97,7 @@
 PJ_DEF(void) pj_turn_sock_cfg_default(pj_turn_sock_cfg *cfg)
 {
     pj_bzero(cfg, sizeof(*cfg));
+    cfg->max_pkt_size = PJ_TURN_MAX_PKT_LEN;
     cfg->qos_type = PJ_QOS_TYPE_BEST_EFFORT;
     cfg->qos_ignore_error = PJ_TRUE;
 }
@@ -210,6 +211,7 @@
     }
 
     if (turn_sock->active_sock) {
+        pj_activesock_set_user_data(turn_sock->active_sock, NULL);
 	pj_activesock_close(turn_sock->active_sock);
 	turn_sock->active_sock = NULL;
     }
@@ -462,7 +464,17 @@
     pj_turn_sock *turn_sock;
 
     turn_sock = (pj_turn_sock*) pj_activesock_get_user_data(asock);
+    if (!turn_sock)
+        return PJ_FALSE;
 
+    /* TURN session may have already been destroyed here.
+     * See ticket #1557 (http://trac.pjsip.org/repos/ticket/1557).
+     */
+    if (!turn_sock->sess) {
+	sess_fail(turn_sock, "TURN session already destroyed", status);
+	return PJ_FALSE;
+    }
+
     if (status != PJ_SUCCESS) {
 	sess_fail(turn_sock, "TCP connect() error", status);
 	return PJ_FALSE;
@@ -474,7 +486,7 @@
 
     /* Kick start pending read operation */
     status = pj_activesock_start_read(asock, turn_sock->pool, 
-				      PJ_TURN_MAX_PKT_LEN, 0);
+				      turn_sock->setting.max_pkt_size, 0);
 
     /* Init send_key */
     pj_ioqueue_op_key_init(&turn_sock->send_key, sizeof(turn_sock->send_key));
Index: res/pjproject/pjnath/src/pjnath/ice_strans.c
===================================================================
--- res/pjproject/pjnath/src/pjnath/ice_strans.c	(revision 373380)
+++ res/pjproject/pjnath/src/pjnath/ice_strans.c	(working copy)
@@ -503,6 +503,13 @@
 	add_update_turn(ice_st, comp);
     }
 
+    /* It's possible that we end up without any candidates */
+    if (comp->cand_cnt == 0) {
+	PJ_LOG(4,(ice_st->obj_name,
+		  "Error: no candidate is created due to settings"));
+	return PJ_EINVAL;
+    }
+
     return PJ_SUCCESS;
 }
 
@@ -1145,6 +1152,8 @@
  */
 PJ_DEF(pj_status_t) pj_ice_strans_stop_ice(pj_ice_strans *ice_st)
 {
+    PJ_ASSERT_RETURN(ice_st, PJ_EINVAL);
+
     if (ice_st->ice) {
 	pj_ice_sess_destroy(ice_st->ice);
 	ice_st->ice = NULL;
@@ -1546,7 +1555,7 @@
 		    if (comp->default_cand > idx) {
 			--comp->default_cand;
 		    } else if (comp->default_cand == idx) {
-			comp->default_cand = !idx;
+			comp->default_cand = 0;
 		    }
 
 		    /* Remove srflx candidate */
@@ -1574,7 +1583,7 @@
 	    /* May not have cand, e.g. when error during init */
 	    if (cand)
 		cand->status = status;
-	    if (!ice_st->cfg.stun.ignore_stun_error) {
+	    if (!ice_st->cfg.stun.ignore_stun_error || comp->cand_cnt==1) {
 		sess_fail(ice_st, PJ_ICE_STRANS_OP_INIT,
 			  "STUN binding request failed", status);
 	    } else {
Index: res/pjproject/pjnath/src/pjnath/stun_auth.c
===================================================================
--- res/pjproject/pjnath/src/pjnath/stun_auth.c	(revision 373380)
+++ res/pjproject/pjnath/src/pjnath/stun_auth.c	(working copy)
@@ -34,25 +34,31 @@
 				      pj_stun_auth_cred *dst,
 				      const pj_stun_auth_cred *src)
 {
-    dst->type = src->type;
+	dst->type = src->type;
 
-    switch (src->type) {
-    case PJ_STUN_AUTH_CRED_STATIC:
-	pj_strdup(pool, &dst->data.static_cred.realm,
-			&src->data.static_cred.realm);
-	pj_strdup(pool, &dst->data.static_cred.username,
-			&src->data.static_cred.username);
-	dst->data.static_cred.data_type = src->data.static_cred.data_type;
-	pj_strdup(pool, &dst->data.static_cred.data,
-			&src->data.static_cred.data);
-	pj_strdup(pool, &dst->data.static_cred.nonce,
-			&src->data.static_cred.nonce);
-	break;
-    case PJ_STUN_AUTH_CRED_DYNAMIC:
-	pj_memcpy(&dst->data.dyn_cred, &src->data.dyn_cred, 
-		  sizeof(src->data.dyn_cred));
-	break;
-    }
+	switch (src->type) {
+		case PJ_STUN_AUTH_CRED_WEBRTC:
+			pj_strdup(pool, &dst->data.webrtc_cred.rx_username,
+				&src->data.webrtc_cred.rx_username);
+			pj_strdup(pool, &dst->data.webrtc_cred.tx_username,
+				&src->data.webrtc_cred.tx_username);
+			break;
+		case PJ_STUN_AUTH_CRED_STATIC:
+			pj_strdup(pool, &dst->data.static_cred.realm,
+				&src->data.static_cred.realm);
+			pj_strdup(pool, &dst->data.static_cred.username,
+				&src->data.static_cred.username);
+			dst->data.static_cred.data_type = src->data.static_cred.data_type;
+			pj_strdup(pool, &dst->data.static_cred.data,
+				&src->data.static_cred.data);
+			pj_strdup(pool, &dst->data.static_cred.nonce,
+				&src->data.static_cred.nonce);
+			break;
+		case PJ_STUN_AUTH_CRED_DYNAMIC:
+			pj_memcpy(&dst->data.dyn_cred, &src->data.dyn_cred, 
+				sizeof(src->data.dyn_cred));
+			break;
+	}
 }
 
 
@@ -231,7 +237,7 @@
     pj_uint8_t digest[PJ_SHA1_DIGEST_SIZE];
     pj_stun_status err_code;
     const char *err_text = NULL;
-    pj_status_t status;
+    pj_status_t status;	
 
     /* msg and credential MUST be specified */
     PJ_ASSERT_RETURN(pkt && pkt_len && msg && cred, PJ_EINVAL);
@@ -252,7 +258,10 @@
 
     /* Get realm and nonce from credential */
     p_info->realm.slen = p_info->nonce.slen = 0;
-    if (cred->type == PJ_STUN_AUTH_CRED_STATIC) {
+	if(cred->type == PJ_STUN_AUTH_CRED_WEBRTC){
+		/* no realm or nonce for webrtc */
+	}
+    else if (cred->type == PJ_STUN_AUTH_CRED_STATIC) {
 	p_info->realm = cred->data.static_cred.realm;
 	p_info->nonce = cred->data.static_cred.nonce;
     } else if (cred->type == PJ_STUN_AUTH_CRED_DYNAMIC) {
@@ -318,7 +327,20 @@
     }
 
     /* Check if username match */
-    if (cred->type == PJ_STUN_AUTH_CRED_STATIC) {
+	if(cred->type == PJ_STUN_AUTH_CRED_WEBRTC){
+		pj_bool_t username_ok = !pj_strcmp(&auser->value, &cred->data.webrtc_cred.rx_username);
+		if (username_ok) {
+			pj_strdup(pool, &p_info->username, 
+				  &cred->data.webrtc_cred.rx_username);
+			//pj_stun_create_key(pool, &p_info->auth_key, &p_info->realm,
+			//		   &auser->value, cred->data.webrtc_cred.data_type,
+			//		   &cred->data.webrtc_cred.data);
+			// For webrtc do not check other fields
+			return PJ_SUCCESS;
+		}
+		err_code = PJ_STUN_SC_UNAUTHORIZED;
+	    goto on_auth_failed;
+	} else if (cred->type == PJ_STUN_AUTH_CRED_STATIC) {
 	pj_bool_t username_ok;
 	username_ok = !pj_strcmp(&auser->value, 
 				 &cred->data.static_cred.username);
Index: res/pjproject/pjnath/src/pjnath/turn_session.c
===================================================================
--- res/pjproject/pjnath/src/pjnath/turn_session.c	(revision 373380)
+++ res/pjproject/pjnath/src/pjnath/turn_session.c	(working copy)
@@ -421,7 +421,10 @@
 	/* This may recursively call this function again with
 	 * state==PJ_TURN_STATE_DEALLOCATED.
 	 */
+	/* No need to deallocate as we're already deallocating!
+	 * See https://trac.pjsip.org/repos/ticket/1551
 	send_refresh(sess, 0);
+	*/
 	break;
     case PJ_TURN_STATE_DEALLOCATED:
     case PJ_TURN_STATE_DESTROYING:
Index: res/pjproject/pjnath/src/pjnath/stun_session.c
===================================================================
--- res/pjproject/pjnath/src/pjnath/stun_session.c	(revision 373380)
+++ res/pjproject/pjnath/src/pjnath/stun_session.c	(working copy)
@@ -500,11 +500,9 @@
     pj_memcpy(&sess->cb, cb, sizeof(*cb));
     sess->use_fingerprint = fingerprint;
     sess->log_flag = 0xFFFF;
-    
-    sess->srv_name.ptr = (char*) pj_pool_alloc(pool, 32);
-    sess->srv_name.slen = pj_ansi_snprintf(sess->srv_name.ptr, 32,
-					   "pjnath-%s", pj_get_version());
 
+    pj_stun_session_set_software_name(sess, &cfg->software_name);
+
     sess->rx_pool = pj_pool_create(sess->cfg->pf, name, 
 				   PJNATH_POOL_LEN_STUN_TDATA, 
 				   PJNATH_POOL_INC_STUN_TDATA, NULL);
@@ -657,7 +655,10 @@
 static pj_status_t get_auth(pj_stun_session *sess,
 			    pj_stun_tx_data *tdata)
 {
-    if (sess->cred.type == PJ_STUN_AUTH_CRED_STATIC) {
+	if(sess->cred.type == PJ_STUN_AUTH_CRED_WEBRTC){
+		tdata->auth_info.username = sess->cred.data.webrtc_cred.tx_username;
+	}
+    else if (sess->cred.type == PJ_STUN_AUTH_CRED_STATIC) {
 	//tdata->auth_info.realm = sess->cred.data.static_cred.realm;
 	tdata->auth_info.realm = sess->server_realm;
 	tdata->auth_info.username = sess->cred.data.static_cred.username;
@@ -728,9 +729,9 @@
     
     /* Get authentication information for the request */
     if (sess->auth_type == PJ_STUN_AUTH_NONE) {
-	/* No authentication */
+	/* No authentication or chrome auth */
 
-    } else if (sess->auth_type == PJ_STUN_AUTH_SHORT_TERM) {
+    } else if (sess->auth_type == PJ_STUN_AUTH_SHORT_TERM || sess->auth_type == PJ_STUN_AUTH_WEBRTC) {
 	/* MUST put authentication in request */
 	status = get_auth(sess, tdata);
 	if (status != PJ_SUCCESS) {
@@ -821,6 +822,14 @@
     /* copy the credential found in the request */
     pj_stun_req_cred_info_dup(tdata->pool, &tdata->auth_info, &rdata->info);
 
+	/* Add USERNAME */
+	if(sess->cred.type == PJ_STUN_AUTH_CRED_WEBRTC){
+		status = pj_stun_msg_add_string_attr(tdata->pool, tdata->msg,
+					     PJ_STUN_ATTR_USERNAME,
+						 &sess->cred.data.webrtc_cred.rx_username);
+		PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
+	}
+
     *p_tdata = tdata;
 
     return PJ_SUCCESS;
@@ -1138,11 +1147,17 @@
     {
 	return PJ_SUCCESS;
     }
-
+	
     status = pj_stun_authenticate_request(pkt, pkt_len, rdata->msg, 
 					  &sess->cred, tmp_pool, &rdata->info,
 					  &response);
     if (status != PJ_SUCCESS && response != NULL) {
+		if(sess->cred.type == PJ_STUN_AUTH_CRED_WEBRTC){
+			// Fix for http://code.google.com/p/sipml5/issues/detail?id=36
+			// Do not send error to chrome
+			return (!sess->cred.data.webrtc_cred.rx_username.slen || !sess->cred.data.webrtc_cred.tx_username.slen) ? PJ_STUN_ERROR_WEBRTC_NOTREADY : PJ_SUCCESS;
+		}
+		
 	PJ_LOG(5,(SNAME(sess), "Message authentication failed"));
 	send_response(sess, token, tmp_pool, response, &rdata->info, 
 		      PJ_FALSE, src_addr, src_addr_len);
@@ -1174,7 +1189,7 @@
 
     if (sess->auth_type == PJ_STUN_AUTH_NONE)
 	options |= PJ_STUN_NO_AUTHENTICATE;
-
+	
     /* Authenticate the message, unless PJ_STUN_NO_AUTHENTICATE
      * is specified in the option.
      */
@@ -1261,7 +1276,7 @@
 
     if (sess->auth_type == PJ_STUN_AUTH_NONE)
 	options |= PJ_STUN_NO_AUTHENTICATE;
-
+	
     /* Authenticate the message, unless PJ_STUN_NO_AUTHENTICATE
      * is specified in the option.
      */
@@ -1434,3 +1449,7 @@
     return status;
 }
 
+enum pj_stun_auth_type pj_stun_session_get_auth_type(pj_stun_session *sess)
+{
+	return sess->auth_type;
+}
\ No newline at end of file
Index: res/res_rtp_asterisk.c
===================================================================
--- res/res_rtp_asterisk.c	(revision 373380)
+++ res/res_rtp_asterisk.c	(working copy)
@@ -40,12 +40,6 @@
 #include <signal.h>
 #include <fcntl.h>
 
-#ifdef HAVE_OPENSSL_SRTP
-#include <openssl/ssl.h>
-#include <openssl/err.h>
-#include <openssl/bio.h>
-#endif
-
 /* Asterisk discourages the use of bzero in favor of memset, in fact if you try to use bzero it will tell you to use memset. As a result bzero has to be undefined
  * here since it is used internally by pjlib. The only other option would be to modify pjlib... which won't happen. */
 #undef bzero
@@ -91,7 +85,18 @@
 #define RTCP_PT_SDES    202
 #define RTCP_PT_BYE     203
 #define RTCP_PT_APP     204
+#define RTCP_PT_RTPFB	205
+#define RTCP_PT_PSFB	206
 
+#define RTCP_PT_PSFB_PLI	1 /* rfc 4585: Picture Loss Indication (PLI) */
+#define RTCP_PT_PSFB_SLI	2 /* rfc 4585: Slice Loss Indication (SLI) */
+#define RTCP_PT_PSFB_RPSI	3 /* rfc 4585: Reference Picture Selection Indication (RPSI) */
+#define RTCP_PT_PSFB_FIR	4 /* rfc 5104: Full Intra Request (FIR) Command*/
+#define RTCP_PT_PSFB_AFB	15 /* rfc 4585: Application layer FB (AFB) message */
+
+#define RTCP_PT_RTPFB_NACK	1 /* RFC 4585 */
+#define RTCP_PT_RTPFB_TMMBN 4 /* RFC 5104 */
+
 #define RTP_MTU		1200
 
 #define DEFAULT_DTMF_TIMEOUT (150 * (8000 / 1000))	/*!< samples */
@@ -100,10 +105,6 @@
 
 #define DEFAULT_LEARNING_MIN_SEQUENTIAL 4
 
-#define SRTP_MASTER_KEY_LEN 16
-#define SRTP_MASTER_SALT_LEN 14
-#define SRTP_MASTER_LEN (SRTP_MASTER_KEY_LEN + SRTP_MASTER_SALT_LEN)
-
 enum strict_rtp_state {
 	STRICT_RTP_OPEN = 0, /*! No RTP packets should be dropped, all sources accepted */
 	STRICT_RTP_LEARN,    /*! Accept next packet as source */
@@ -114,8 +115,6 @@
 #define DEFAULT_ICESUPPORT 1
 
 extern struct ast_srtp_res *res_srtp;
-extern struct ast_srtp_policy_res *res_srtp_policy;
-
 static int dtmftimeout = DEFAULT_DTMF_TIMEOUT;
 
 static int rtpstart = DEFAULT_RTP_START;			/*!< First port for RTP sessions (set in rtp.conf) */
@@ -265,21 +264,6 @@
 
 	struct ao2_container *local_candidates;   /*!< The local ICE candidates */
 	struct ao2_container *remote_candidates;  /*!< The remote ICE candidates */
-
-#ifdef HAVE_OPENSSL_SRTP
-	SSL_CTX *ssl_ctx; /*!< SSL context */
-	SSL *ssl;         /*!< SSL session */
-	BIO *read_bio;    /*!< Memory buffer for reading */
-	BIO *write_bio;   /*!< Memory buffer for writing */
-	enum ast_rtp_dtls_setup dtls_setup; /*!< Current setup state */
-	enum ast_srtp_suite suite;   /*!< SRTP crypto suite */
-	char local_fingerprint[160]; /*!< Fingerprint of our certificate */
-	unsigned char remote_fingerprint[EVP_MAX_MD_SIZE]; /*!< Fingerprint of the peer certificate */
-	enum ast_rtp_dtls_connection connection; /*!< Whether this is a new or existing connection */
-	unsigned int dtls_failure:1; /*!< Failure occurred during DTLS negotiation */
-	unsigned int rekey; /*!< Interval at which to renegotiate and rekey */
-	int rekeyid; /*!< Scheduled item id for rekeying */
-#endif
 };
 
 /*!
@@ -385,13 +369,8 @@
 static void ast_rtp_stop(struct ast_rtp_instance *instance);
 static int ast_rtp_qos_set(struct ast_rtp_instance *instance, int tos, int cos, const char* desc);
 static int ast_rtp_sendcng(struct ast_rtp_instance *instance, int level);
+static int ast_rtcpfb(struct ast_rtp_instance *instance, void* data, unsigned int len);
 
-#ifdef HAVE_OPENSSL_SRTP
-static int ast_rtp_activate(struct ast_rtp_instance *instance);
-#endif
-
-static int __rtp_sendto(struct ast_rtp_instance *instance, void *buf, size_t size, int flags, struct ast_sockaddr *sa, int rtcp, int *ice, int use_srtp);
-
 /*! \brief Destructor for locally created ICE candidates */
 static void ast_rtp_ice_candidate_destroy(void *obj)
 {
@@ -444,6 +423,7 @@
 	ast_sockaddr_copy(&remote_candidate->address, &candidate->address);
 	ast_sockaddr_copy(&remote_candidate->relay_address, &candidate->relay_address);
 	remote_candidate->type = candidate->type;
+	remote_candidate->is_webrtc = candidate->is_webrtc;
 
 	ao2_link(rtp->remote_candidates, remote_candidate);
 	ao2_ref(remote_candidate, -1);
@@ -495,6 +475,7 @@
 	struct ao2_iterator i;
 	struct ast_rtp_engine_ice_candidate *candidate;
 	int cand_cnt = 0;
+	int is_webrtc = 0;
 
 	if (!rtp->ice || !rtp->remote_candidates || rtp->ice_started) {
 		return;
@@ -531,11 +512,31 @@
 			pj_turn_sock_set_perm(rtp->turn_rtcp, 1, &candidates[cand_cnt].addr, 1);
 		}
 
+		// WebRTC candidates if at least one candidate is marked as it
+		if(candidate->is_webrtc){
+			is_webrtc = 1;
+		}
+
 		cand_cnt++;
 	}
 
 	ao2_iterator_destroy(&i);
+	
+	// WebRTC option is enabled by default and have to be disabled if not needed
+	{
+		pj_status_t status;
+		pj_ice_sess_options opt;
 
+		status = pj_ice_sess_get_options(rtp->ice, &opt);
+		if(status == PJ_SUCCESS){
+			opt.is_webrtc = is_webrtc;
+			status = pj_ice_sess_set_options(rtp->ice, &opt);
+			if(status != PJ_SUCCESS){
+				// Print Error message
+			}
+		}
+	}
+
 	if (pj_ice_sess_create_check_list(rtp->ice, &ufrag, &passwd, ao2_container_count(rtp->remote_candidates), &candidates[0]) == PJ_SUCCESS) {
 		pj_ice_sess_start_check(rtp->ice);
 		pj_timer_heap_poll(timerheap, NULL);
@@ -690,305 +691,6 @@
 	.ice_lite = ast_rtp_ice_lite,
 };
 
-#ifdef HAVE_OPENSSL_SRTP
-static void dtls_info_callback(const SSL *ssl, int where, int ret)
-{
-	struct ast_rtp *rtp = SSL_get_ex_data(ssl, 0);
-
-	/* We only care about alerts */
-	if (!(where & SSL_CB_ALERT)) {
-		return;
-	}
-
-	rtp->dtls_failure = 1;
-}
-
-static int ast_rtp_dtls_set_configuration(struct ast_rtp_instance *instance, const struct ast_rtp_dtls_cfg *dtls_cfg)
-{
-	struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
-
-	if (!dtls_cfg->enabled) {
-		return 0;
-	}
-
-	if (!ast_rtp_engine_srtp_is_registered()) {
-		return -1;
-	}
-
-	if (!(rtp->ssl_ctx = SSL_CTX_new(DTLSv1_method()))) {
-		return -1;
-	}
-
-	SSL_CTX_set_verify(rtp->ssl_ctx, dtls_cfg->verify ? SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT : SSL_VERIFY_NONE, NULL);
-
-	if (dtls_cfg->suite == AST_AES_CM_128_HMAC_SHA1_80) {
-		SSL_CTX_set_tlsext_use_srtp(rtp->ssl_ctx, "SRTP_AES128_CM_SHA1_80");
-	} else if (dtls_cfg->suite == AST_AES_CM_128_HMAC_SHA1_32) {
-		SSL_CTX_set_tlsext_use_srtp(rtp->ssl_ctx, "SRTP_AES128_CM_SHA1_32");
-	} else {
-		ast_log(LOG_ERROR, "Unsupported suite specified for DTLS-SRTP on RTP instance '%p'\n", instance);
-		goto error;
-	}
-
-	if (!ast_strlen_zero(dtls_cfg->certfile)) {
-		char *private = ast_strlen_zero(dtls_cfg->pvtfile) ? dtls_cfg->certfile : dtls_cfg->pvtfile;
-		BIO *certbio;
-		X509 *cert;
-		unsigned int size, i;
-		unsigned char fingerprint[EVP_MAX_MD_SIZE];
-		char *local_fingerprint = rtp->local_fingerprint;
-
-		if (!SSL_CTX_use_certificate_file(rtp->ssl_ctx, dtls_cfg->certfile, SSL_FILETYPE_PEM)) {
-			ast_log(LOG_ERROR, "Specified certificate file '%s' for RTP instance '%p' could not be used\n",
-				dtls_cfg->certfile, instance);
-			goto error;
-		}
-
-		if (!SSL_CTX_use_PrivateKey_file(rtp->ssl_ctx, private, SSL_FILETYPE_PEM) ||
-		    !SSL_CTX_check_private_key(rtp->ssl_ctx)) {
-			ast_log(LOG_ERROR, "Specified private key file '%s' for RTP instance '%p' could not be used\n",
-				private, instance);
-			goto error;
-		}
-
-		if (!(certbio = BIO_new(BIO_s_file()))) {
-			ast_log(LOG_ERROR, "Failed to allocate memory for certificate fingerprinting on RTP instance '%p'\n",
-				instance);
-			goto error;
-		}
-
-		if (!BIO_read_filename(certbio, dtls_cfg->certfile) ||
-		    !(cert = PEM_read_bio_X509(certbio, NULL, 0, NULL)) ||
-		    !X509_digest(cert, EVP_sha1(), fingerprint, &size) ||
-		    !size) {
-			ast_log(LOG_ERROR, "Could not produce fingerprint from certificate '%s' for RTP instance '%p'\n",
-				dtls_cfg->certfile, instance);
-			BIO_free_all(certbio);
-			goto error;
-		}
-
-		for (i = 0; i < size; i++) {
-			sprintf(local_fingerprint, "%.2X:", fingerprint[i]);
-			local_fingerprint += 3;
-		}
-
-		*(local_fingerprint-1) = 0;
-
-		BIO_free_all(certbio);
-	}
-
-	if (!ast_strlen_zero(dtls_cfg->cipher)) {
-		if (!SSL_CTX_set_cipher_list(rtp->ssl_ctx, dtls_cfg->cipher)) {
-			ast_log(LOG_ERROR, "Invalid cipher specified in cipher list '%s' for RTP instance '%p'\n",
-				dtls_cfg->cipher, instance);
-			goto error;
-		}
-	}
-
-	if (!ast_strlen_zero(dtls_cfg->cafile) || !ast_strlen_zero(dtls_cfg->capath)) {
-		if (!SSL_CTX_load_verify_locations(rtp->ssl_ctx, S_OR(dtls_cfg->cafile, NULL), S_OR(dtls_cfg->capath, NULL))) {
-			ast_log(LOG_ERROR, "Invalid certificate authority file '%s' or path '%s' specified for RTP instance '%p'\n",
-				S_OR(dtls_cfg->cafile, ""), S_OR(dtls_cfg->capath, ""), instance);
-			goto error;
-		}
-	}
-
-	rtp->rekey = dtls_cfg->rekey;
-	rtp->dtls_setup = dtls_cfg->default_setup;
-	rtp->suite = dtls_cfg->suite;
-
-	if (!(rtp->ssl = SSL_new(rtp->ssl_ctx))) {
-		ast_log(LOG_ERROR, "Failed to allocate memory for SSL context on RTP instance '%p'\n",
-			instance);
-		goto error;
-	}
-
-	SSL_set_ex_data(rtp->ssl, 0, rtp);
-	SSL_set_info_callback(rtp->ssl, dtls_info_callback);
-
-	if (!(rtp->read_bio = BIO_new(BIO_s_mem()))) {
-		ast_log(LOG_ERROR, "Failed to allocate memory for inbound SSL traffic on RTP instance '%p'\n",
-			instance);
-		goto error;
-	}
-	BIO_set_mem_eof_return(rtp->read_bio, -1);
-
-	if (!(rtp->write_bio = BIO_new(BIO_s_mem()))) {
-		ast_log(LOG_ERROR, "Failed to allocate memory for outbound SSL traffic on RTP instance '%p'\n",
-			instance);
-		goto error;
-	}
-	BIO_set_mem_eof_return(rtp->write_bio, -1);
-
-	SSL_set_bio(rtp->ssl, rtp->read_bio, rtp->write_bio);
-
-	if (rtp->dtls_setup == AST_RTP_DTLS_SETUP_PASSIVE) {
-		SSL_set_accept_state(rtp->ssl);
-	} else {
-		SSL_set_connect_state(rtp->ssl);
-	}
-
-	rtp->connection = AST_RTP_DTLS_CONNECTION_NEW;
-
-	return 0;
-
-error:
-	if (rtp->read_bio) {
-		BIO_free(rtp->read_bio);
-		rtp->read_bio = NULL;
-	}
-
-	if (rtp->write_bio) {
-		BIO_free(rtp->write_bio);
-		rtp->write_bio = NULL;
-	}
-
-	if (rtp->ssl) {
-		SSL_free(rtp->ssl);
-		rtp->ssl = NULL;
-	}
-
-	SSL_CTX_free(rtp->ssl_ctx);
-	rtp->ssl_ctx = NULL;
-
-	return -1;
-}
-
-static int ast_rtp_dtls_active(struct ast_rtp_instance *instance)
-{
-	struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
-
-	return !rtp->ssl_ctx ? 0 : 1;
-}
-
-static void ast_rtp_dtls_stop(struct ast_rtp_instance *instance)
-{
-	struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
-
-	if (rtp->ssl_ctx) {
-		SSL_CTX_free(rtp->ssl_ctx);
-		rtp->ssl_ctx = NULL;
-	}
-
-	if (rtp->ssl) {
-		SSL_free(rtp->ssl);
-		rtp->ssl = NULL;
-	}
-}
-
-static void ast_rtp_dtls_reset(struct ast_rtp_instance *instance)
-{
-	struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
-
-	/* If the SSL session is not yet finalized don't bother resetting */
-	if (!SSL_is_init_finished(rtp->ssl)) {
-		return;
-	}
-
-	SSL_shutdown(rtp->ssl);
-	rtp->connection = AST_RTP_DTLS_CONNECTION_NEW;
-}
-
-static enum ast_rtp_dtls_connection ast_rtp_dtls_get_connection(struct ast_rtp_instance *instance)
-{
-	struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
-
-	return rtp->connection;
-}
-
-static enum ast_rtp_dtls_setup ast_rtp_dtls_get_setup(struct ast_rtp_instance *instance)
-{
-	struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
-
-	return rtp->dtls_setup;
-}
-
-static void ast_rtp_dtls_set_setup(struct ast_rtp_instance *instance, enum ast_rtp_dtls_setup setup)
-{
-	struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
-	enum ast_rtp_dtls_setup old = rtp->dtls_setup;
-
-	switch (setup) {
-	case AST_RTP_DTLS_SETUP_ACTIVE:
-		rtp->dtls_setup = AST_RTP_DTLS_SETUP_PASSIVE;
-		break;
-	case AST_RTP_DTLS_SETUP_PASSIVE:
-		rtp->dtls_setup = AST_RTP_DTLS_SETUP_ACTIVE;
-		break;
-	case AST_RTP_DTLS_SETUP_ACTPASS:
-		/* We can't respond to an actpass setup with actpass ourselves... so respond with active, as we can initiate connections */
-		if (rtp->dtls_setup == AST_RTP_DTLS_SETUP_ACTPASS) {
-			rtp->dtls_setup = AST_RTP_DTLS_SETUP_ACTIVE;
-		}
-		break;
-	case AST_RTP_DTLS_SETUP_HOLDCONN:
-		rtp->dtls_setup = AST_RTP_DTLS_SETUP_HOLDCONN;
-		break;
-	default:
-		/* This should never occur... if it does exit early as we don't know what state things are in */
-		return;
-	}
-
-	/* If the setup state did not change we go on as if nothing happened */
-	if (old == rtp->dtls_setup) {
-		return;
-	}
-
-	/* If they don't want us to establish a connection wait until later */
-	if (rtp->dtls_setup == AST_RTP_DTLS_SETUP_HOLDCONN) {
-		return;
-	}
-
-	if (rtp->dtls_setup == AST_RTP_DTLS_SETUP_ACTIVE) {
-		SSL_set_connect_state(rtp->ssl);
-	} else if (rtp->dtls_setup == AST_RTP_DTLS_SETUP_PASSIVE) {
-		SSL_set_accept_state(rtp->ssl);
-	} else {
-		return;
-	}
-}
-
-static void ast_rtp_dtls_set_fingerprint(struct ast_rtp_instance *instance, enum ast_rtp_dtls_hash hash, const char *fingerprint)
-{
-	char *tmp = ast_strdupa(fingerprint), *value;
-	int pos = 0;
-	struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
-
-	if (hash != AST_RTP_DTLS_HASH_SHA1) {
-		return;
-	}
-
-	while ((value = strsep(&tmp, ":")) && (pos != (EVP_MAX_MD_SIZE - 1))) {
-		sscanf(value, "%02x", (unsigned int*)&rtp->remote_fingerprint[pos++]);
-	}
-}
-
-static const char *ast_rtp_dtls_get_fingerprint(struct ast_rtp_instance *instance, enum ast_rtp_dtls_hash hash)
-{
-	struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
-
-	if (hash != AST_RTP_DTLS_HASH_SHA1) {
-		return NULL;
-	}
-
-	return rtp->local_fingerprint;
-}
-
-/* DTLS RTP Engine interface declaration */
-static struct ast_rtp_engine_dtls ast_rtp_dtls = {
-	.set_configuration = ast_rtp_dtls_set_configuration,
-	.active = ast_rtp_dtls_active,
-	.stop = ast_rtp_dtls_stop,
-	.reset = ast_rtp_dtls_reset,
-	.get_connection = ast_rtp_dtls_get_connection,
-	.get_setup = ast_rtp_dtls_get_setup,
-	.set_setup = ast_rtp_dtls_set_setup,
-	.set_fingerprint = ast_rtp_dtls_set_fingerprint,
-	.get_fingerprint = ast_rtp_dtls_get_fingerprint,
-};
-
-#endif
-
 /* RTP Engine Declaration */
 static struct ast_rtp_engine asterisk_rtp_engine = {
 	.name = "asterisk",
@@ -1016,11 +718,8 @@
 	.stop = ast_rtp_stop,
 	.qos = ast_rtp_qos_set,
 	.sendcng = ast_rtp_sendcng,
+	.rtcpfb = ast_rtcpfb,
 	.ice = &ast_rtp_ice,
-#ifdef HAVE_OPENSSL_SRTP
-	.dtls = &ast_rtp_dtls,
-	.activate = ast_rtp_activate,
-#endif
 };
 
 static void ast_rtp_on_ice_rx_data(pj_ice_sess *ice, unsigned comp_id, unsigned transport_id, void *pkt, pj_size_t size, const pj_sockaddr_t *src_addr, unsigned src_addr_len)
@@ -1036,19 +735,14 @@
 {
 	struct ast_rtp *rtp = ice->user_data;
 	pj_status_t status = PJ_EINVALIDOP;
-	pj_ssize_t _size = (pj_ssize_t)size;
 
 	if (transport_id == TRANSPORT_SOCKET_RTP) {
 		/* Traffic is destined to go right out the RTP socket we already have */
-		status = pj_sock_sendto(rtp->s, pkt, &_size, 0, dst_addr, dst_addr_len);
-		/* sendto on a connectionless socket should send all the data, or none at all */
-		ast_assert(_size == size || status != PJ_SUCCESS);
+		status = pj_sock_sendto(rtp->s, pkt, (pj_ssize_t*)&size, 0, dst_addr, dst_addr_len);
 	} else if (transport_id == TRANSPORT_SOCKET_RTCP) {
 		/* Traffic is destined to go right out the RTCP socket we already have */
 		if (rtp->rtcp) {
-			status = pj_sock_sendto(rtp->rtcp->s, pkt, &_size, 0, dst_addr, dst_addr_len);
-			/* sendto on a connectionless socket should send all the data, or none at all */
-			ast_assert(_size == size || status != PJ_SUCCESS);
+			status = pj_sock_sendto(rtp->rtcp->s, pkt, (pj_ssize_t*)&size, 0, dst_addr, dst_addr_len);
 		} else {
 			status = PJ_SUCCESS;
 		}
@@ -1210,228 +904,28 @@
 	return 1;
 }
 
-#ifdef HAVE_OPENSSL_SRTP
-static void dtls_srtp_check_pending(struct ast_rtp_instance *instance, struct ast_rtp *rtp)
-{
-	size_t pending = BIO_ctrl_pending(rtp->write_bio);
-
-	if (pending > 0) {
-		char outgoing[pending];
-		size_t out;
-		struct ast_sockaddr remote_address = { {0, } };
-		int ice;
-
-		ast_rtp_instance_get_remote_address(instance, &remote_address);
-
-		/* If we do not yet know an address to send this to defer it until we do */
-		if (ast_sockaddr_isnull(&remote_address)) {
-			return;
-		}
-
-		out = BIO_read(rtp->write_bio, outgoing, sizeof(outgoing));
-
-		__rtp_sendto(instance, outgoing, out, 0, &remote_address, 0, &ice, 0);
-	}
-}
-
-static int dtls_srtp_renegotiate(const void *data)
-{
-	struct ast_rtp_instance *instance = (struct ast_rtp_instance *)data;
-	struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
-
-	SSL_renegotiate(rtp->ssl);
-	SSL_do_handshake(rtp->ssl);
-	dtls_srtp_check_pending(instance, rtp);
-
-	rtp->rekeyid = -1;
-	ao2_ref(instance, -1);
-
-	return 0;
-}
-
-static int dtls_srtp_setup(struct ast_rtp *rtp, struct ast_srtp *srtp, struct ast_rtp_instance *instance)
-{
-	unsigned char material[SRTP_MASTER_LEN * 2];
-	unsigned char *local_key, *local_salt, *remote_key, *remote_salt;
-	struct ast_srtp_policy *local_policy, *remote_policy = NULL;
-	struct ast_rtp_instance_stats stats = { 0, };
-
-	/* If a fingerprint is present in the SDP make sure that the peer certificate matches it */
-	if (SSL_CTX_get_verify_mode(rtp->ssl_ctx) != SSL_VERIFY_NONE) {
-		X509 *certificate;
-
-		if (!(certificate = SSL_get_peer_certificate(rtp->ssl))) {
-			ast_log(LOG_WARNING, "No certificate was provided by the peer on RTP instance '%p'\n", instance);
-			return -1;
-		}
-
-		/* If a fingerprint is present in the SDP make sure that the peer certificate matches it */
-		if (rtp->remote_fingerprint[0]) {
-			unsigned char fingerprint[EVP_MAX_MD_SIZE];
-			unsigned int size;
-
-			if (!X509_digest(certificate, EVP_sha1(), fingerprint, &size) ||
-			    !size ||
-			    memcmp(fingerprint, rtp->remote_fingerprint, size)) {
-				X509_free(certificate);
-				ast_log(LOG_WARNING, "Fingerprint provided by remote party does not match that of peer certificate on RTP instance '%p'\n",
-					instance);
-				return -1;
-			}
-		}
-
-		X509_free(certificate);
-	}
-
-	/* Ensure that certificate verification was successful */
-	if (SSL_get_verify_result(rtp->ssl) != X509_V_OK) {
-		ast_log(LOG_WARNING, "Peer certificate on RTP instance '%p' failed verification test\n",
-			instance);
-		return -1;
-	}
-
-	/* Produce key information and set up SRTP */
-	if (!SSL_export_keying_material(rtp->ssl, material, SRTP_MASTER_LEN * 2, "EXTRACTOR-dtls_srtp", 19, NULL, 0, 0)) {
-		ast_log(LOG_WARNING, "Unable to extract SRTP keying material from DTLS-SRTP negotiation on RTP instance '%p'\n",
-			instance);
-		return -1;
-	}
-
-	/* Whether we are acting as a server or client determines where the keys/salts are */
-	if (rtp->dtls_setup == AST_RTP_DTLS_SETUP_ACTIVE) {
-		local_key = material;
-		remote_key = local_key + SRTP_MASTER_KEY_LEN;
-		local_salt = remote_key + SRTP_MASTER_KEY_LEN;
-		remote_salt = local_salt + SRTP_MASTER_SALT_LEN;
-	} else {
-		remote_key = material;
-		local_key = remote_key + SRTP_MASTER_KEY_LEN;
-		remote_salt = local_key + SRTP_MASTER_KEY_LEN;
-		local_salt = remote_salt + SRTP_MASTER_SALT_LEN;
-	}
-
-	if (!(local_policy = res_srtp_policy->alloc())) {
-		return -1;
-	}
-
-	if (res_srtp_policy->set_master_key(local_policy, local_key, SRTP_MASTER_KEY_LEN, local_salt, SRTP_MASTER_SALT_LEN) < 0) {
-		ast_log(LOG_WARNING, "Could not set key/salt information on local policy of '%p' when setting up DTLS-SRTP\n", rtp);
-		goto error;
-	}
-
-	if (res_srtp_policy->set_suite(local_policy, rtp->suite)) {
-		ast_log(LOG_WARNING, "Could not set suite to '%d' on local policy of '%p' when setting up DTLS-SRTP\n", rtp->suite, rtp);
-		goto error;
-	}
-
-	if (ast_rtp_instance_get_stats(instance, &stats, AST_RTP_INSTANCE_STAT_LOCAL_SSRC)) {
-		goto error;
-	}
-
-	res_srtp_policy->set_ssrc(local_policy, stats.local_ssrc, 0);
-
-	if (!(remote_policy = res_srtp_policy->alloc())) {
-		goto error;
-	}
-
-	if (res_srtp_policy->set_master_key(remote_policy, remote_key, SRTP_MASTER_KEY_LEN, remote_salt, SRTP_MASTER_SALT_LEN) < 0) {
-		ast_log(LOG_WARNING, "Could not set key/salt information on remote policy of '%p' when setting up DTLS-SRTP\n", rtp);
-		goto error;
-	}
-
-	if (res_srtp_policy->set_suite(remote_policy, rtp->suite)) {
-		ast_log(LOG_WARNING, "Could not set suite to '%d' on remote policy of '%p' when setting up DTLS-SRTP\n", rtp->suite, rtp);
-		goto error;
-	}
-
-	res_srtp_policy->set_ssrc(remote_policy, 0, 1);
-
-	if (ast_rtp_instance_add_srtp_policy(instance, remote_policy, local_policy)) {
-		ast_log(LOG_WARNING, "Could not set policies when setting up DTLS-SRTP on '%p'\n", rtp);
-		goto error;
-	}
-
-	if (rtp->rekey) {
-		ao2_ref(instance, +1);
-		if ((rtp->rekeyid = ast_sched_add(rtp->sched, rtp->rekey * 1000, dtls_srtp_renegotiate, instance)) < 0) {
-			ao2_ref(instance, -1);
-			goto error;
-		}
-	}
-
-	return 0;
-
-error:
-	res_srtp_policy->destroy(local_policy);
-
-	if (remote_policy) {
-		res_srtp_policy->destroy(remote_policy);
-	}
-
-	return -1;
-}
-#endif
-
 static int __rtp_recvfrom(struct ast_rtp_instance *instance, void *buf, size_t size, int flags, struct ast_sockaddr *sa, int rtcp)
 {
 	int len;
 	struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
 	struct ast_srtp *srtp = ast_rtp_instance_get_srtp(instance);
+	const unsigned char* buf_ptr = (const unsigned char*)buf;
+	int is_muxed_rtcp = 0;
 
+	if(!rtcp && size >= 2 && (buf_ptr[1] & 0x80)){
+		// RFC 5761
+		switch((buf_ptr[1] & 0x7F)){
+			case 64: case 65: 
+			case 72: case 73: case 74: case 75: case 76:
+			case 77: case 78:
+			case 79: is_muxed_rtcp = 1; break;
+		}
+	}
+
 	if ((len = ast_recvfrom(rtcp ? rtp->rtcp->s : rtp->s, buf, size, flags, sa)) < 0) {
 	   return len;
 	}
 
-#ifdef HAVE_OPENSSL_SRTP
-	if (!rtcp) {
-		char *in = buf;
-
-		dtls_srtp_check_pending(instance, rtp);
-
-		/* If this is an SSL packet pass it to OpenSSL for processing */
-		if ((*in >= 20) && (*in <= 64)) {
-			int res = 0;
-
-			/* If no SSL session actually exists terminate things */
-			if (!rtp->ssl) {
-				ast_log(LOG_ERROR, "Received SSL traffic on RTP instance '%p' without an SSL session\n",
-					instance);
-				return -1;
-			}
-
-			/* If we don't yet know if we are active or passive and we receive a packet... we are obviously passive */
-			if (rtp->dtls_setup == AST_RTP_DTLS_SETUP_ACTPASS) {
-				rtp->dtls_setup = AST_RTP_DTLS_SETUP_PASSIVE;
-				SSL_set_accept_state(rtp->ssl);
-			}
-
-			dtls_srtp_check_pending(instance, rtp);
-
-			BIO_write(rtp->read_bio, buf, len);
-
-			len = SSL_read(rtp->ssl, buf, len);
-
-			dtls_srtp_check_pending(instance, rtp);
-
-			if (rtp->dtls_failure) {
-				ast_log(LOG_ERROR, "DTLS failure occurred on RTP instance '%p', terminating\n",
-					instance);
-				return -1;
-			}
-
-			if (SSL_is_init_finished(rtp->ssl)) {
-				/* Any further connections will be existing since this is now established */
-				rtp->connection = AST_RTP_DTLS_CONNECTION_EXISTING;
-
-				/* Use the keying material to set up key/salt information */
-				res = dtls_srtp_setup(rtp, srtp, instance);
-			}
-
-			return res;
-		}
-	}
-#endif
-
 	if (rtp->ice) {
 		pj_str_t combined = pj_str(ast_sockaddr_stringify(sa));
 		pj_sockaddr address;
@@ -1444,7 +938,7 @@
 		status = pj_ice_sess_on_rx_pkt(rtp->ice, rtcp ? COMPONENT_RTCP : COMPONENT_RTP,
 			rtcp ? TRANSPORT_SOCKET_RTCP : TRANSPORT_SOCKET_RTP, buf, len, &address,
 			pj_sockaddr_get_len(&address));
-		if (status != PJ_SUCCESS) {
+		if (status != PJ_SUCCESS && status != PJ_STUN_ERROR_WEBRTC_NOTREADY) {
 			char buf[100];
 
 			pj_strerror(status, buf, sizeof(buf));
@@ -1458,7 +952,7 @@
 		rtp->passthrough = 0;
 	}
 
-	if (res_srtp && srtp && res_srtp->unprotect(srtp, buf, &len, rtcp) < 0) {
+	if (res_srtp && srtp && res_srtp->unprotect(srtp, buf, &len, (rtcp || is_muxed_rtcp)) < 0) {
 	   return -1;
 	}
 
@@ -1475,7 +969,7 @@
 	return __rtp_recvfrom(instance, buf, size, flags, sa, 0);
 }
 
-static int __rtp_sendto(struct ast_rtp_instance *instance, void *buf, size_t size, int flags, struct ast_sockaddr *sa, int rtcp, int *ice, int use_srtp)
+static int __rtp_sendto(struct ast_rtp_instance *instance, void *buf, size_t size, int flags, struct ast_sockaddr *sa, int rtcp, int *ice)
 {
 	int len = size;
 	void *temp = buf;
@@ -1484,7 +978,7 @@
 
 	*ice = 0;
 
-	if (use_srtp && res_srtp && srtp && res_srtp->protect(srtp, &temp, &len, rtcp) < 0) {
+	if (res_srtp && srtp && res_srtp->protect(srtp, &temp, &len, rtcp) < 0) {
 		return -1;
 	}
 
@@ -1502,12 +996,12 @@
 
 static int rtcp_sendto(struct ast_rtp_instance *instance, void *buf, size_t size, int flags, struct ast_sockaddr *sa, int *ice)
 {
-	return __rtp_sendto(instance, buf, size, flags, sa, 1, ice, 1);
+	return __rtp_sendto(instance, buf, size, flags, sa, 1, ice);
 }
 
 static int rtp_sendto(struct ast_rtp_instance *instance, void *buf, size_t size, int flags, struct ast_sockaddr *sa, int *ice)
 {
-	return __rtp_sendto(instance, buf, size, flags, sa, 0, ice, 1);
+	return __rtp_sendto(instance, buf, size, flags, sa, 0, ice);
 }
 
 static int rtp_get_rate(struct ast_format *format)
@@ -1771,10 +1265,6 @@
 	/* Record any information we may need */
 	rtp->sched = sched;
 
-#ifdef HAVE_OPENSSL_SRTP
-	rtp->rekeyid = -1;
-#endif
-
 	return 0;
 }
 
@@ -1837,18 +1327,6 @@
 		ao2_ref(rtp->remote_candidates, -1);
 	}
 
-#ifdef HAVE_OPENSSL_SRTP
-	/* Destroy the SSL context if present */
-	if (rtp->ssl_ctx) {
-		SSL_CTX_free(rtp->ssl_ctx);
-	}
-
-	/* Destroy the SSL session if present */
-	if (rtp->ssl) {
-		SSL_free(rtp->ssl);
-	}
-#endif
-
 	/* Destroy synchronization items */
 	ast_mutex_destroy(&rtp->lock);
 	ast_cond_destroy(&rtp->cond);
@@ -2143,7 +1621,7 @@
 }
 
 /*! \brief Send RTCP recipient's report */
-static int ast_rtcp_write_rr(struct ast_rtp_instance *instance)
+static int ast_rtcp_write_rr(struct ast_rtp_instance *instance, void* xdata, unsigned int xdata_len)
 {
 	struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
 	int res;
@@ -2216,12 +1694,21 @@
 
 	/*! \note Insert SDES here. Probably should make SDES text equal to mimetypes[code].type (not subtype 'cos
 	  it can change mid call, and SDES can't) */
-	rtcpheader[len/4]     = htonl((2 << 30) | (1 << 24) | (RTCP_PT_SDES << 16) | 2);
-	rtcpheader[(len/4)+1] = htonl(rtp->ssrc);               /* Our SSRC */
-	rtcpheader[(len/4)+2] = htonl(0x01 << 24);              /* Empty for the moment */
+	rtcpheader[(len>>2)]     = htonl((2 << 30) | (1 << 24) | (RTCP_PT_SDES << 16) | 2);
+	rtcpheader[(len>>2) + 1] = htonl(rtp->ssrc);               /* Our SSRC */
+	rtcpheader[(len>>2) + 2] = htonl(0x01 << 24);              /* Empty for the moment */
 	len += 12;
 
 	ast_sockaddr_copy(&remote_address, &rtp->rtcp->them);
+	if(xdata && xdata_len){
+		if ((len + xdata_len) > sizeof(bdata)) {
+			ast_log(LOG_ERROR, "RTCP RR transmission cannot append: %d\n", xdata_len);
+		}
+		else {
+			memcpy(&rtcpheader[(len>>2)], xdata, xdata_len);
+			len += xdata_len;
+		}
+	}
 
 	res = rtcp_sendto(instance, (unsigned int *)rtcpheader, len, 0, &remote_address, &ice);
 
@@ -2402,7 +1889,7 @@
 	if (rtp->txcount > rtp->rtcp->lastsrtxcount) {
 		res = ast_rtcp_write_sr(instance);
 	} else {
-		res = ast_rtcp_write_rr(instance);
+		res = ast_rtcp_write_rr(instance, 0, 0);
 	}
 
 	if (!res) {
@@ -2500,7 +1987,7 @@
 		int hdrlen = 12, res, ice;
 		unsigned char *rtpheader = (unsigned char *)(frame->data.ptr - hdrlen);
 
-		put_unaligned_uint32(rtpheader, htonl((2 << 30) | (codec << 16) | (rtp->seqno) | (mark << 23)));
+		put_unaligned_uint32(rtpheader, htonl((2 << 30) | (codec << 16) | (/*rtp->seqno*/frame->seqno) | (mark << 23))); // FIXME: use frame seqno to reflect pkt loss
 		put_unaligned_uint32(rtpheader + 4, htonl(rtp->lastts));
 		put_unaligned_uint32(rtpheader + 8, htonl(rtp->ssrc));
 
@@ -2531,7 +2018,7 @@
 				}
 			}
 		}
-
+		
 		update_address_with_ice_candidate(rtp, COMPONENT_RTP, &remote_address);
 
 		if (rtp_debug_test_addr(&remote_address)) {
@@ -3141,9 +2628,25 @@
 		}
 
 		switch (pt) {
+			case RTCP_PT_RTPFB:
+			case RTCP_PT_PSFB:
+				{
+					unsigned int* pkt = &rtcpheader[i - 2];
+					unsigned int len = (((ntohl(pkt[0]) & 0xFFFF) + 1) << 2);
+					
+					rtp->f.frametype = AST_FRAME_CONTROL;
+					rtp->f.subclass.integer = AST_CONTROL_RTCPFB;
+					rtp->f.mallocd = 0;
+					rtp->f.datalen = len;
+					rtp->f.data.ptr = (void*)&pkt[0];
+					rtp->f.offset = 0;
+					f = &rtp->f;
+					break;
+				}
+			
 		case RTCP_PT_SR:
 			gettimeofday(&rtp->rtcp->rxlsr,NULL); /* To be able to populate the dlsr */
-			rtp->rtcp->spc = ntohl(rtcpheader[i+3]);
+			rtp->rtcp->spc = ntohl(rtcpheader[i + 3]);
 			rtp->rtcp->soc = ntohl(rtcpheader[i + 4]);
 			rtp->rtcp->themrxlsr = ((ntohl(rtcpheader[i]) & 0x0000ffff) << 16) | ((ntohl(rtcpheader[i + 1]) & 0xffff0000) >> 16); /* Going to LSR in RR*/
 
@@ -3433,6 +2936,7 @@
 	struct ast_rtp_payload_type payload;
 	struct ast_sockaddr remote_address = { {0,} };
 	struct frame_list frames;
+	int is_muxed_rtcp = 0;
 
 	/* If this is actually RTCP let's hop on over and handle it */
 	if (rtcp) {
@@ -3568,6 +3072,21 @@
 	timestamp = ntohl(rtpheader[1]);
 	ssrc = ntohl(rtpheader[2]);
 
+	
+	/* check if it's RTCP muxed with RTP */
+	switch((payloadtype)){
+		case 64: case 65: 
+		case 72: case 73: case 74: case 75: case 76:
+		case 77: case 78:
+		case 79: is_muxed_rtcp = 1; break;
+	}
+	if(is_muxed_rtcp){
+		if (rtp->rtcp) {
+			return ast_rtcp_read(instance);
+		}
+		return &ast_null_frame;
+	}
+
 	AST_LIST_HEAD_INIT_NOLOCK(&frames);
 	/* Force a marker bit and change SSRC if the SSRC changes */
 	if (rtp->rxssrc && rtp->rxssrc != ssrc) {
@@ -4071,10 +3590,6 @@
 	struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
 	struct ast_sockaddr addr = { {0,} };
 
-#ifdef HAVE_OPENSSL_SRTP
-	AST_SCHED_DEL_UNREF(rtp->sched, rtp->rekeyid, ao2_ref(instance, -1));
-#endif
-
 	if (rtp->rtcp && rtp->rtcp->schedid > 0) {
 		if (!ast_sched_del(rtp->sched, rtp->rtcp->schedid)) {
 			/* successfully cancelled scheduler entry. */
@@ -4154,22 +3669,57 @@
 	return res;
 }
 
-#ifdef HAVE_OPENSSL_SRTP
-static int ast_rtp_activate(struct ast_rtp_instance *instance)
+/*! \brief forward RTCP-FB message received from remote peer */
+static int ast_rtcpfb(struct ast_rtp_instance *instance, void* data, unsigned int len)
 {
+	unsigned int pkt_len, u1, fci, pkt_type, *pkt;
+	int forward = 0;
 	struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
+	pkt = (unsigned int*)data;
+	u1 = ntohl(pkt[0]);
+	pkt_type = ((u1 >> 16) & 0xFF);
+	pkt_len = (((u1 & 0xFFFF) + 1) << 2);
+	fci = (pkt[0] & 0x1F);
 
-	if (!rtp->ssl) {
-		return 0;
+	if(pkt_len != len){
+		ast_log(LOG_ERROR, "Invalid packet length %u<>%u\n", len, pkt_len);
+		return -1;
 	}
 
-	SSL_do_handshake(rtp->ssl);
-
-	dtls_srtp_check_pending(instance, rtp);
-
-	return 0;
+	if(pkt_type == RTCP_PT_RTPFB){
+		switch(fci){
+			case RTCP_PT_RTPFB_NACK:
+				{
+					if(len >= 12){
+						pkt[1] = htonl(rtp->ssrc); /* Sender SSRC */
+						pkt[2] = htonl(rtp->themssrc); /* Media SSRC */
+					}
+					forward = 1;
+					break;
+				}
+		}
+	}
+	else if(pkt_type == RTCP_PT_PSFB){
+		switch(fci){
+			case RTCP_PT_PSFB_FIR:
+			case RTCP_PT_PSFB_PLI:
+				{
+					if(len >= 12){
+						pkt[1] = htonl(rtp->ssrc); /* Sender SSRC */
+						pkt[2] = htonl(rtp->themssrc); /* Media SSRC */
+					}
+					if(fci == RTCP_PT_PSFB_FIR){
+						if(len >= 20){
+							pkt[3] = htonl(rtp->themssrc); /* FIR-1 Media SSRC */
+						}
+					}
+					forward = 1;
+					break;
+				}
+		}
+	}
+	return forward ? ast_rtcp_write_rr(instance, data, len) : 0;
 }
-#endif
 
 static char *rtp_do_debug_ip(struct ast_cli_args *a)
 {
