Index: channels/chan_sip.c
===================================================================
--- channels/chan_sip.c	(revision 372708)
+++ channels/chan_sip.c	(working copy)
@@ -1388,7 +1388,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 start_ice(struct ast_rtp_instance *instance);
 static void add_codec_to_sdp(const struct sip_pvt *p, struct ast_format *codec,
 			     struct ast_str **m_buf, struct ast_str **a_buf,
@@ -1681,6 +1681,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",
@@ -10412,9 +10415,10 @@
 {
 	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;
+	int generation = -1;
 
 	if (!instance || !(ice = ast_rtp_instance_get_ice(instance))) {
 		return found;
@@ -10426,10 +10430,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);
@@ -11990,7 +11995,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;
@@ -12013,6 +12018,13 @@
 	i = ao2_iterator_init(candidates, 0);
 
 	while ((candidate = ao2_iterator_next(&i))) {
+		if((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));
@@ -12030,6 +12042,13 @@
 			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 = 10;
+			// 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");
 	}
 
@@ -12517,7 +12536,7 @@
 			}
 
 			if (!doing_directmedia && 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);
 			}
 		}
 
@@ -12534,7 +12553,7 @@
 			}
 
 			if (!doing_directmedia && 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);
 			}
 		}
 
@@ -12633,7 +12652,7 @@
 			ast_str_append(&a_text, 0, "a=ptime:%d\r\n", min_text_packet_size);
 
 		if (!doing_directmedia && 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);
 		}
 
 		if (m_audio->len - m_audio->used < 2 || m_video->len - m_video->used < 2 ||
@@ -15416,6 +15435,9 @@
 		ast_string_field_set(peer, useragent, useragent);
 		ast_verb(4, "Saved useragent \"%s\" for peer %s\n", peer->useragent, peer->name);
 	}
+
+	ast_verb(4, "User Agent transport = %s", get_transport_pvt(pvt));
+
 	return PARSE_REGISTER_UPDATE;
 }
 
@@ -32882,6 +32904,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/sip/include/sip.h
===================================================================
--- channels/sip/include/sip.h	(revision 372708)
+++ channels/sip/include/sip.h	(working copy)
@@ -1212,6 +1212,8 @@
 	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 */
 };
 
 /*! \brief sip packet - raw format for outbound packets that are sent or scheduled for transmission
Index: include/asterisk/rtp_engine.h
===================================================================
--- include/asterisk/rtp_engine.h	(revision 372708)
+++ 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 */
Index: res/pjproject/pjnath/include/pjnath/stun_auth.h
===================================================================
--- res/pjproject/pjnath/include/pjnath/stun_auth.h	(revision 372708)
+++ 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 372708)
+++ 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 372708)
+++ 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 372708)
+++ 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 372708)
+++ 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 372708)
+++ 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 372708)
+++ 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 372708)
+++ res/pjproject/pjnath/src/pjnath/ice_session.c	(working copy)
@@ -301,12 +301,15 @@
 
     /* 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.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;
+	}
+
+	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;
@@ -320,6 +323,7 @@
     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;
 }
 
 /*
@@ -435,8 +439,20 @@
 PJ_DEF(pj_status_t) pj_ice_sess_set_options(pj_ice_sess *ice,
 					    const pj_ice_sess_options *opt)
 {
+	pj_bool_t update;
     PJ_ASSERT_RETURN(ice && opt, PJ_EINVAL);
-    pj_memcpy(&ice->opt, opt, sizeof(*opt));
+	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;
@@ -929,6 +945,10 @@
 			    pj_ice_sess_check_state st, 
 			    pj_status_t err_code)
 {
+	if(ice->opt.is_webrtc && check->state >= PJ_ICE_SESS_CHECK_STATE_SUCCEEDED){
+		return;// return WebRTC keepAlive
+	}
+
     pj_assert(check->state < PJ_ICE_SESS_CHECK_STATE_SUCCEEDED);
 
     LOG5((ice->obj_name, "Check %s: state changed from %s to %s",
@@ -1150,6 +1170,7 @@
 	     * 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);
 
@@ -1621,9 +1642,11 @@
 
     /* Save credentials */
     username.ptr = buf;
-
+	
     pj_strcpy(&username, rem_ufrag);
-    pj_strcat2(&username, ":");
+	if(!ice->opt.is_webrtc){
+		pj_strcat2(&username, ":");
+	}
     pj_strcat(&username, &ice->rx_ufrag);
 
     pj_strdup(ice->pool, &ice->tx_uname, &username);
@@ -1631,7 +1654,9 @@
     pj_strdup(ice->pool, &ice->tx_pass, rem_passwd);
 
     pj_strcpy(&username, &ice->rx_ufrag);
-    pj_strcat2(&username, ":");
+	if(!ice->opt.is_webrtc){
+		pj_strcat2(&username, ":");
+	}
     pj_strcat(&username, rem_ufrag);
 
     pj_strdup(ice->pool, &ice->rx_uname, &username);
@@ -1709,6 +1734,21 @@
     }
     ice->comp_cnt = highest_comp;
 
+	// 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);
+
+		for(i = 0; i < ice->comp_cnt ; ++i){
+			pj_stun_session_set_credential(ice->comp[i].stun_sess,
+							PJ_STUN_AUTH_WEBRTC,
+							&auth_cred);
+		}
+	}
+
     /* Init timer entry in the checklist. Initially the timer ID is FALSE
      * because timer is not running.
      */
@@ -2156,6 +2196,7 @@
     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);
@@ -2167,6 +2208,10 @@
     clist = msg_data->data.req.clist;
     check = &clist->checks[msg_data->data.req.ckid];
     
+	//FIXME: Find why WebRTC keepalive requests cause tdata mismatch
+	if(tdata != check->tdata){
+		return;
+	}
 
     /* Mark STUN transaction as complete */
     pj_assert(tdata == check->tdata);
@@ -2291,18 +2336,23 @@
     /* 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, 
-			PJNATH_ESTUNNOMAPPEDADDR);
-	on_check_complete(ice, check);
-	pj_mutex_unlock(ice->mutex);
-	return;
+	/* 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;
     }
 
     /* 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) {
+	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;
@@ -2335,7 +2385,7 @@
 				      msg_data->transport_id,
 				      PJ_ICE_CAND_TYPE_PRFLX,
 				      65535, &foundation,
-				      &xaddr->sockaddr, 
+					  xaddr ? &xaddr->sockaddr : &addr->sockaddr, 
 				      &check->lcand->base_addr, 
 				      &check->lcand->base_addr,
 				      sizeof(pj_sockaddr_in), &cand_id);
@@ -2461,7 +2511,7 @@
     /* Get PRIORITY attribute */
     prio_attr = (pj_stun_priority_attr*)
 	        pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_PRIORITY, 0);
-    if (prio_attr == NULL) {
+	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;
@@ -2544,6 +2594,11 @@
 					   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;
@@ -2574,7 +2629,9 @@
     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;
+	if(prio_attr){
+		rcheck->priority = prio_attr->value;
+	}
     rcheck->role_attr = role_attr;
 
     if (ice->rcand_cnt == 0) {
@@ -2752,6 +2809,29 @@
 	    pj_bool_t complete;
 	    unsigned j;
 
+		// WebRTC STUN refreshness
+		if(ice->opt.is_webrtc && PJ_FALSE){ // FIXME: No longer needed in newest chrome and make Asterisk to overrun
+			pj_status_t status;
+			pj_ice_msg_data* msg_data;
+
+			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, &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.
@@ -2785,7 +2865,7 @@
 	    }
 	}
 
-    }
+	}
     /* 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
Index: res/pjproject/pjnath/src/pjnath/turn_sock.c
===================================================================
--- res/pjproject/pjnath/src/pjnath/turn_sock.c	(revision 372708)
+++ 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 372708)
+++ 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 372708)
+++ 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 372708)
+++ 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 372708)
+++ 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 372708)
+++ res/res_rtp_asterisk.c	(working copy)
@@ -411,6 +411,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);
@@ -462,6 +463,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;
@@ -498,11 +500,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);
@@ -891,7 +913,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));