diff --git a/contrib/src/pjproject/fix_turn_fallback.patch b/contrib/src/pjproject/fix_turn_fallback.patch
new file mode 100644
index 0000000000000000000000000000000000000000..2a54ee15cd243969f3b1621c9a50e9871263c469
--- /dev/null
+++ b/contrib/src/pjproject/fix_turn_fallback.patch
@@ -0,0 +1,39 @@
+--- a/pjnath/src/pjnath/turn_session.c	2016-09-19 18:21:09.073614574 -0400
++++ b/pjnath/src/pjnath/turn_session.c	2016-09-19 18:21:30.648631620 -0400
+@@ -653,3 +653,3 @@
+ 
+-	cnt = PJ_TURN_MAX_DNS_SRV_CNT;
++	cnt = 1;
+ 	ai = (pj_addrinfo*)
+--- a/pjnath/src/pjnath/ice_strans.c	2016-09-19 18:36:04.180104330 -0400
++++ b/pjnath/src/pjnath/ice_strans.c	2016-09-19 18:37:10.614136809 -0400
+@@ -1304,2 +1304,5 @@
+ 
++		if (!comp->turn[n].sock)
++			continue;
++
+ 	    /* Gather remote addresses for this component */
+@@ -2013,4 +2016,21 @@
+ 	    if (comp->ice_st->state < PJ_ICE_STRANS_STATE_READY) {
+-		sess_fail(comp->ice_st, PJ_ICE_STRANS_OP_INIT,
+-			  "TURN allocation failed", info.last_status);
++			PJ_LOG(4,(comp->ice_st->obj_name,
++					  "TURN allocation failed, disable the associated candidate"));
++			pj_ice_sess_cand *cand = NULL;
++			unsigned i;
++			/* Wait until initialization completes */
++			pj_grp_lock_acquire(comp->ice_st->grp_lock);
++			/* Find relayed candidate in the component */
++			for (i=0; i<comp->cand_cnt; ++i) {
++				if (comp->cand_list[i].type == PJ_ICE_CAND_TYPE_RELAYED &&
++					comp->cand_list[i].transport_id == data->transport_id) {
++					cand = &comp->cand_list[i];
++					break;
++				}
++			}
++			pj_grp_lock_release(comp->ice_st->grp_lock);
++			pj_assert(cand != NULL);
++			// Make session init succeed but disable this TURN server to be used
++			cand->status = PJNATH_ESTUNTIMEDOUT;
++			sess_init_update(comp->ice_st);
+ 	    } else if (comp->turn[tp_idx].err_cnt > 1) {
diff --git a/contrib/src/pjproject/ice_config.patch b/contrib/src/pjproject/ice_config.patch
index e958c0d2eb9d3802651f30253ef8a1dce6388c92..a6398f4e29209ee2bd85ad25ec0f56ae763f7070 100644
--- a/contrib/src/pjproject/ice_config.patch
+++ b/contrib/src/pjproject/ice_config.patch
@@ -1,23 +1,22 @@
 --- a/pjnath/include/pjnath/config.h
 +++ b/pjnath/include/pjnath/config.h
-@@ -231,5 +231,5 @@
-  * Default: 16
-  */
+@@ -233,3 +233,3 @@
  #ifndef PJ_ICE_MAX_CAND
 -#   define PJ_ICE_MAX_CAND			    16
 +#   define PJ_ICE_MAX_CAND			    32
  #endif
-@@ -250,5 +250,5 @@
-  * the maximum number of components (PJ_ICE_MAX_COMP) value.
-  */
+@@ -254,3 +254,3 @@
+ #ifndef PJ_ICE_MAX_STUN
+-#   define PJ_ICE_MAX_STUN			    2
++#   define PJ_ICE_MAX_STUN			    3
+ #endif
+@@ -274,3 +274,3 @@
  #ifndef PJ_ICE_COMP_BITS
 -#   define PJ_ICE_COMP_BITS			    1
 +#   define PJ_ICE_COMP_BITS			    2
  #endif
-@@ -301,5 +301,5 @@
-  * Default: 32
-  */
+@@ -325,3 +325,3 @@
  #ifndef PJ_ICE_MAX_CHECKS
 -#   define PJ_ICE_MAX_CHECKS			    32
 +#   define PJ_ICE_MAX_CHECKS			    150
- #endif
+ #endif
\ No newline at end of file
diff --git a/contrib/src/pjproject/rules.mak b/contrib/src/pjproject/rules.mak
index da0e0fb4a0f39cbab9c15e8cbece657895ec7290..95e6cbb45c42e46cf7cb8e2a447f0e406aa4322f 100644
--- a/contrib/src/pjproject/rules.mak
+++ b/contrib/src/pjproject/rules.mak
@@ -33,8 +33,8 @@ ifdef HAVE_IOS
 PJPROJECT_OPTIONS += --with-ssl=$(PREFIX)
 endif
 
-PJPROJECT_EXTRA_CFLAGS = -DPJ_ICE_MAX_CAND=32 -DPJ_ICE_MAX_CHECKS=150 -DPJ_ICE_COMP_BITS=2 -std=gnu11
-PJPROJECT_EXTRA_CXXFLAGS = -DPJ_ICE_MAX_CAND=32 -DPJ_ICE_MAX_CHECKS=150 -DPJ_ICE_COMP_BITS=2 -std=gnu++11
+PJPROJECT_EXTRA_CFLAGS = -DPJ_ICE_MAX_CAND=32 -DPJ_ICE_MAX_CHECKS=150 -DPJ_ICE_COMP_BITS=2 -DPJ_ICE_MAX_STUN=3
+PJPROJECT_EXTRA_CXXFLAGS = -DPJ_ICE_MAX_CAND=32 -DPJ_ICE_MAX_CHECKS=150 -DPJ_ICE_COMP_BITS=2 -DPJ_ICE_MAX_STUN=3 -std=gnu++11
 
 ifdef HAVE_WIN64
 PJPROJECT_EXTRA_CFLAGS += -DPJ_WIN64=1
@@ -75,6 +75,7 @@ endif
 	$(APPLY) $(SRC)/pjproject/ice_config.patch
 	$(APPLY) $(SRC)/pjproject/multiple_listeners.patch
 	$(APPLY) $(SRC)/pjproject/pj_ice_sess.patch
+	$(APPLY) $(SRC)/pjproject/fix_turn_fallback.patch
 	$(UPDATE_AUTOCONFIG)
 	$(MOVE)
 
diff --git a/src/ice_transport.cpp b/src/ice_transport.cpp
index eaf7f0422ac9e31d617158e29834720682813155..e0ad0452fece0a2120380c7f3338c7c019265ab2 100644
--- a/src/ice_transport.cpp
+++ b/src/ice_transport.cpp
@@ -937,7 +937,7 @@ IceTransportFactory::IceTransportFactory()
     // v2.4.5 of PJNATH has a default of 100ms but RFC 5389 since version 14 requires
     // a minimum of 500ms on fixed-line links. Our usual case is wireless links.
     // This solves too long ICE exchange by DHT.
-    // Using 500ms with default PJ_STUN_MAX_TRANSMIT_COUNT (7) gives around 31s before timeout.
+    // Using 500ms with default PJ_STUN_MAX_TRANSMIT_COUNT (7) gives around 33s before timeout.
     ice_cfg_.stun_cfg.rto_msec = 500;
 
     // Add local hosts (IPv4, IPv6) as stun candidates
diff --git a/src/ringdht/ringaccount.cpp b/src/ringdht/ringaccount.cpp
index ee14773644c30c3c108c10a216335082df142dbb..3a48f2c0232a871c2bacd7f2b8bc0652dc182ae6 100644
--- a/src/ringdht/ringaccount.cpp
+++ b/src/ringdht/ringaccount.cpp
@@ -81,7 +81,6 @@ using std::chrono::system_clock;
 
 static constexpr int ICE_COMPONENTS {1};
 static constexpr int ICE_COMP_SIP_TRANSPORT {0};
-static constexpr int ICE_INIT_TIMEOUT {10};
 static constexpr auto ICE_NEGOTIATION_TIMEOUT = std::chrono::seconds(60);
 static constexpr auto TLS_TIMEOUT = std::chrono::seconds(30);
 const constexpr auto EXPORT_KEY_RENEWAL_TIME = std::chrono::minutes(20);
@@ -141,7 +140,7 @@ RingAccount::createIceTransport(const Args&... args)
     }
 
     auto ice = Manager::instance().getIceTransportFactory().createTransport(args...);
-    if (!ice or ice->waitForInitialization(ICE_INIT_TIMEOUT) <= 0)
+    if (!ice)
         throw std::runtime_error("ICE transport creation failed");
 
     if (const auto& publicIP = getPublishedIpAddress()) {
@@ -254,24 +253,24 @@ RingAccount::newOutgoingCall(const std::string& toUrl)
 
                 call->addSubCall(dev_call);
 
-                auto iceInitTimeout = std::chrono::steady_clock::now() + std::chrono::seconds {ICE_INIT_TIMEOUT};
-
-                manager.addTask([sthis, weak_dev_call, ice, iceInitTimeout, toUri, dev] {
+                manager.addTask([sthis, weak_dev_call, ice, toUri, dev] {
                     auto call = weak_dev_call.lock();
 
+                    // call aborted?
                     if (not call)
                         return false;
 
-                    if (ice->isFailed() or std::chrono::steady_clock::now() >= iceInitTimeout) {
-                        RING_DBG("ice init failed (or timeout)");
-                        call->onFailure();
+                    if (ice->isFailed()) {
+                        RING_ERR("[call:%s] ice init failed", call->getCallId().c_str());
+                        call->onFailure(EIO);
                         return false;
                     }
 
+                    // Loop until ICE transport is initialized.
+                    // Note: we suppose that ICE init routine has a an internal timeout (bounded in time)
+                    // and we let upper layers decide when the call shall be aborded (our first check upper).
                     if (not ice->isInitialized())
-                        return true; // process task again!
-
-                    RING_WARN("ICE initialised");
+                        return true;
 
                     // Next step: sent the ICE data to peer through DHT
                     const dht::Value::Id callvid  = udist(sthis->rand_);
@@ -280,7 +279,6 @@ RingAccount::newOutgoingCall(const std::string& toUrl)
                     dht::Value val { dht::IceCandidates(callvid, ice->getLocalAttributesAndCandidates()) };
                     val.id = vid;
 
-                    //RING_WARN("ICE initialised");
                     sthis->dht_.putEncrypted(
                         callkey, dev.dev,
                         std::move(val),
diff --git a/src/sip/sipcall.cpp b/src/sip/sipcall.cpp
index ca0547e0cc0ea8524d62ccbf18c4638a02afe2df..09382c627439443e7f59817ae7f3ae5161fe88aa 100644
--- a/src/sip/sipcall.cpp
+++ b/src/sip/sipcall.cpp
@@ -63,7 +63,7 @@ getVideoSettings()
 }
 #endif
 
-static constexpr int DEFAULT_ICE_INIT_TIMEOUT {10}; // seconds
+static constexpr int DEFAULT_ICE_INIT_TIMEOUT {35}; // seconds
 static constexpr int DEFAULT_ICE_NEGO_TIMEOUT {60}; // seconds
 
 // SDP media Ids
@@ -718,8 +718,9 @@ SIPCall::setupLocalSDPFromIce()
         return;
     }
 
-    if (waitForIceInitialization(DEFAULT_ICE_INIT_TIMEOUT) <= 0) {
-        RING_ERR("[call:%s] Local ICE init failed", getCallId().c_str());
+    // we need an initialized ICE to progress further
+    if (iceTransport_->waitForInitialization(DEFAULT_ICE_INIT_TIMEOUT) <= 0) {
+        RING_ERR("[call:%s] Medias' ICE init failed", getCallId().c_str());
         return;
     }
 
@@ -761,7 +762,7 @@ SIPCall::getAllRemoteCandidates()
 bool
 SIPCall::startIce()
 {
-    if (not iceTransport_ or iceTransport_->isFailed())
+    if (not iceTransport_ or iceTransport_->isFailed() or not iceTransport_->isInitialized())
         return false;
     if (iceTransport_->isStarted()) {
         RING_DBG("[call:%s] ICE already started", getCallId().c_str());