Browse Source

modules/rtpproxy: Add 'b' flag to add a branch specific string tot the call-id

In a forking call, sometimes it is needed that each branch uses different
options to the rtpproxy. This patch adds a parameter that makes each
rtpproxy session unique to a branch by appending the value of a PV to the
call-id rtpproxy parameter.
Alex Hermann 13 years ago
parent
commit
a2d09db983
3 changed files with 168 additions and 48 deletions
  1. 77 46
      modules/rtpproxy/README
  2. 37 0
      modules/rtpproxy/doc/rtpproxy_admin.xml
  3. 54 2
      modules/rtpproxy/rtpproxy.c

+ 77 - 46
modules/rtpproxy/README

@@ -30,13 +30,13 @@ Carsten Bock
 
 
    ng-voice GmbH
    ng-voice GmbH
 
 
-   Copyright © 2003-2008 Sippy Software, Inc.
+   Copyright (c) 2003-2008 Sippy Software, Inc.
 
 
-   Copyright © 2005 Voice Sistem SRL
+   Copyright (c) 2005 Voice Sistem SRL
 
 
-   Copyright © 2009-2012 TuTPro Inc.
+   Copyright (c) 2009-2012 TuTPro Inc.
 
 
-   Copyright © 2010 VoIPEmbedded Inc.
+   Copyright (c) 2010 VoIPEmbedded Inc.
      __________________________________________________________________
      __________________________________________________________________
 
 
    Table of Contents
    Table of Contents
@@ -59,6 +59,7 @@ Carsten Bock
               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.7. ice_candidate_priority_avp (string)
+              4.8. extra_id_pv (string)
 
 
         5. Functions
         5. Functions
 
 
@@ -94,16 +95,17 @@ Carsten Bock
    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 ice_candidate_priority_avp parameter
    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
+   1.8. Set extra_id_pv parameter
+   1.9. set_rtp_proxy_set usage
+   1.10. rtpproxy_offer usage
+   1.11. rtpproxy_answer usage
+   1.12. rtpproxy_destroy usage
+   1.13. rtpproxy_manage usage
+   1.14. rtpproxy_stream2xxx usage
+   1.15. start_recording usage
+   1.16. $rtpstat-Usage
+   1.17. nh_enable_rtpp usage
+   1.18. nh_show_rtpp usage
 
 
 Chapter 1. Admin Guide
 Chapter 1. Admin Guide
 
 
@@ -125,6 +127,7 @@ Chapter 1. Admin Guide
         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.7. ice_candidate_priority_avp (string)
+        4.8. extra_id_pv (string)
 
 
    5. Functions
    5. Functions
 
 
@@ -166,7 +169,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
@@ -209,13 +212,14 @@ Chapter 1. Admin Guide
    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.7. ice_candidate_priority_avp (string)
+   4.8. extra_id_pv (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
 ...
 ...
@@ -237,7 +241,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
 ...
 ...
@@ -248,7 +252,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
 ...
 ...
@@ -260,7 +264,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
 ...
 ...
@@ -279,7 +283,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
 ...
 ...
@@ -295,7 +299,7 @@ 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
 ...
 ...
@@ -319,6 +323,19 @@ modparam("nathelper", "timeout_socket", "xmlrpc:http://127.0.0.1:8000/RPC2")
 modparam("rtpproxy", "ice_candidate_priority_avp", "$avp(ice_priority)")
 modparam("rtpproxy", "ice_candidate_priority_avp", "$avp(ice_priority)")
 ...
 ...
 
 
+4.8. extra_id_pv (string)
+
+   The parameter sets the PV defination to use when the "b" parameter is
+   used on unforce_rtp_proxy(), rtpproxy_offer(), rtpproxy_answer() or
+   rtpproxy_manage() command.
+
+   Default is empty, the "b" parameter may not be used then.
+
+   Example 1.8. Set extra_id_pv parameter
+...
+modparam("rtpproxy", "extra_id_pv", "$avp(extra_id)")
+...
+
 5. Functions
 5. Functions
 
 
    5.1. set_rtp_proxy_set(setid)
    5.1. set_rtp_proxy_set(setid)
@@ -343,7 +360,7 @@ modparam("rtpproxy", "ice_candidate_priority_avp", "$avp(ice_priority)")
    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.8. set_rtp_proxy_set usage
+   Example 1.9. set_rtp_proxy_set usage
 ...
 ...
 set_rtp_proxy_set("2");
 set_rtp_proxy_set("2");
 rtpproxy_offer();
 rtpproxy_offer();
@@ -359,16 +376,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.
@@ -376,7 +393,18 @@ 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
+          + b - append branch specific variable to Call-ID when sending
+            command to rtpproxy. This creates one rtpproxy session per
+            unique variable. Works similar to the 1, 2 and 3 parameter,
+            but is usefull when forking to multiple destinations on
+            different address families or network segments, requiring
+            different rtpproxy parameters. The variable value is taken
+            from the "extra_id_pv". When used, it must be used in every
+            call to rtpproxy_manage(), rtpproxy_offer(), rtpproxy_answer()
+            and rtpproxy_destroy() with the same contents of the PV. The b
+            parameter may not be used in conjunction with the 1, 2 or 3
+            parameter to use the Via branch in the Call-ID.
+          + 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.
@@ -437,7 +465,7 @@ rtpproxy_offer();
 
 
    This function can be used from ANY_ROUTE.
    This function can be used from ANY_ROUTE.
 
 
-   Example 1.9. rtpproxy_offer usage
+   Example 1.10. rtpproxy_offer usage
 route {
 route {
 ...
 ...
     if (is_method("INVITE")) {
     if (is_method("INVITE")) {
@@ -481,7 +509,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.10. rtpproxy_answer usage
+   Example 1.11. rtpproxy_answer usage
 
 
    See rtpproxy_offer() function example above for example.
    See rtpproxy_offer() function example above for example.
 
 
@@ -495,25 +523,28 @@ 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
+          + b - append branch number to Call-ID when sending command to
+            rtpproxy. <listitem>
+            </listitem>
+            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.11. rtpproxy_destroy usage
+   Example 1.12. rtpproxy_destroy usage
 ...
 ...
 rtpproxy_destroy();
 rtpproxy_destroy();
 ...
 ...
@@ -545,7 +576,7 @@ rtpproxy_destroy();
 
 
    This function can be used from ANY_ROUTE.
    This function can be used from ANY_ROUTE.
 
 
-   Example 1.12. rtpproxy_manage usage
+   Example 1.13. rtpproxy_manage usage
 ...
 ...
 rtpproxy_manage();
 rtpproxy_manage();
 ...
 ...
@@ -581,7 +612,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.13. rtpproxy_stream2xxx usage
+   Example 1.14. rtpproxy_stream2xxx usage
 ...
 ...
     if (is_method("INVITE")) {
     if (is_method("INVITE")) {
         rtpproxy_offer();
         rtpproxy_offer();
@@ -614,7 +645,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.14. start_recording usage
+   Example 1.15. start_recording usage
 ...
 ...
 start_recording();
 start_recording();
 ...
 ...
@@ -634,7 +665,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.15. $rtpstat-Usage
+   Example 1.16. $rtpstat-Usage
 ...
 ...
     append_hf("X-RTP-Statistics: $rtpstat\r\n");
     append_hf("X-RTP-Statistics: $rtpstat\r\n");
 ...
 ...
@@ -657,7 +688,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.16.  nh_enable_rtpp usage
+   Example 1.17.  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
 ...
 ...
@@ -669,23 +700,23 @@ $ kamctl fifo nh_enable_rtpp udp:192.168.2.133:8081 0
 
 
    No parameter.
    No parameter.
 
 
-   Example 1.17.  nh_show_rtpp usage
+   Example 1.18.  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
+       It was removed as it became obsolete - now "rtpproxy_sock" can take
        empty value to disable the rtpproxy functionality.
        empty value to disable the rtpproxy functionality.
 
 
    2.2.
    2.2.

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

@@ -260,6 +260,24 @@ modparam("nathelper", "timeout_socket", "xmlrpc:http://127.0.0.1:8000/RPC2")
 ...
 ...
 modparam("rtpproxy", "ice_candidate_priority_avp", "$avp(ice_priority)")
 modparam("rtpproxy", "ice_candidate_priority_avp", "$avp(ice_priority)")
 ...
 ...
+</programlisting>
+		</example>
+	</section>
+	<section>
+		<title><varname>extra_id_pv</varname> (string)</title>
+		<para>
+			The parameter sets the PV defination to use when the <quote>b</quote>
+			parameter is used on unforce_rtp_proxy(), rtpproxy_offer(),
+			rtpproxy_answer() or rtpproxy_manage() command.
+		</para><para>
+			Default is empty, the <quote>b</quote> parameter may not be used then.
+		</para>
+		<example>
+		<title>Set <varname>extra_id_pv</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("rtpproxy", "extra_id_pv", "$avp(extra_id)")
+...
 </programlisting>
 </programlisting>
 		</example>
 		</example>
 	</section>
 	</section>
@@ -335,6 +353,21 @@ rtpproxy_offer();
 				received doesn't support symmetric RTP. (automatically sets the 'r' flag)
 				received doesn't support symmetric RTP. (automatically sets the 'r' flag)
 				</para></listitem>
 				</para></listitem>
 				<listitem><para>
 				<listitem><para>
+				<emphasis>b</emphasis> - append branch specific variable to Call-ID when sending
+				command to rtpproxy. This creates one rtpproxy session per unique variable.
+
+				Works similar to the 1, 2 and 3 parameter, but is usefull when forking to multiple
+				destinations on different address families or network segments, requiring different
+				rtpproxy parameters.
+
+				The variable value is taken from the <quote>extra_id_pv</quote>.
+
+				When used, it must be used in every call to rtpproxy_manage(), rtpproxy_offer(),
+				rtpproxy_answer() and rtpproxy_destroy() with the same contents of the PV.
+				The b parameter may not be used in conjunction with the 1, 2 or 3 parameter
+				to use the Via branch in the Call-ID.
+				</para></listitem>
+				<listitem><para>
 				<emphasis>l</emphasis> - force <quote>lookup</quote>, that is,
 				<emphasis>l</emphasis> - force <quote>lookup</quote>, that is,
 				only rewrite SDP when corresponding session already exists
 				only rewrite SDP when corresponding session already exists
 				in the RTP proxy. By default is on when the session is to be
 				in the RTP proxy. By default is on when the session is to be
@@ -512,6 +545,10 @@ onreply_route[2]
 				command to rtpproxy. See flag '1' for its meaning.
 				command to rtpproxy. See flag '1' for its meaning.
 				</para></listitem>
 				</para></listitem>
 				<listitem><para>
 				<listitem><para>
+				<emphasis>b</emphasis> - append branch specific variable to Call-ID when sending
+				command to rtpproxy. See rtpproxy_offer() for details.
+				<listitem><para>
+				</para></listitem>
 				<emphasis>t</emphasis> - do not include To tag to <quote>delete</quote> command to rtpproxy thus causing full call to be deleted. Useful for deleting unused rtpproxy call when 200 OK is received on a branch, where rtpproxy is not needed.
 				<emphasis>t</emphasis> - do not include To tag to <quote>delete</quote> command to rtpproxy thus causing full call to be deleted. Useful for deleting unused rtpproxy call when 200 OK is received on a branch, where rtpproxy is not needed.
 				</para></listitem>
 				</para></listitem>
 			</itemizedlist>
 			</itemizedlist>

+ 54 - 2
modules/rtpproxy/rtpproxy.c

@@ -322,6 +322,7 @@ static int rtpproxy_tout = 1;
 static pid_t mypid;
 static pid_t mypid;
 static unsigned int myseqn = 0;
 static unsigned int myseqn = 0;
 static str nortpproxy_str = str_init("a=nortpproxy:yes");
 static str nortpproxy_str = str_init("a=nortpproxy:yes");
+static str extra_id_pv_param = {NULL, 0};
 
 
 static char ** rtpp_strings=0;
 static char ** rtpp_strings=0;
 static int rtpp_sets=0; /*used in rtpproxy_set_store()*/
 static int rtpp_sets=0; /*used in rtpproxy_set_store()*/
@@ -352,6 +353,7 @@ static struct tm_binds tmb;
 unsigned int *natping_state=0;
 unsigned int *natping_state=0;
 
 
 static str timeout_socket_str = {0, 0};
 static str timeout_socket_str = {0, 0};
+static pv_elem_t *extra_id_pv = NULL;
 
 
 static cmd_export_t cmds[] = {
 static cmd_export_t cmds[] = {
 	{"set_rtp_proxy_set",  (cmd_function)set_rtp_proxy_set_f,    1,
 	{"set_rtp_proxy_set",  (cmd_function)set_rtp_proxy_set_f,    1,
@@ -430,6 +432,7 @@ static param_export_t params[] = {
 	{"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", STR_PARAM,
 	 &ice_candidate_priority_avp_param},
 	 &ice_candidate_priority_avp_param},
+	{"extra_id_pv",           STR_PARAM, &extra_id_pv_param.s },
 	{0, 0, 0}
 	{0, 0, 0}
 };
 };
 
 
@@ -931,6 +934,16 @@ mod_init(void)
 	    ice_candidate_priority_avp_type = avp_flags;
 	    ice_candidate_priority_avp_type = avp_flags;
 	}
 	}
 
 
+	if (extra_id_pv_param.s && *extra_id_pv_param.s) {
+		extra_id_pv_param.len = strlen(extra_id_pv_param.s);
+		if(pv_parse_format(&extra_id_pv_param, &extra_id_pv) < 0) {
+			LM_ERR("malformed PV string: %s\n", extra_id_pv_param.s);
+			return -1;
+		}
+	} else {
+		extra_id_pv = NULL;
+	}
+
 	if (rtpp_strings)
 	if (rtpp_strings)
 		pkg_free(rtpp_strings);
 		pkg_free(rtpp_strings);
 
 
@@ -1773,6 +1786,22 @@ found:
 	return node;
 	return node;
 }
 }
 
 
+
+static int
+get_extra_id(struct sip_msg* msg, str *id_str) {
+	if(msg==NULL || extra_id_pv==NULL || id_str==NULL) {
+		LM_ERR("bad parameters\n");
+		return 0;
+	}
+	if (pv_printf_s(msg, extra_id_pv, id_str)<0) {
+		LM_ERR("cannot print the additional id\n");
+		return 0;
+	}
+
+	return 1;
+}
+
+
 static int
 static int
 unforce_rtp_proxy_f(struct sip_msg* msg, char* flags, char* str2)
 unforce_rtp_proxy_f(struct sip_msg* msg, char* flags, char* str2)
 {
 {
@@ -1780,10 +1809,12 @@ unforce_rtp_proxy_f(struct sip_msg* msg, char* flags, char* str2)
 	char *cp;
 	char *cp;
 	int via = 0;
 	int via = 0;
 	int to = 1;
 	int to = 1;
+	int extra = 0;
+	str extra_id;
 	int ret;
 	int ret;
 	struct rtpp_node *node;
 	struct rtpp_node *node;
 	struct iovec v[1 + 4 + 3 + 2] = {{NULL, 0}, {"D", 1}, {" ", 1}, {NULL, 0}, {NULL, 0}, {NULL, 0}, {" ", 1}, {NULL, 0}, {" ", 1}, {NULL, 0}};
 	struct iovec v[1 + 4 + 3 + 2] = {{NULL, 0}, {"D", 1}, {" ", 1}, {NULL, 0}, {NULL, 0}, {NULL, 0}, {" ", 1}, {NULL, 0}, {" ", 1}, {NULL, 0}};
-						    /* 1 */   /* 2 */   /* 3 */    /* 4 */    /* 5 */    /* 6 */   /* 7 */    /* 8 */   /* 9 */
+	                                            /* 1 */   /* 2 */   /* 3 */    /* 4 */    /* 5 */    /* 6 */   /* 7 */    /* 8 */   /* 9 */
 
 
 	for (cp = flags; cp && *cp; cp++) {
 	for (cp = flags; cp && *cp; cp++) {
 		switch (*cp) {
 		switch (*cp) {
@@ -1806,6 +1837,9 @@ unforce_rtp_proxy_f(struct sip_msg* msg, char* flags, char* str2)
 		        case 'T':
 		        case 'T':
 			    to = 0;
 			    to = 0;
 			    break;
 			    break;
+			case 'b':
+				extra = 1;
+				break;
 			case 'a':
 			case 'a':
 			case 'A':
 			case 'A':
 			case 'i':
 			case 'i':
@@ -1863,6 +1897,12 @@ unforce_rtp_proxy_f(struct sip_msg* msg, char* flags, char* str2)
 		v[4].iov_base = ";";
 		v[4].iov_base = ";";
 		v[4].iov_len = 1;
 		v[4].iov_len = 1;
 		STR2IOVEC(viabranch, v[5]);
 		STR2IOVEC(viabranch, v[5]);
+	} else
+	/* Append extra id to call-id */
+	if (extra && extra_id_pv && get_extra_id(msg, &extra_id)) {
+		v[4].iov_base = ";";
+		v[4].iov_len = 1;
+		STR2IOVEC(extra_id, v[5]);
 	}
 	}
 	STR2IOVEC(callid, v[3]);
 	STR2IOVEC(callid, v[3]);
 	STR2IOVEC(from_tag, v[7]);
 	STR2IOVEC(from_tag, v[7]);
@@ -2140,6 +2180,8 @@ force_rtp_proxy(struct sip_msg* msg, char* str1, char* str2, int offer, int forc
 	};
 	};
 	int iovec_param_count;
 	int iovec_param_count;
 	int autobridge_ipv4v6;
 	int autobridge_ipv4v6;
+	int extra;
+	str extra_id;
 
 
 	char *c1p, *c2p, *bodylimit, *o1p;
 	char *c1p, *c2p, *bodylimit, *o1p;
 	char itoabuf_buf[20];
 	char itoabuf_buf[20];
@@ -2161,7 +2203,7 @@ force_rtp_proxy(struct sip_msg* msg, char* str1, char* str2, int offer, int forc
 		LM_ERR("out of pkg memory\n");
 		LM_ERR("out of pkg memory\n");
 		FORCE_RTP_PROXY_RET (-1);
 		FORCE_RTP_PROXY_RET (-1);
 	}
 	}
-	flookup = force = real = orgip = commip = via = autobridge_ipv4v6 = 0;
+	flookup = force = real = orgip = commip = via = autobridge_ipv4v6 = extra = 0;
 	for (cp = str1; cp != NULL && *cp != '\0'; cp++) {
 	for (cp = str1; cp != NULL && *cp != '\0'; cp++) {
 		switch (*cp) {
 		switch (*cp) {
 		case '1':
 		case '1':
@@ -2188,6 +2230,10 @@ force_rtp_proxy(struct sip_msg* msg, char* str1, char* str2, int offer, int forc
 			real = 1;
 			real = 1;
 			break;
 			break;
 
 
+		case 'b':
+			extra = 1;
+			break;
+
 		case 'i':
 		case 'i':
 		case 'I':
 		case 'I':
 			if (append_opts(&opts, 'I') == -1) {
 			if (append_opts(&opts, 'I') == -1) {
@@ -2308,6 +2354,12 @@ force_rtp_proxy(struct sip_msg* msg, char* str1, char* str2, int offer, int forc
 		v[6].iov_base = ";";
 		v[6].iov_base = ";";
 		v[6].iov_len = 1;
 		v[6].iov_len = 1;
 		STR2IOVEC(viabranch, v[7]);
 		STR2IOVEC(viabranch, v[7]);
+	} else
+	/* Append extra id to call-id */
+	if (extra && extra_id_pv && get_extra_id(msg, &extra_id)) {
+		v[6].iov_base = ";";
+		v[6].iov_len = 1;
+		STR2IOVEC(extra_id, v[7]);
 	}
 	}
 	if (flookup != 0) {
 	if (flookup != 0) {
 		if (to_tag.len == 0) {
 		if (to_tag.len == 0) {