Pārlūkot izejas kodu

modules/rtpproxy: rtpproxy_manage can now add ice relay candidates

- The feature is activated by defining ice_candidate_priority_avp module
  parameter.
Juha Heinanen 12 gadi atpakaļ
vecāks
revīzija
75fde552f1

+ 85 - 64
modules/rtpproxy/README

@@ -30,13 +30,13 @@ Carsten Bock
 
 
    ng-voice GmbH
    ng-voice GmbH
 
 
-   Copyright © 2003-2008 Sippy Software, Inc.
+   Copyright © 2003-2008 Sippy Software, Inc.
 
 
-   Copyright © 2005 Voice Sistem SRL
+   Copyright © 2005 Voice Sistem SRL
 
 
-   Copyright © 2009-2012 TuTPro Inc.
+   Copyright © 2009-2012 TuTPro Inc.
 
 
-   Copyright © 2010 VoIPEmbedded Inc.
+   Copyright © 2010 VoIPEmbedded Inc.
      __________________________________________________________________
      __________________________________________________________________
 
 
    Table of Contents
    Table of Contents
@@ -58,6 +58,7 @@ Carsten Bock
               4.4. rtpproxy_retr (integer)
               4.4. rtpproxy_retr (integer)
               4.5. nortpproxy_str (string)
               4.5. nortpproxy_str (string)
               4.6. timeout_socket (string)
               4.6. timeout_socket (string)
+              4.7. ice_candidate_priority_avp (string)
 
 
         5. Functions
         5. Functions
 
 
@@ -92,16 +93,17 @@ Carsten Bock
    1.4. Set rtpproxy_retr parameter
    1.4. Set rtpproxy_retr parameter
    1.5. Set nortpproxy_str parameter
    1.5. Set nortpproxy_str parameter
    1.6. Set timeout_socket parameter
    1.6. Set timeout_socket parameter
-   1.7. set_rtp_proxy_set usage
-   1.8. rtpproxy_offer usage
-   1.9. rtpproxy_answer usage
-   1.10. rtpproxy_destroy usage
-   1.11. rtpproxy_manage usage
-   1.12. rtpproxy_stream2xxx usage
-   1.13. start_recording usage
-   1.14. $rtpstat-Usage
-   1.15. nh_enable_rtpp usage
-   1.16. nh_show_rtpp usage
+   1.7. Set ice_candidate_priority_avp parameter
+   1.8. set_rtp_proxy_set usage
+   1.9. rtpproxy_offer usage
+   1.10. rtpproxy_answer usage
+   1.11. rtpproxy_destroy usage
+   1.12. rtpproxy_manage usage
+   1.13. rtpproxy_stream2xxx usage
+   1.14. start_recording usage
+   1.15. $rtpstat-Usage
+   1.16. nh_enable_rtpp usage
+   1.17. nh_show_rtpp usage
 
 
 Chapter 1. Admin Guide
 Chapter 1. Admin Guide
 
 
@@ -122,6 +124,7 @@ Chapter 1. Admin Guide
         4.4. rtpproxy_retr (integer)
         4.4. rtpproxy_retr (integer)
         4.5. nortpproxy_str (string)
         4.5. nortpproxy_str (string)
         4.6. timeout_socket (string)
         4.6. timeout_socket (string)
+        4.7. ice_candidate_priority_avp (string)
 
 
    5. Functions
    5. Functions
 
 
@@ -163,7 +166,7 @@ Chapter 1. Admin Guide
    The module allows definition of several sets of rtpproxies.
    The module allows definition of several sets of rtpproxies.
    Load-balancing will be performed over a set and the admin has the
    Load-balancing will be performed over a set and the admin has the
    ability to choose what set should be used. The set is selected via its
    ability to choose what set should be used. The set is selected via its
-   id - the id being defined with the set. Refer to the "rtpproxy_sock"
+   id - the id being defined with the set. Refer to the “rtpproxy_sock�
    module parameter definition for syntax description.
    module parameter definition for syntax description.
 
 
    The balancing inside a set is done automatically by the module based on
    The balancing inside a set is done automatically by the module based on
@@ -205,13 +208,14 @@ Chapter 1. Admin Guide
    4.4. rtpproxy_retr (integer)
    4.4. rtpproxy_retr (integer)
    4.5. nortpproxy_str (string)
    4.5. nortpproxy_str (string)
    4.6. timeout_socket (string)
    4.6. timeout_socket (string)
+   4.7. ice_candidate_priority_avp (string)
 
 
 4.1. rtpproxy_sock (string)
 4.1. rtpproxy_sock (string)
 
 
    Definition of socket(s) used to connect to (a set) RTPProxy. It may
    Definition of socket(s) used to connect to (a set) RTPProxy. It may
    specify a UNIX socket or an IPv4/IPv6 UDP socket.
    specify a UNIX socket or an IPv4/IPv6 UDP socket.
 
 
-   Default value is "NONE" (disabled).
+   Default value is “NONE� (disabled).
 
 
    Example 1.1. Set rtpproxy_sock parameter
    Example 1.1. Set rtpproxy_sock parameter
 ...
 ...
@@ -233,7 +237,7 @@ modparam("rtpproxy", "rtpproxy_sock",
    rtpproxy module will not attempt to establish communication to RTPProxy
    rtpproxy module will not attempt to establish communication to RTPProxy
    for rtpproxy_disable_tout seconds.
    for rtpproxy_disable_tout seconds.
 
 
-   Default value is "60".
+   Default value is “60�.
 
 
    Example 1.2. Set rtpproxy_disable_tout parameter
    Example 1.2. Set rtpproxy_disable_tout parameter
 ...
 ...
@@ -244,7 +248,7 @@ modparam("rtpproxy", "rtpproxy_disable_tout", 20)
 
 
    Timeout value in waiting for reply from RTPProxy.
    Timeout value in waiting for reply from RTPProxy.
 
 
-   Default value is "1".
+   Default value is “1�.
 
 
    Example 1.3. Set rtpproxy_tout parameter
    Example 1.3. Set rtpproxy_tout parameter
 ...
 ...
@@ -256,7 +260,7 @@ modparam("rtpproxy", "rtpproxy_tout", 2)
    How many times the module should retry to send and receive after
    How many times the module should retry to send and receive after
    timeout was generated.
    timeout was generated.
 
 
-   Default value is "5".
+   Default value is “5�.
 
 
    Example 1.4. Set rtpproxy_retr parameter
    Example 1.4. Set rtpproxy_retr parameter
 ...
 ...
@@ -275,7 +279,7 @@ Note
 
 
    The string must be a complete SDP line, including the EOH (\r\n).
    The string must be a complete SDP line, including the EOH (\r\n).
 
 
-   Default value is "a=nortpproxy:yes\r\n".
+   Default value is “a=nortpproxy:yes\r\n�.
 
 
    Example 1.5. Set nortpproxy_str parameter
    Example 1.5. Set nortpproxy_str parameter
 ...
 ...
@@ -291,13 +295,30 @@ modparam("rtpproxy", "nortpproxy_str", "a=sdpmangled:yes\r\n")
    If it is an empty string, no timeout socket will be transmitted to the
    If it is an empty string, no timeout socket will be transmitted to the
    RTP-Proxy.
    RTP-Proxy.
 
 
-   Default value is "" (nothing).
+   Default value is “� (nothing).
 
 
    Example 1.6. Set timeout_socket parameter
    Example 1.6. Set timeout_socket parameter
 ...
 ...
 modparam("nathelper", "timeout_socket", "xmlrpc:http://127.0.0.1:8000/RPC2")
 modparam("nathelper", "timeout_socket", "xmlrpc:http://127.0.0.1:8000/RPC2")
 ...
 ...
 
 
+4.7. ice_candidate_priority_avp (string)
+
+   If specified and if value of the avp value is not 0, rtpproxy_manage
+   function adds ICE relay candidate attributes to sdp stream(s)
+   containing ICE candidate attributes.
+
+   If value of the avp is 1, added candidates have high priority. If value
+   of the avp is 2 (default), added candidates have low priority.
+
+   There is no default value meaning that no ICE relay candidates are
+   added in any circumstance.
+
+   Example 1.7. Set ice_candidate_priority_avp parameter
+...
+modparam("rtpproxy", "ice_candidate_priority_avp", "$avp(ice_priority)")
+...
+
 5. Functions
 5. Functions
 
 
    5.1. set_rtp_proxy_set(setid)
    5.1. set_rtp_proxy_set(setid)
@@ -322,7 +343,7 @@ modparam("nathelper", "timeout_socket", "xmlrpc:http://127.0.0.1:8000/RPC2")
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    BRANCH_ROUTE.
    BRANCH_ROUTE.
 
 
-   Example 1.7. set_rtp_proxy_set usage
+   Example 1.8. set_rtp_proxy_set usage
 ...
 ...
 set_rtp_proxy_set("2");
 set_rtp_proxy_set("2");
 rtpproxy_offer();
 rtpproxy_offer();
@@ -338,16 +359,16 @@ rtpproxy_offer();
      * flags - flags to turn on some features.
      * flags - flags to turn on some features.
           + 1 - append first Via branch to Call-ID when sending command to
           + 1 - append first Via branch to Call-ID when sending command to
             rtpproxy. This can be used to create one media session per
             rtpproxy. This can be used to create one media session per
-            branch on the rtpproxy. When sending a subsequent "delete"
+            branch on the rtpproxy. When sending a subsequent “delete�
             command to the rtpproxy, you can then stop just the session
             command to the rtpproxy, you can then stop just the session
             for a specific branch when passing the flag '1' or '2' in the
             for a specific branch when passing the flag '1' or '2' in the
-            "unforce_rtpproxy", or stop all sessions for a call when not
+            “unforce_rtpproxy�, or stop all sessions for a call when not
             passing one of those two flags there. This is especially
             passing one of those two flags there. This is especially
             useful if you have serially forked call scenarios where
             useful if you have serially forked call scenarios where
-            rtpproxy gets an "update" command for a new branch, and then a
-            "delete" command for the previous branch, which would
+            rtpproxy gets an “update� command for a new branch, and then a
+            “delete� command for the previous branch, which would
             otherwise delete the full call, breaking the subsequent
             otherwise delete the full call, breaking the subsequent
-            "lookup" for the new branch. This flag is only supported by
+            “lookup� for the new branch. This flag is only supported by
             the ngcp-mediaproxy-ng rtpproxy at the moment!
             the ngcp-mediaproxy-ng rtpproxy at the moment!
           + 2 - append second Via branch to Call-ID when sending command
           + 2 - append second Via branch to Call-ID when sending command
             to rtpproxy. See flag '1' for its meaning.
             to rtpproxy. See flag '1' for its meaning.
@@ -355,7 +376,7 @@ rtpproxy_offer();
             set for a reply.
             set for a reply.
           + a - flags that UA from which message is received doesn't
           + a - flags that UA from which message is received doesn't
             support symmetric RTP. (automatically sets the 'r' flag)
             support symmetric RTP. (automatically sets the 'r' flag)
-          + l - force "lookup", that is, only rewrite SDP when
+          + l - force “lookup�, that is, only rewrite SDP when
             corresponding session already exists in the RTP proxy. By
             corresponding session already exists in the RTP proxy. By
             default is on when the session is to be completed.
             default is on when the session is to be completed.
           + i, e - these flags specify the direction of the SIP message.
           + i, e - these flags specify the direction of the SIP message.
@@ -416,7 +437,7 @@ rtpproxy_offer();
 
 
    This function can be used from ANY_ROUTE.
    This function can be used from ANY_ROUTE.
 
 
-   Example 1.8. rtpproxy_offer usage
+   Example 1.9. rtpproxy_offer usage
 route {
 route {
 ...
 ...
     if (is_method("INVITE")) {
     if (is_method("INVITE")) {
@@ -460,7 +481,7 @@ onreply_route[2]
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    FAILURE_ROUTE, BRANCH_ROUTE.
    FAILURE_ROUTE, BRANCH_ROUTE.
 
 
-   Example 1.9. rtpproxy_answer usage
+   Example 1.10. rtpproxy_answer usage
 
 
    See rtpproxy_offer() function example above for example.
    See rtpproxy_offer() function example above for example.
 
 
@@ -474,25 +495,25 @@ onreply_route[2]
      * flags - flags to turn on some features.
      * flags - flags to turn on some features.
           + 1 - append first Via branch to Call-ID when sending command to
           + 1 - append first Via branch to Call-ID when sending command to
             rtpproxy. This can be used to create one media session per
             rtpproxy. This can be used to create one media session per
-            branch on the rtpproxy. When sending a subsequent "delete"
+            branch on the rtpproxy. When sending a subsequent “delete�
             command to the rtpproxy, you can then stop just the session
             command to the rtpproxy, you can then stop just the session
             for a specific branch when passing the flag '1' or '2' in the
             for a specific branch when passing the flag '1' or '2' in the
-            "unforce_rtpproxy", or stop all sessions for a call when not
+            “unforce_rtpproxy�, or stop all sessions for a call when not
             passing one of those two flags there. This is especially
             passing one of those two flags there. This is especially
             useful if you have serially forked call scenarios where
             useful if you have serially forked call scenarios where
-            rtpproxy gets an "update" command for a new branch, and then a
-            "delete" command for the previous branch, which would
+            rtpproxy gets an “update� command for a new branch, and then a
+            “delete� command for the previous branch, which would
             otherwise delete the full call, breaking the subsequent
             otherwise delete the full call, breaking the subsequent
-            "lookup" for the new branch. This flag is only supported by
+            “lookup� for the new branch. This flag is only supported by
             the ngcp-mediaproxy-ng rtpproxy at the moment!
             the ngcp-mediaproxy-ng rtpproxy at the moment!
           + 2 - append second Via branch to Call-ID when sending command
           + 2 - append second Via branch to Call-ID when sending command
             to rtpproxy. See flag '1' for its meaning.
             to rtpproxy. See flag '1' for its meaning.
-          + t - do not include To tag to "delete" command to rtpproxy thus
+          + t - do not include To tag to “delete� command to rtpproxy thus
             causing full call to be deleted. Useful for deleting unused
             causing full call to be deleted. Useful for deleting unused
             rtpproxy call when 200 OK is received on a branch, where
             rtpproxy call when 200 OK is received on a branch, where
             rtpproxy is not needed.
             rtpproxy is not needed.
 
 
-   Example 1.10. rtpproxy_destroy usage
+   Example 1.11. rtpproxy_destroy usage
 ...
 ...
 rtpproxy_destroy();
 rtpproxy_destroy();
 ...
 ...
@@ -524,7 +545,7 @@ rtpproxy_destroy();
 
 
    This function can be used from ANY_ROUTE.
    This function can be used from ANY_ROUTE.
 
 
-   Example 1.11. rtpproxy_manage usage
+   Example 1.12. rtpproxy_manage usage
 ...
 ...
 rtpproxy_manage();
 rtpproxy_manage();
 ...
 ...
@@ -560,7 +581,7 @@ rtpproxy_manage();
        -1 means that it will be streaming in a loop indefinitely, until
        -1 means that it will be streaming in a loop indefinitely, until
        the appropriate rtpproxy_stop_stream2xxx is issued.
        the appropriate rtpproxy_stop_stream2xxx is issued.
 
 
-   Example 1.12. rtpproxy_stream2xxx usage
+   Example 1.13. rtpproxy_stream2xxx usage
 ...
 ...
     if (is_method("INVITE")) {
     if (is_method("INVITE")) {
         rtpproxy_offer();
         rtpproxy_offer();
@@ -593,7 +614,7 @@ rtpproxy_manage();
 
 
    This function can be used from REQUEST_ROUTE and ONREPLY_ROUTE.
    This function can be used from REQUEST_ROUTE and ONREPLY_ROUTE.
 
 
-   Example 1.13. start_recording usage
+   Example 1.14. start_recording usage
 ...
 ...
 start_recording();
 start_recording();
 ...
 ...
@@ -613,7 +634,7 @@ start_recording();
    packet-counters. The statistics must be retrieved before the session is
    packet-counters. The statistics must be retrieved before the session is
    deleted (before unforce_rtpproxy()).
    deleted (before unforce_rtpproxy()).
 
 
-   Example 1.14. $rtpstat-Usage
+   Example 1.15. $rtpstat-Usage
 ...
 ...
     append_hf("X-RTP-Statistics: $rtpstat\r\n");
     append_hf("X-RTP-Statistics: $rtpstat\r\n");
 ...
 ...
@@ -636,7 +657,7 @@ start_recording();
    NOTE: if a rtpproxy is defined multiple times (in the same or diferente
    NOTE: if a rtpproxy is defined multiple times (in the same or diferente
    sete), all of its instances will be enables/disabled.
    sete), all of its instances will be enables/disabled.
 
 
-   Example 1.15.  nh_enable_rtpp usage
+   Example 1.16.  nh_enable_rtpp usage
 ...
 ...
 $ kamctl fifo nh_enable_rtpp udp:192.168.2.133:8081 0
 $ kamctl fifo nh_enable_rtpp udp:192.168.2.133:8081 0
 ...
 ...
@@ -648,52 +669,52 @@ $ kamctl fifo nh_enable_rtpp udp:192.168.2.133:8081 0
 
 
    No parameter.
    No parameter.
 
 
-   Example 1.16.  nh_show_rtpp usage
+   Example 1.17.  nh_show_rtpp usage
 ...
 ...
 $ kamctl fifo nh_show_rtpp
 $ kamctl fifo nh_show_rtpp
 ...
 ...
 
 
 Chapter 2. Frequently Asked Questions
 Chapter 2. Frequently Asked Questions
 
 
-   2.1. What happend with "rtpproxy_disable" parameter?
+   2.1. What happend with “rtpproxy_disable� parameter?
    2.2. Where can I find more about Kamailio?
    2.2. Where can I find more about Kamailio?
    2.3. Where can I post a question about this module?
    2.3. Where can I post a question about this module?
    2.4. How can I report a bug?
    2.4. How can I report a bug?
 
 
    2.1.
    2.1.
 
 
-   What happend with "rtpproxy_disable" parameter?
+       What happend with “rtpproxy_disable� parameter?
 
 
-   It was removed as it became obsolete - now "rtpproxy_sock" can take
-   empty value to disable the rtpproxy functionality.
+       It was removed as it became obsolete - now “rtpproxy_sock� can take
+       empty value to disable the rtpproxy functionality.
 
 
    2.2.
    2.2.
 
 
-   Where can I find more about Kamailio?
+       Where can I find more about Kamailio?
 
 
-   Take a look at http://www.kamailio.org/.
+       Take a look at http://www.kamailio.org/.
 
 
    2.3.
    2.3.
 
 
-   Where can I post a question about this module?
+       Where can I post a question about this module?
 
 
-   First at all check if your question was already answered on one of our
-   mailing lists:
-     * User Mailing List -
-       http://lists.sip-router.org/cgi-bin/mailman/listinfo/sr-users
-     * Developer Mailing List -
-       http://lists.sip-router.org/cgi-bin/mailman/listinfo/sr-dev
+       First at all check if your question was already answered on one of our
+       mailing lists:
+         * User Mailing List -
+           http://lists.sip-router.org/cgi-bin/mailman/listinfo/sr-users
+         * Developer Mailing List -
+           http://lists.sip-router.org/cgi-bin/mailman/listinfo/sr-dev
 
 
-   E-mails regarding any stable Kamailio release should be sent to
-   <[email protected]> and e-mails regarding development
-   versions should be sent to <[email protected]>.
+       E-mails regarding any stable Kamailio release should be sent to
+       <[email protected]> and e-mails regarding development
+       versions should be sent to <[email protected]>.
 
 
-   If you want to keep the mail private, send it to
-   <[email protected]>.
+       If you want to keep the mail private, send it to
+       <[email protected]>.
 
 
    2.4.
    2.4.
 
 
-   How can I report a bug?
+       How can I report a bug?
 
 
-   Please follow the guidelines provided at:
-   http://sip-router.org/tracker.
+       Please follow the guidelines provided at:
+       http://sip-router.org/tracker.

+ 28 - 0
modules/rtpproxy/doc/rtpproxy_admin.xml

@@ -232,6 +232,34 @@ modparam("rtpproxy", "nortpproxy_str", "a=sdpmangled:yes\r\n")
 ...
 ...
 modparam("nathelper", "timeout_socket", "xmlrpc:http://127.0.0.1:8000/RPC2")
 modparam("nathelper", "timeout_socket", "xmlrpc:http://127.0.0.1:8000/RPC2")
 ...
 ...
+</programlisting>
+		</example>
+	</section>
+	<section>
+		<title><varname>ice_candidate_priority_avp</varname> (string)</title>
+		<para>
+		If specified and if value of the avp value is not 0,
+		<function>rtpproxy_manage</function> function adds
+		ICE relay candidate attributes
+		to sdp stream(s) containing ICE candidate attributes.
+		</para>
+		<para>
+		If value of the avp is 1, added candidates
+		have high priority.  If value of the avp is 2 (default),
+		added candidates have low priority.
+		</para>
+		<para>
+		<emphasis>
+		There is no default value meaning that no ICE relay
+		candidates are added in any circumstance.
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>ice_candidate_priority_avp</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("rtpproxy", "ice_candidate_priority_avp", "$avp(ice_priority)")
+...
 </programlisting>
 </programlisting>
 		</example>
 		</example>
 	</section>
 	</section>

+ 137 - 2
modules/rtpproxy/rtpproxy.c

@@ -331,6 +331,9 @@ static unsigned int current_msg_id = (unsigned int)-1;
 struct rtpp_set_head * rtpp_set_list =0;
 struct rtpp_set_head * rtpp_set_list =0;
 struct rtpp_set * selected_rtpp_set =0;
 struct rtpp_set * selected_rtpp_set =0;
 struct rtpp_set * default_rtpp_set=0;
 struct rtpp_set * default_rtpp_set=0;
+static char *ice_candidate_priority_avp_param = NULL;
+static int ice_candidate_priority_avp_type;
+static int_str ice_candidate_priority_avp;
 
 
 /* array with the sockets used by rtpporxy (per process)*/
 /* array with the sockets used by rtpporxy (per process)*/
 static unsigned int rtpp_no = 0;
 static unsigned int rtpp_no = 0;
@@ -425,6 +428,8 @@ static param_export_t params[] = {
 	{"rtpproxy_retr",         INT_PARAM, &rtpproxy_retr         },
 	{"rtpproxy_retr",         INT_PARAM, &rtpproxy_retr         },
 	{"rtpproxy_tout",         INT_PARAM, &rtpproxy_tout         },
 	{"rtpproxy_tout",         INT_PARAM, &rtpproxy_tout         },
 	{"timeout_socket",    	  STR_PARAM, &timeout_socket_str.s  },
 	{"timeout_socket",    	  STR_PARAM, &timeout_socket_str.s  },
+	{"ice_candidate_priority_avp", STR_PARAM,
+	 &ice_candidate_priority_avp_param},
 	{0, 0, 0}
 	{0, 0, 0}
 };
 };
 
 
@@ -868,6 +873,9 @@ static int
 mod_init(void)
 mod_init(void)
 {
 {
 	int i;
 	int i;
+	pv_spec_t avp_spec;
+	str s;
+	unsigned short avp_flags;
 
 
 	if(register_mi_mod(exports.name, mi_cmds)!=0)
 	if(register_mi_mod(exports.name, mi_cmds)!=0)
 	{
 	{
@@ -910,6 +918,19 @@ mod_init(void)
 		timeout_socket_str.len = strlen(timeout_socket_str.s);
 		timeout_socket_str.len = strlen(timeout_socket_str.s);
 	}
 	}
 
 
+	if (ice_candidate_priority_avp_param) {
+	    s.s = ice_candidate_priority_avp_param; s.len = strlen(s.s);
+	    if (pv_parse_spec(&s, &avp_spec) == 0 || avp_spec.type != PVT_AVP) {
+		LM_ERR("malformed or non AVP definition <%s>\n", ice_candidate_priority_avp_param);
+		return -1;
+	    }
+	    if (pv_get_avp_name(0, &(avp_spec.pvp), &ice_candidate_priority_avp, &avp_flags) != 0) {
+		LM_ERR("invalid AVP definition <%s>\n", ice_candidate_priority_avp_param);
+		return -1;
+	    }
+	    ice_candidate_priority_avp_type = avp_flags;
+	}
+
 	if (rtpp_strings)
 	if (rtpp_strings)
 		pkg_free(rtpp_strings);
 		pkg_free(rtpp_strings);
 
 
@@ -1379,6 +1400,88 @@ alter_rtcp(struct sip_msg *msg, str *body, str *oldport, str *newport)
 	return 0;
 	return 0;
 }
 }
 
 
+
+static char *
+append_filtered_ip(char *at, str *ip)
+{
+    int i;
+    for (i = 0; i < ip->len; i++) {
+	if (isdigit(ip->s[i])) {
+	    append_chr(at, ip->s[i]);
+	}
+    }
+    return at;
+}
+
+		
+static int
+insert_candidates(struct sip_msg *msg, char *where, str *ip, unsigned int port,
+		  str *rtcp_port, int priority)
+{
+    char *buf, *at;
+    struct lump* anchor;
+    str rtp_port;
+
+    if (rtcp_port->len) {
+	buf = pkg_malloc(24 + 78 + 14 + 24 + 2*ip->len + 2 + 2*rtcp_port->len +
+			 24);
+    } else {
+	buf = pkg_malloc(12 + 39 + 12 + 12 + ip->len + 1 + rtcp_port->len + 12);
+    }	
+    if (buf == NULL) {
+	LM_ERR("insert_candidates: out of memory\n");
+	return -1;
+    }
+
+    at = buf;
+
+    if (rtcp_port->len) {
+	append_str(at, "a=candidate:", 12);
+	at = append_filtered_ip(at, ip);
+	append_str(at, " 2 UDP ", 7);
+	if (priority == 2) {
+	    append_str(at, "16777214 ", 9);
+	} else {
+	    append_str(at, "2197815294 ", 11);
+	}
+	append_str(at, ip->s, ip->len);
+	append_chr(at, ' ');
+	append_str(at, rtcp_port->s, rtcp_port->len);
+	append_str(at, " typ relay\r\n", 12);
+    }
+
+    rtp_port.s = int2str(port, &rtp_port.len);
+    append_str(at, "a=candidate:", 12);
+    at = append_filtered_ip(at, ip);
+    append_str(at, " 1 UDP ", 7);
+    if (priority == 2) {
+	append_str(at, "16777215 ", 9);
+    } else {
+	append_str(at, "2197815295 ", 11);
+    }
+    append_str(at, ip->s, ip->len);
+    append_chr(at, ' ');
+    append_str(at, rtp_port.s, rtp_port.len);
+    append_str(at, " typ relay\r\n", 12);
+
+    LM_DBG("inserting '%.*s'\n", at - buf, buf);
+
+    anchor = anchor_lump(msg, where - msg->buf, 0, 0);
+    if (anchor == 0) {
+	LOG(L_ERR, "insert_candidates: can't get anchor\n");
+	pkg_free(buf);
+	return -1;
+    }
+    if (insert_new_lump_before(anchor, buf, at - buf, 0) == 0) {
+	LM_ERR("insert_candidates: insert_new_lump_before failed\n");
+	pkg_free(buf);
+	return -1;
+    }
+
+    return 0;
+}
+    
+
 static char * gencookie(void)
 static char * gencookie(void)
 {
 {
 	static char cook[34];
 	static char cook[34];
@@ -2002,7 +2105,8 @@ force_rtp_proxy(struct sip_msg* msg, char* str1, char* str2, int offer, int forc
 {
 {
 	str body, body1, oldport, oldip, newport, newip;
 	str body, body1, oldport, oldip, newport, newip;
 	str callid, from_tag, to_tag, tmp, payload_types;
 	str callid, from_tag, to_tag, tmp, payload_types;
-	str newrtcp, viabranch;
+	str newrtcp = {0, 0};
+	str viabranch;
 	int create, port, len, flookup, argc, proxied, real, via, ret;
 	int create, port, len, flookup, argc, proxied, real, via, ret;
 	int orgip, commip;
 	int orgip, commip;
 	int pf, pf1, force;
 	int pf, pf1, force;
@@ -2049,6 +2153,8 @@ force_rtp_proxy(struct sip_msg* msg, char* str1, char* str2, int offer, int forc
 	sdp_session_cell_t* sdp_session;
 	sdp_session_cell_t* sdp_session;
 	sdp_stream_cell_t* sdp_stream;
 	sdp_stream_cell_t* sdp_stream;
 
 
+	int_str ice_candidate_priority_val;
+
 	memset(&opts, '\0', sizeof(opts));
 	memset(&opts, '\0', sizeof(opts));
 	memset(&rep_opts, '\0', sizeof(rep_opts));
 	memset(&rep_opts, '\0', sizeof(rep_opts));
 	memset(&pt_opts, '\0', sizeof(pt_opts));
 	memset(&pt_opts, '\0', sizeof(pt_opts));
@@ -2268,6 +2374,22 @@ force_rtp_proxy(struct sip_msg* msg, char* str1, char* str2, int offer, int forc
 	STR2IOVEC(from_tag, v[13]);
 	STR2IOVEC(from_tag, v[13]);
 	STR2IOVEC(to_tag, v[17]);
 	STR2IOVEC(to_tag, v[17]);
 
 
+	if (ice_candidate_priority_avp_param) {
+	    if (search_first_avp(ice_candidate_priority_avp_type,
+				 ice_candidate_priority_avp,
+				 &ice_candidate_priority_val, 0)
+		== NULL) {
+		ice_candidate_priority_val.n = 2;
+	    } else if ((ice_candidate_priority_val.n < 1) ||
+		       (ice_candidate_priority_val.n > 2)) {
+		LM_ERR("invalid ice candidate priority value %d\n",
+		       ice_candidate_priority_val.n);
+		FORCE_RTP_PROXY_RET (-1);
+	    }
+	} else {
+	    ice_candidate_priority_val.n = 0;
+	}
+
 	/* check if this is a single or a multi stream SDP offer/answer */
 	/* check if this is a single or a multi stream SDP offer/answer */
 	sdp_stream_num = get_sdp_stream_num(msg);
 	sdp_stream_num = get_sdp_stream_num(msg);
 	switch (sdp_stream_num) {
 	switch (sdp_stream_num) {
@@ -2294,7 +2416,8 @@ force_rtp_proxy(struct sip_msg* msg, char* str1, char* str2, int offer, int forc
 		o1p = sdp_session->o_ip_addr.s;
 		o1p = sdp_session->o_ip_addr.s;
 		for(;;) {
 		for(;;) {
 			sdp_stream = get_sdp_stream(msg, sdp_session_num, sdp_stream_num);
 			sdp_stream = get_sdp_stream(msg, sdp_session_num, sdp_stream_num);
-			if(!sdp_stream) break;
+			if (!sdp_stream ||
+			    (ice_candidate_priority_val.n && sdp_stream->remote_candidates.len)) break;
 
 
 			if (sdp_stream->ip_addr.s && sdp_stream->ip_addr.len>0) {
 			if (sdp_stream->ip_addr.s && sdp_stream->ip_addr.len>0) {
 				oldip = sdp_stream->ip_addr;
 				oldip = sdp_stream->ip_addr;
@@ -2509,6 +2632,7 @@ force_rtp_proxy(struct sip_msg* msg, char* str1, char* str2, int offer, int forc
 			 * See RFC 3605 for definition of RTCP attribute.
 			 * See RFC 3605 for definition of RTCP attribute.
 			 * ported from ser
 			 * ported from ser
 			 */
 			 */
+
 			if (sdp_stream->rtcp_port.s && sdp_stream->rtcp_port.len) {
 			if (sdp_stream->rtcp_port.s && sdp_stream->rtcp_port.len) {
 				newrtcp.s = int2str(port+1, &newrtcp.len); /* beware static buffer */
 				newrtcp.s = int2str(port+1, &newrtcp.len); /* beware static buffer */
 				/* Alter port. */
 				/* Alter port. */
@@ -2522,6 +2646,17 @@ force_rtp_proxy(struct sip_msg* msg, char* str1, char* str2, int offer, int forc
 				}
 				}
 			}
 			}
 
 
+			/* Add ice relay candidates */
+			if (ice_candidate_priority_val.n && sdp_stream->ice_attrs_num > 0) {
+			    body1.s = sdp_stream->ice_attr->foundation.s - 12;
+			    body1.len = bodylimit - body1.s;
+			    if (insert_candidates(msg, sdp_stream->ice_attr->foundation.s - 12,
+						  &newip, port, &newrtcp,
+						  ice_candidate_priority_val.n) == -1) {
+				FORCE_RTP_PROXY_RET (-1);
+			    }
+			}
+
 			c1p = sdp_session->ip_addr.s;
 			c1p = sdp_session->ip_addr.s;
 			c2p = sdp_stream->ip_addr.s;
 			c2p = sdp_stream->ip_addr.s;
 			/*
 			/*