diff -c /usr/src/orig/rtpengine/daemon/call_interfaces.c ./call_interfaces.c
*** /usr/src/orig/rtpengine/daemon/call_interfaces.c	Mon Apr  7 09:38:28 2014
--- ./call_interfaces.c	Tue Apr 22 21:31:59 2014
***************
*** 462,467 ****
--- 462,469 ----
  			out->ice_remove = 1;
  		else if (!str_cmp(&s, "force"))
  			out->ice_force = 1;
+ 		else if (!str_cmp(&s, "force_relay"))
+ 			out->ice_force_relay = 1;
  	}
  
  	if ((list = bencode_dictionary_get_expect(input, "rtcp-mux", BENCODE_LIST))) {
diff -c /usr/src/orig/rtpengine/daemon/sdp.c ./sdp.c
*** /usr/src/orig/rtpengine/daemon/sdp.c	Mon Apr  7 21:34:48 2014
--- ./sdp.c	Tue Apr 22 21:33:47 2014
***************
*** 78,84 ****
  	str component_str;
  	str transport;
  	str priority_str;
! 	/* incomplete */
  
  	unsigned long component;
  	unsigned long priority;
--- 78,87 ----
  	str component_str;
  	str transport;
  	str priority_str;
! 	str ip_str;
! 	str port_str;
! 	str typ_str;
! 	str type_str;
  
  	unsigned long component;
  	unsigned long priority;
***************
*** 554,559 ****
--- 557,566 ----
  	EXTRACT_TOKEN(u.candidate.component_str);
  	EXTRACT_TOKEN(u.candidate.transport);
  	EXTRACT_TOKEN(u.candidate.priority_str);
+ 	EXTRACT_TOKEN(u.candidate.ip_str);
+ 	EXTRACT_TOKEN(u.candidate.port_str);
+ 	EXTRACT_TOKEN(u.candidate.typ_str);
+ 	EXTRACT_TOKEN(u.candidate.type_str);
  
  	output->u.candidate.component = strtoul(output->u.candidate.component_str.s, &ep, 10);
  	if (ep == output->u.candidate.component_str.s)
***************
*** 1311,1317 ****
--- 1319,1336 ----
  		switch (attr->attr) {
  			case ATTR_ICE:
  			case ATTR_ICE_UFRAG:
+ 				if (!flags->ice_remove && !flags->ice_force)
+ 					break;
+ 				goto strip;
+ 
  			case ATTR_CANDIDATE:
+ 				if (flags->ice_force_relay) {
+ 					if ((attr->u.candidate.type_str.len == 5) &&
+ 					    (strncasecmp(attr->u.candidate.type_str.s, "relay", 5) == 0))
+ 						goto strip;
+ 					else
+ 						break;
+ 				}
  				if (!flags->ice_remove && !flags->ice_force)
  					break;
  				goto strip;
***************
*** 1359,1367 ****
--- 1378,1399 ----
  		switch (attr->attr) {
  			case ATTR_ICE:
  			case ATTR_ICE_UFRAG:
+ 				if (MEDIA_ISSET(media, PASSTHRU))
+ 					break;
+ 				if (!flags->ice_remove && !flags->ice_force)
+ 					break;
+ 				goto strip;
+ 
  			case ATTR_CANDIDATE:
  				if (MEDIA_ISSET(media, PASSTHRU))
  					break;
+ 				if (flags->ice_force_relay) {
+ 					if ((attr->u.candidate.type_str.len == 5) &&
+ 					    (strncasecmp(attr->u.candidate.type_str.s, "relay", 5) == 0))
+ 						goto strip;
+ 					else
+ 						break;
+ 				}
  				if (!flags->ice_remove && !flags->ice_force)
  					break;
  				goto strip;
***************
*** 1442,1454 ****
  }
  
  static void insert_candidates(struct sdp_chopper *chop, struct packet_stream *rtp, struct packet_stream *rtcp,
! 		unsigned long priority, struct sdp_media *media)
  {
  	chopper_append_c(chop, "a=candidate:");
  	chopper_append_str(chop, &ice_foundation_str);
  	chopper_append_printf(chop, " 1 UDP %lu ", priority);
  	insert_ice_address(chop, rtp);
! 	chopper_append_c(chop, " typ host\r\n");
  
  	if (rtcp) {
  		/* rtcp-mux only possible in answer */
--- 1474,1490 ----
  }
  
  static void insert_candidates(struct sdp_chopper *chop, struct packet_stream *rtp, struct packet_stream *rtcp,
! 			      unsigned long priority, struct sdp_media *media,
! 			      unsigned int relay)
  {
  	chopper_append_c(chop, "a=candidate:");
  	chopper_append_str(chop, &ice_foundation_str);
  	chopper_append_printf(chop, " 1 UDP %lu ", priority);
  	insert_ice_address(chop, rtp);
! 	if (relay == 1)
! 	    chopper_append_c(chop, " typ relay\r\n");
! 	else
! 	    chopper_append_c(chop, " typ host\r\n");
  
  	if (rtcp) {
  		/* rtcp-mux only possible in answer */
***************
*** 1456,1481 ****
  		chopper_append_str(chop, &ice_foundation_str);
  		chopper_append_printf(chop, " 2 UDP %lu ", priority - 1);
  		insert_ice_address(chop, rtcp);
! 		chopper_append_c(chop, " typ host\r\n");
  	}
  
  }
  
  static void insert_candidates_alt(struct sdp_chopper *chop, struct packet_stream *rtp, struct packet_stream *rtcp,
! 		unsigned long priority, struct sdp_media *media)
  {
  	chopper_append_c(chop, "a=candidate:");
  	chopper_append_str(chop, &ice_foundation_str_alt);
  	chopper_append_printf(chop, " 1 UDP %lu ", priority);
  	insert_ice_address_alt(chop, rtp);
! 	chopper_append_c(chop, " typ host\r\n");
  
  	if (rtcp) {
  		chopper_append_c(chop, "a=candidate:");
  		chopper_append_str(chop, &ice_foundation_str_alt);
  		chopper_append_printf(chop, " 2 UDP %lu ", priority - 1);
  		insert_ice_address_alt(chop, rtcp);
! 		chopper_append_c(chop, " typ host\r\n");
  	}
  
  }
--- 1492,1527 ----
  		chopper_append_str(chop, &ice_foundation_str);
  		chopper_append_printf(chop, " 2 UDP %lu ", priority - 1);
  		insert_ice_address(chop, rtcp);
! 		if (relay)
! 		    chopper_append_c(chop, " typ relay\r\n");
! 		else
! 		    chopper_append_c(chop, " typ host\r\n");
  	}
  
  }
  
  static void insert_candidates_alt(struct sdp_chopper *chop, struct packet_stream *rtp, struct packet_stream *rtcp,
! 				  unsigned long priority, struct sdp_media *media,
! 				  unsigned int relay)
  {
  	chopper_append_c(chop, "a=candidate:");
  	chopper_append_str(chop, &ice_foundation_str_alt);
  	chopper_append_printf(chop, " 1 UDP %lu ", priority);
  	insert_ice_address_alt(chop, rtp);
! 	if (relay == 1)
! 	    chopper_append_c(chop, " typ relay\r\n");
! 	else
! 	    chopper_append_c(chop, " typ host\r\n");
  
  	if (rtcp) {
  		chopper_append_c(chop, "a=candidate:");
  		chopper_append_str(chop, &ice_foundation_str_alt);
  		chopper_append_printf(chop, " 2 UDP %lu ", priority - 1);
  		insert_ice_address_alt(chop, rtcp);
! 		if (relay)
! 		    chopper_append_c(chop, " typ relay\r\n");
! 		else
! 		    chopper_append_c(chop, " typ host\r\n");
  	}
  
  }
***************
*** 1591,1597 ****
  	struct call *call;
  
  	m = monologue->medias.head;
! 	do_ice = (flags->ice_force || (!has_ice(sessions) && !flags->ice_remove)) ? 1 : 0;
  	call = monologue->call;
  
  	for (l = sessions->head; l; l = l->next) {
--- 1637,1644 ----
  	struct call *call;
  
  	m = monologue->medias.head;
! 	do_ice = (flags->ice_force || flags->ice_force_relay ||
! 		  (!has_ice(sessions) && !flags->ice_remove)) ? 1 : 0;
  	call = monologue->call;
  
  	for (l = sessions->head; l; l = l->next) {
***************
*** 1730,1741 ****
  				priority = new_priority(flags->ice_force ? NULL : sdp_media);
  
  				insert_candidates(chop, ps, ps_rtcp,
! 						priority, sdp_media);
  
  				if (callmaster_has_ipv6(call->callmaster)) {
  					priority -= 256;
  					insert_candidates_alt(chop, ps, ps_rtcp,
! 							priority, sdp_media);
  				}
  			}
  
--- 1777,1789 ----
  				priority = new_priority(flags->ice_force ? NULL : sdp_media);
  
  				insert_candidates(chop, ps, ps_rtcp,
! 						  priority, sdp_media, flags->ice_force_relay);
  
  				if (callmaster_has_ipv6(call->callmaster)) {
  					priority -= 256;
  					insert_candidates_alt(chop, ps, ps_rtcp,
! 							      priority, sdp_media,
! 							      flags->ice_force_relay);
  				}
  			}
  
diff -c /usr/src/orig/rtpengine/daemon/sdp.h ./sdp.h
*** /usr/src/orig/rtpengine/daemon/sdp.h	Mon Apr  7 09:38:28 2014
--- ./sdp.h	Tue Apr 22 17:35:58 2014
***************
*** 25,30 ****
--- 25,31 ----
  	    replace_sess_conn:1,
  	    ice_remove:1,
  	    ice_force:1,
+ 	    ice_force_relay:1,
  	    rtcp_mux_offer:1,
  	    rtcp_mux_demux:1,
  	    rtcp_mux_accept:1,
