<p>Harald Welte <strong>merged</strong> this change.</p><p><a href="https://gerrit.osmocom.org/9768">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  Jenkins Builder: Verified
  Harald Welte: Looks good to me, approved

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">MGCP_Test: add tests to verify actual RTP flows<br><br>The test coverage of the RTP aspects of the MGW is currently very<br>minima. Lets add a few more testcase to verify RTP behaves as<br>expected in various situations.<br><br>- Add testcase TC_one_crcx_receive_only_rtp:<br>  Test recvonly mode of the MGW. All packets must be absorbed by<br>  the MGW, no packets must come back.<br><br>- Add testcase TC_one_crcx_loopback_rtp:<br>  Test loopback mode of the MGW. All packet sent to the MGW must<br>  come back.<br><br>- Add testcase TC_two_crcx_and_rtp_bidir:<br>  We already test unidirectional transmissions. This test does<br>  the same as TC_two_crcx_and_rtp but for both directions.<br><br>- Add testcase TC_two_crcx_mdcx_and_rtp:<br>  Simulate a typical behaviour of a normal call. First create<br>  two half open connections and complete the connections later<br>  using MDCX.<br><br>- Add testcase TC_two_crcx_and_unsolicited_rtp:<br>  Test what happens when a RTP packets from rogue source are mixed<br>  into the RTP stream.<br><br>- Add testcase TC_two_crcx_and_one_mdcx_rtp_ho:<br>  Test a typical handover situation. An existing connection is<br>  handovered to another source on one end but the old source will<br>  keep transmitting for a while.<br><br>Change-Id: I556a6efff0e74aab897bd8165200eec36e46629f<br>Closes: OS#2703<br>---<br>M library/RTP_Emulation.ttcn<br>M mgw/MGCP_Test.ttcn<br>M mgw/expected-results.xml<br>3 files changed, 423 insertions(+), 33 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/library/RTP_Emulation.ttcn b/library/RTP_Emulation.ttcn</span><br><span>index 20e4299..475b478 100644</span><br><span>--- a/library/RTP_Emulation.ttcn</span><br><span>+++ b/library/RTP_Emulation.ttcn</span><br><span>@@ -188,19 +188,56 @@</span><br><span>         return stats;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-function f_rtpem_stats_compare(RtpemStats a, RtpemStats b) return boolean {</span><br><span style="color: hsl(0, 100%, 40%);">-       log("stats A: ", a);</span><br><span style="color: hsl(0, 100%, 40%);">-  log("stats B: ", b);</span><br><span style="color: hsl(120, 100%, 40%);">+function f_rtpem_stats_compare_value(integer a, integer b, integer tolerance := 0) return boolean {</span><br><span style="color: hsl(120, 100%, 40%);">+   var integer temp;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   if (a.num_pkts_tx != b.num_pkts_rx or</span><br><span style="color: hsl(0, 100%, 40%);">-       a.num_pkts_rx != b.num_pkts_tx or</span><br><span style="color: hsl(0, 100%, 40%);">-       a.bytes_payload_tx != b.bytes_payload_rx or</span><br><span style="color: hsl(0, 100%, 40%);">-     a.bytes_payload_rx != b.bytes_payload_tx) {</span><br><span style="color: hsl(120, 100%, 40%);">+       temp := (a - b)</span><br><span style="color: hsl(120, 100%, 40%);">+       if (temp < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+            temp := -temp;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (temp > tolerance) {</span><br><span>           return false;</span><br><span>        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>  return true;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/* Cross-compare two rtpem-statistics. The transmission statistics on the a side</span><br><span style="color: hsl(120, 100%, 40%);">+ * must match the reception statistics on the other side and vice versa. The</span><br><span style="color: hsl(120, 100%, 40%);">+ * user may also supply a tolerance value (number of packets) when deviations</span><br><span style="color: hsl(120, 100%, 40%);">+ * are acceptable */</span><br><span style="color: hsl(120, 100%, 40%);">+function f_rtpem_stats_compare(RtpemStats a, RtpemStats b, integer tolerance := 0) return boolean {</span><br><span style="color: hsl(120, 100%, 40%);">+       var integer plen;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   log("stats A: ", a);</span><br><span style="color: hsl(120, 100%, 40%);">+        log("stats B: ", b);</span><br><span style="color: hsl(120, 100%, 40%);">+        log("tolerance: ", tolerance, " packets");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (f_rtpem_stats_compare_value(a.num_pkts_tx, b.num_pkts_rx, tolerance) == false) {</span><br><span style="color: hsl(120, 100%, 40%);">+          return false;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (f_rtpem_stats_compare_value(a.num_pkts_rx, b.num_pkts_tx, tolerance) == false) {</span><br><span style="color: hsl(120, 100%, 40%);">+          return false;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if(a.num_pkts_tx > 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+            plen := a.bytes_payload_tx / a.num_pkts_tx;</span><br><span style="color: hsl(120, 100%, 40%);">+   } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              plen := 0;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (f_rtpem_stats_compare_value(a.bytes_payload_tx, b.bytes_payload_rx, tolerance * plen) == false) {</span><br><span style="color: hsl(120, 100%, 40%);">+         return false;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (f_rtpem_stats_compare_value(a.bytes_payload_rx, b.bytes_payload_tx, tolerance * plen) == false) {</span><br><span style="color: hsl(120, 100%, 40%);">+         return false;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return true;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span> </span><br><span> template PDU_RTP ts_RTP(BIT32_BO_LAST ssrc, INT7b pt, LIN2_BO_LAST seq, uint32_t ts,</span><br><span>                  octetstring payload, BIT1 marker := '0'B) := {</span><br><span>diff --git a/mgw/MGCP_Test.ttcn b/mgw/MGCP_Test.ttcn</span><br><span>index 6868405..8746c38 100644</span><br><span>--- a/mgw/MGCP_Test.ttcn</span><br><span>+++ b/mgw/MGCP_Test.ttcn</span><br><span>@@ -22,8 +22,8 @@</span><br><span>              var ConnectionId g_mgcp_conn_id := -1;</span><br><span>               var integer g_trans_id;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-             var RTP_Emulation_CT vc_RTPEM[2];</span><br><span style="color: hsl(0, 100%, 40%);">-               port RTPEM_CTRL_PT RTPEM[2];</span><br><span style="color: hsl(120, 100%, 40%);">+          var RTP_Emulation_CT vc_RTPEM[3];</span><br><span style="color: hsl(120, 100%, 40%);">+             port RTPEM_CTRL_PT RTPEM[3];</span><br><span>         };</span><br><span> </span><br><span>       function get_next_trans_id() runs on dummy_CT return MgcpTransId {</span><br><span>@@ -246,10 +246,10 @@</span><br><span>           MgcpConnectionId mgcp_conn_id optional</span><br><span>       }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   function f_flow_create(RTPEM_CTRL_PT pt, MgcpEndpoint ep, inout RtpFlowData flow,</span><br><span style="color: hsl(120, 100%, 40%);">+     /* Create an RTP flow (bidirectional, or receive-only) */</span><br><span style="color: hsl(120, 100%, 40%);">+     function f_flow_create(RTPEM_CTRL_PT pt, MgcpEndpoint ep, MgcpCallId call_id, charstring mode, inout RtpFlowData flow,</span><br><span>                               boolean one_phase := true)</span><br><span>   runs on dummy_CT {</span><br><span style="color: hsl(0, 100%, 40%);">-              var MgcpCallId call_id := '1226'H;</span><br><span>           var template MgcpCommand cmd;</span><br><span>                var MgcpResponse resp;</span><br><span> </span><br><span>@@ -257,8 +257,12 @@</span><br><span>            f_rtpem_bind(pt, flow.em.hostname, flow.em.portnr);</span><br><span> </span><br><span>              if (one_phase) {</span><br><span style="color: hsl(0, 100%, 40%);">-                        /* Connect flow to MGW */</span><br><span style="color: hsl(0, 100%, 40%);">-                       cmd := ts_CRCX(get_next_trans_id(), ep, "sendrecv", call_id);</span><br><span style="color: hsl(120, 100%, 40%);">+                       /* Connect flow to MGW using a CRCX that also contains an SDP</span><br><span style="color: hsl(120, 100%, 40%);">+                  * part that tells the MGW where we are listening for RTP streams</span><br><span style="color: hsl(120, 100%, 40%);">+                      * that come from the MGW. We get a fully working connection in</span><br><span style="color: hsl(120, 100%, 40%);">+                        * one go. */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                       cmd := ts_CRCX(get_next_trans_id(), ep, mode, call_id);</span><br><span>                      cmd.sdp := ts_SDP(flow.em.hostname, flow.em.hostname, "23", "42",</span><br><span>                                          flow.em.portnr, { int2str(flow.pt) },</span><br><span>                                        { valueof(ts_SDP_rtpmap(flow.pt, flow.codec)),</span><br><span>@@ -269,27 +273,65 @@</span><br><span>                     flow.mgw.portnr :=</span><br><span>                           resp.sdp.media_list[0].media_field.ports.port_number;</span><br><span>                } else {</span><br><span style="color: hsl(0, 100%, 40%);">-                        /* first create the MGW side RTP socket */</span><br><span style="color: hsl(0, 100%, 40%);">-                      cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);</span><br><span style="color: hsl(120, 100%, 40%);">+                       /* Create a half-open connection only. We do not tell the MGW</span><br><span style="color: hsl(120, 100%, 40%);">+                  * where it can send RTP streams to us. This means this</span><br><span style="color: hsl(120, 100%, 40%);">+                        * connection will only be able to receive but can not send</span><br><span style="color: hsl(120, 100%, 40%);">+                    * data back to us. In order to turn the connection in a fully</span><br><span style="color: hsl(120, 100%, 40%);">+                         * bi-directional one, a separate MDCX is needed. */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                        cmd := ts_CRCX(get_next_trans_id(), ep, mode, call_id);</span><br><span>                      resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);</span><br><span>                       flow.mgcp_conn_id := extract_conn_id(resp);</span><br><span>                  /* extract MGW-side port number from response */</span><br><span>                     flow.mgw.portnr :=</span><br><span>                           resp.sdp.media_list[0].media_field.ports.port_number;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                   /* then connect it to the emulation-side RTP socket using SDP */</span><br><span style="color: hsl(0, 100%, 40%);">-                        cmd := ts_MDCX(get_next_trans_id(), ep, "sendrecv", call_id, flow.mgcp_conn_id);</span><br><span style="color: hsl(0, 100%, 40%);">-                      cmd.sdp := ts_SDP(flow.em.hostname, flow.em.hostname, "23", "42",</span><br><span style="color: hsl(0, 100%, 40%);">-                                     flow.em.portnr, { int2str(flow.pt) },</span><br><span style="color: hsl(0, 100%, 40%);">-                                   { valueof(ts_SDP_rtpmap(flow.pt, flow.codec)),</span><br><span style="color: hsl(0, 100%, 40%);">-                                            valueof(ts_SDP_ptime(20)) });</span><br><span style="color: hsl(0, 100%, 40%);">-                       resp := mgcp_transceive_mgw(cmd, tr_MDCX_ACK);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>               }</span><br><span>            /* finally, connect the emulation-side RTP socket to the MGW */</span><br><span>              f_rtpem_connect(pt, flow.mgw.hostname, flow.mgw.portnr);</span><br><span>     }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ /* Modify an existing RTP flow */</span><br><span style="color: hsl(120, 100%, 40%);">+     function f_flow_modify(RTPEM_CTRL_PT pt, MgcpEndpoint ep, MgcpCallId call_id, charstring mode, inout RtpFlowData flow)</span><br><span style="color: hsl(120, 100%, 40%);">+        runs on dummy_CT {</span><br><span style="color: hsl(120, 100%, 40%);">+            var template MgcpCommand cmd;</span><br><span style="color: hsl(120, 100%, 40%);">+         var MgcpResponse resp;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+              /* rebind local RTP emulation socket to the new address */</span><br><span style="color: hsl(120, 100%, 40%);">+            f_rtpem_bind(pt, flow.em.hostname, flow.em.portnr);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+         /* connect MGW side RTP socket to the emulation-side RTP socket using SDP */</span><br><span style="color: hsl(120, 100%, 40%);">+          cmd := ts_MDCX(get_next_trans_id(), ep, mode, call_id, flow.mgcp_conn_id);</span><br><span style="color: hsl(120, 100%, 40%);">+            cmd.sdp := ts_SDP(flow.em.hostname, flow.em.hostname, "23", "42",</span><br><span style="color: hsl(120, 100%, 40%);">+                           flow.em.portnr, { int2str(flow.pt) },</span><br><span style="color: hsl(120, 100%, 40%);">+                                 { valueof(ts_SDP_rtpmap(flow.pt, flow.codec)),</span><br><span style="color: hsl(120, 100%, 40%);">+                                  valueof(ts_SDP_ptime(20)) });</span><br><span style="color: hsl(120, 100%, 40%);">+             resp := mgcp_transceive_mgw(cmd, tr_MDCX_ACK);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+              /* extract MGW-side port number from response. (usually this</span><br><span style="color: hsl(120, 100%, 40%);">+           * will not change, but thats is up to the MGW) */</span><br><span style="color: hsl(120, 100%, 40%);">+            flow.mgw.portnr :=</span><br><span style="color: hsl(120, 100%, 40%);">+                    resp.sdp.media_list[0].media_field.ports.port_number;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               /* reconnect the emulation-side RTP socket to the MGW */</span><br><span style="color: hsl(120, 100%, 40%);">+              f_rtpem_connect(pt, flow.mgw.hostname, flow.mgw.portnr);</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Delete an existing RTP flow */</span><br><span style="color: hsl(120, 100%, 40%);">+     function f_flow_delete(RTPEM_CTRL_PT pt, template MgcpEndpoint ep := omit, template MgcpCallId call_id := omit)</span><br><span style="color: hsl(120, 100%, 40%);">+       runs on dummy_CT {</span><br><span style="color: hsl(120, 100%, 40%);">+            var template MgcpCommand cmd;</span><br><span style="color: hsl(120, 100%, 40%);">+         var MgcpResponse resp;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+              /* Switch off RTP flow */</span><br><span style="color: hsl(120, 100%, 40%);">+             f_rtpem_mode(pt, RTPEM_MODE_NONE);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+          /* Delete connection on MGW (if needed) */</span><br><span style="color: hsl(120, 100%, 40%);">+            if (isvalue(call_id) and isvalue(ep)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       f_sleep(0.1);</span><br><span style="color: hsl(120, 100%, 40%);">+                 f_dlcx_ok(valueof(ep), call_id);</span><br><span style="color: hsl(120, 100%, 40%);">+              }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>  function f_crcx(charstring ep_prefix) runs on dummy_CT {</span><br><span>             var MgcpEndpoint ep := ep_prefix & "2@" & c_mgw_domain;</span><br><span>            var template MgcpCommand cmd;</span><br><span>@@ -862,14 +904,92 @@</span><br><span>                setverdict(pass);</span><br><span>    }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   /* create two local RTP emulations; create two connections on MGW EP, exchange some data */</span><br><span style="color: hsl(0, 100%, 40%);">-     testcase TC_two_crcx_and_rtp() runs on dummy_CT {</span><br><span style="color: hsl(120, 100%, 40%);">+     /* Create one half open connection in receive-only mode. The MGW must accept</span><br><span style="color: hsl(120, 100%, 40%);">+   * the packets but must not send any. */</span><br><span style="color: hsl(120, 100%, 40%);">+      testcase TC_one_crcx_receive_only_rtp() runs on dummy_CT {</span><br><span style="color: hsl(120, 100%, 40%);">+            var RtpFlowData flow;</span><br><span style="color: hsl(120, 100%, 40%);">+         var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "1@" & c_mgw_domain;</span><br><span style="color: hsl(120, 100%, 40%);">+            var MgcpCallId call_id := '1225'H;</span><br><span style="color: hsl(120, 100%, 40%);">+            var RtpemStats stats;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               f_init(ep);</span><br><span style="color: hsl(120, 100%, 40%);">+           flow := valueof(t_RtpFlow(mp_local_ip, mp_remote_ip, 112, "AMR/8000/1"));</span><br><span style="color: hsl(120, 100%, 40%);">+           flow.em.portnr := 10000;</span><br><span style="color: hsl(120, 100%, 40%);">+              f_flow_create(RTPEM[0], ep, call_id, "recvonly", flow, false);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            f_rtpem_mode(RTPEM[0], RTPEM_MODE_TXONLY);</span><br><span style="color: hsl(120, 100%, 40%);">+            f_sleep(1.0);</span><br><span style="color: hsl(120, 100%, 40%);">+         f_flow_delete(RTPEM[0], ep, call_id);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               stats := f_rtpem_stats_get(RTPEM[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               if (stats.num_pkts_tx < 40) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      setverdict(fail);</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+             if (stats.bytes_payload_tx < 190) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        setverdict(fail);</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+             if (stats.num_pkts_rx != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 setverdict(fail);</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+             if (stats.num_pkts_rx_err_seq != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 setverdict(fail);</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+             if (stats.num_pkts_rx_err_ts != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  setverdict(fail);</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+             if (stats.num_pkts_rx_err_disabled != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    setverdict(fail);</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           setverdict(pass);</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Create one connection in loopback mode, test if the RTP packets are</span><br><span style="color: hsl(120, 100%, 40%);">+         * actually reflected */</span><br><span style="color: hsl(120, 100%, 40%);">+      testcase TC_one_crcx_loopback_rtp() runs on dummy_CT {</span><br><span style="color: hsl(120, 100%, 40%);">+                var RtpFlowData flow;</span><br><span style="color: hsl(120, 100%, 40%);">+         var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "1@" & c_mgw_domain;</span><br><span style="color: hsl(120, 100%, 40%);">+            var MgcpCallId call_id := '1225'H;</span><br><span style="color: hsl(120, 100%, 40%);">+            var RtpemStats stats;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               f_init(ep);</span><br><span style="color: hsl(120, 100%, 40%);">+           flow := valueof(t_RtpFlow(mp_local_ip, mp_remote_ip, 111, "GSM-HR-08/8000/1"));</span><br><span style="color: hsl(120, 100%, 40%);">+             flow.em.portnr := 10000;</span><br><span style="color: hsl(120, 100%, 40%);">+              f_flow_create(RTPEM[0], ep, call_id, "loopback", flow);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           f_rtpem_mode(RTPEM[0], RTPEM_MODE_BIDIR);</span><br><span style="color: hsl(120, 100%, 40%);">+             f_sleep(1.0);</span><br><span style="color: hsl(120, 100%, 40%);">+         f_flow_delete(RTPEM[0], ep, call_id);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               stats := f_rtpem_stats_get(RTPEM[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               if (stats.num_pkts_tx != stats.num_pkts_rx) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 setverdict(fail);</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+             if (stats.bytes_payload_tx != stats.bytes_payload_rx) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       setverdict(fail);</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+             if (stats.num_pkts_rx_err_seq != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 setverdict(fail);</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+             if (stats.num_pkts_rx_err_ts != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  setverdict(fail);</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+             if (stats.num_pkts_rx_err_disabled != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    setverdict(fail);</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           setverdict(pass);</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   function f_TC_two_crcx_and_rtp(boolean bidir) runs on dummy_CT {</span><br><span>             var RtpFlowData flow[2];</span><br><span>             var RtpemStats stats[2];</span><br><span style="color: hsl(0, 100%, 40%);">-                var template MgcpCommand cmd;</span><br><span>                var MgcpResponse resp;</span><br><span>               var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "2@" & c_mgw_domain;</span><br><span>           var MgcpCallId call_id := '1226'H;</span><br><span style="color: hsl(120, 100%, 40%);">+            var integer tolerance := 0;</span><br><span> </span><br><span>              f_init(ep);</span><br><span> </span><br><span>@@ -877,20 +997,181 @@</span><br><span>             flow[0] := valueof(t_RtpFlow(mp_local_ip, mp_remote_ip, 98, "AMR/8000"));</span><br><span>          /* bind local RTP emulation sockets */</span><br><span>               flow[0].em.portnr := 10000;</span><br><span style="color: hsl(0, 100%, 40%);">-             f_flow_create(RTPEM[0], ep, flow[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+         f_flow_create(RTPEM[0], ep, call_id, "sendrecv", flow[0]);</span><br><span> </span><br><span>             /* from MGW back to us */</span><br><span>            flow[1] := valueof(t_RtpFlow(mp_local_ip, mp_remote_ip, 98, "AMR/8000"));</span><br><span>          flow[1].em.portnr := 20000;</span><br><span style="color: hsl(0, 100%, 40%);">-             f_flow_create(RTPEM[1], ep, flow[1]);</span><br><span style="color: hsl(120, 100%, 40%);">+         f_flow_create(RTPEM[1], ep, call_id, "sendrecv", flow[1]);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                if (bidir) {</span><br><span style="color: hsl(120, 100%, 40%);">+                          f_rtpem_mode(RTPEM[0], RTPEM_MODE_BIDIR);</span><br><span style="color: hsl(120, 100%, 40%);">+                             f_rtpem_mode(RTPEM[1], RTPEM_MODE_BIDIR);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                           /* Note: When we test bidirectional we may</span><br><span style="color: hsl(120, 100%, 40%);">+                             * loose packets during switch off because</span><br><span style="color: hsl(120, 100%, 40%);">+                             * both ends are transmitting and we only</span><br><span style="color: hsl(120, 100%, 40%);">+                              * can switch them off one by one. */</span><br><span style="color: hsl(120, 100%, 40%);">+                         tolerance := 3;</span><br><span style="color: hsl(120, 100%, 40%);">+               } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                              f_rtpem_mode(RTPEM[0], RTPEM_MODE_RXONLY);</span><br><span style="color: hsl(120, 100%, 40%);">+                            f_rtpem_mode(RTPEM[1], RTPEM_MODE_TXONLY);</span><br><span style="color: hsl(120, 100%, 40%);">+            }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           f_sleep(1.0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               f_flow_delete(RTPEM[1]);</span><br><span style="color: hsl(120, 100%, 40%);">+              f_flow_delete(RTPEM[0], ep, call_id);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               stats[0] := f_rtpem_stats_get(RTPEM[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+              stats[1] := f_rtpem_stats_get(RTPEM[1]);</span><br><span style="color: hsl(120, 100%, 40%);">+              if (not f_rtpem_stats_compare(stats[0], stats[1], tolerance)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       setverdict(fail, "RTP endpoint statistics don't match");</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           setverdict(pass);</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* create two local RTP emulations; create two connections on MGW EP, exchange some data */</span><br><span style="color: hsl(120, 100%, 40%);">+   testcase TC_two_crcx_and_rtp() runs on dummy_CT {</span><br><span style="color: hsl(120, 100%, 40%);">+              f_TC_two_crcx_and_rtp(false);</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* create two local RTP emulations; create two connections on MGW EP,</span><br><span style="color: hsl(120, 100%, 40%);">+  * exchange some data in both directions */</span><br><span style="color: hsl(120, 100%, 40%);">+   testcase TC_two_crcx_and_rtp_bidir() runs on dummy_CT {</span><br><span style="color: hsl(120, 100%, 40%);">+                f_TC_two_crcx_and_rtp(true);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* create two local RTP emulations and pass data in both directions */</span><br><span style="color: hsl(120, 100%, 40%);">+        testcase TC_two_crcx_mdcx_and_rtp() runs on dummy_CT {</span><br><span style="color: hsl(120, 100%, 40%);">+                var RtpFlowData flow[2];</span><br><span style="color: hsl(120, 100%, 40%);">+              var RtpemStats stats[2];</span><br><span style="color: hsl(120, 100%, 40%);">+              var MgcpResponse resp;</span><br><span style="color: hsl(120, 100%, 40%);">+                var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "2@" & c_mgw_domain;</span><br><span style="color: hsl(120, 100%, 40%);">+            var MgcpCallId call_id := '1227'H;</span><br><span style="color: hsl(120, 100%, 40%);">+            var integer num_pkts_tx[2];</span><br><span style="color: hsl(120, 100%, 40%);">+           var integer temp;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           f_init(ep);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+         /* Create the first connection in receive only mode */</span><br><span style="color: hsl(120, 100%, 40%);">+                flow[0] := valueof(t_RtpFlow(mp_local_ip, mp_remote_ip, 3, "GSM/8000/1"));</span><br><span style="color: hsl(120, 100%, 40%);">+          flow[0].em.portnr := 10000;</span><br><span style="color: hsl(120, 100%, 40%);">+           f_flow_create(RTPEM[0], ep, call_id, "recvonly", flow[0], false);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+         /* Create the second connection. This connection will be also</span><br><span style="color: hsl(120, 100%, 40%);">+          * in receive only mode */</span><br><span style="color: hsl(120, 100%, 40%);">+            flow[1] := valueof(t_RtpFlow(mp_local_ip, mp_remote_ip, 3, "GSM/8000/1"));</span><br><span style="color: hsl(120, 100%, 40%);">+          flow[1].em.portnr := 20000;</span><br><span style="color: hsl(120, 100%, 40%);">+           f_flow_create(RTPEM[1], ep, call_id, "recvonly", flow[1], false);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+         /* The first leg starts transmitting */</span><br><span style="color: hsl(120, 100%, 40%);">+               f_rtpem_mode(RTPEM[0], RTPEM_MODE_TXONLY);</span><br><span style="color: hsl(120, 100%, 40%);">+            f_sleep(0.5);</span><br><span style="color: hsl(120, 100%, 40%);">+         stats[0] := f_rtpem_stats_get(RTPEM[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+              if (stats[0].num_pkts_rx_err_disabled != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 setverdict(fail, "received packets from MGW on recvonly connection");</span><br><span style="color: hsl(120, 100%, 40%);">+               }</span><br><span style="color: hsl(120, 100%, 40%);">+             stats[1] := f_rtpem_stats_get(RTPEM[1]);</span><br><span style="color: hsl(120, 100%, 40%);">+              if (stats[1].num_pkts_rx_err_disabled != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 setverdict(fail, "received packets from MGW on recvonly connection");</span><br><span style="color: hsl(120, 100%, 40%);">+               }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           /* The second leg starts transmitting a little later */</span><br><span style="color: hsl(120, 100%, 40%);">+               f_rtpem_mode(RTPEM[1], RTPEM_MODE_TXONLY);</span><br><span style="color: hsl(120, 100%, 40%);">+            f_sleep(1.0);</span><br><span style="color: hsl(120, 100%, 40%);">+         stats[0] := f_rtpem_stats_get(RTPEM[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+              if (stats[0].num_pkts_rx_err_disabled != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 setverdict(fail, "received packets from MGW on recvonly connection");</span><br><span style="color: hsl(120, 100%, 40%);">+               }</span><br><span style="color: hsl(120, 100%, 40%);">+             stats[1] := f_rtpem_stats_get(RTPEM[1]);</span><br><span style="color: hsl(120, 100%, 40%);">+              if (stats[1].num_pkts_rx_err_disabled != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 setverdict(fail, "received packets from MGW on recvonly connection");</span><br><span style="color: hsl(120, 100%, 40%);">+               }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           /* The first leg will now be switched into bidirectional</span><br><span style="color: hsl(120, 100%, 40%);">+               * mode, but we do not expect any data comming back yet. */</span><br><span style="color: hsl(120, 100%, 40%);">+           f_flow_modify(RTPEM[0], ep, call_id, "sendrecv", flow[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+          f_sleep(0.5);</span><br><span style="color: hsl(120, 100%, 40%);">+         stats[0] := f_rtpem_stats_get(RTPEM[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+              if (stats[1].num_pkts_rx_err_disabled != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 setverdict(fail, "received packets from MGW on recvonly connection");</span><br><span style="color: hsl(120, 100%, 40%);">+               }</span><br><span style="color: hsl(120, 100%, 40%);">+             stats[1] := f_rtpem_stats_get(RTPEM[1]);</span><br><span style="color: hsl(120, 100%, 40%);">+              if (stats[1].num_pkts_rx_err_disabled != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 setverdict(fail, "received packets from MGW on recvonly connection");</span><br><span style="color: hsl(120, 100%, 40%);">+               }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           /* When the second leg is switched into bidirectional mode</span><br><span style="color: hsl(120, 100%, 40%);">+             * as well, then the MGW will connect the two together and</span><br><span style="color: hsl(120, 100%, 40%);">+             * we should see RTP streams passing through from both ends. */</span><br><span style="color: hsl(120, 100%, 40%);">+               f_rtpem_mode(RTPEM[0], RTPEM_MODE_BIDIR);</span><br><span style="color: hsl(120, 100%, 40%);">+             f_rtpem_mode(RTPEM[1], RTPEM_MODE_BIDIR);</span><br><span style="color: hsl(120, 100%, 40%);">+             stats[0] := f_rtpem_stats_get(RTPEM[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+              num_pkts_tx[0] := stats[0].num_pkts_tx</span><br><span style="color: hsl(120, 100%, 40%);">+                stats[1] := f_rtpem_stats_get(RTPEM[1]);</span><br><span style="color: hsl(120, 100%, 40%);">+              num_pkts_tx[1] := stats[1].num_pkts_tx</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+              f_flow_modify(RTPEM[1], ep, call_id, "sendrecv", flow[1]);</span><br><span style="color: hsl(120, 100%, 40%);">+          f_sleep(2.0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               stats[0] := f_rtpem_stats_get(RTPEM[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+              stats[1] := f_rtpem_stats_get(RTPEM[1]);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            temp := stats[0].num_pkts_tx - num_pkts_tx[0] - stats[1].num_pkts_rx;</span><br><span style="color: hsl(120, 100%, 40%);">+         if (temp > 3 or temp < -3) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    setverdict(fail, "number of packets not within normal parameters");</span><br><span style="color: hsl(120, 100%, 40%);">+         }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           temp := stats[1].num_pkts_tx - num_pkts_tx[1] - stats[0].num_pkts_rx;</span><br><span style="color: hsl(120, 100%, 40%);">+         if (temp > 3 or temp < -3) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    setverdict(fail, "number of packets not within normal parameters");</span><br><span style="color: hsl(120, 100%, 40%);">+         }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           /* Tear down */</span><br><span style="color: hsl(120, 100%, 40%);">+               f_flow_delete(RTPEM[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+              f_flow_delete(RTPEM[1], ep, call_id);</span><br><span style="color: hsl(120, 100%, 40%);">+         setverdict(pass);</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Test what happens when two RTP streams from different sources target</span><br><span style="color: hsl(120, 100%, 40%);">+        * a single connection. Is the unsolicited stream properly ignored? */</span><br><span style="color: hsl(120, 100%, 40%);">+        testcase TC_two_crcx_and_unsolicited_rtp() runs on dummy_CT {</span><br><span style="color: hsl(120, 100%, 40%);">+         var RtpFlowData flow[2];</span><br><span style="color: hsl(120, 100%, 40%);">+              var RtpemStats stats[2];</span><br><span style="color: hsl(120, 100%, 40%);">+              var MgcpResponse resp;</span><br><span style="color: hsl(120, 100%, 40%);">+                var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "2@" & c_mgw_domain;</span><br><span style="color: hsl(120, 100%, 40%);">+            var MgcpCallId call_id := '1234321326'H;</span><br><span style="color: hsl(120, 100%, 40%);">+              var integer unsolicited_port := 10002;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+              f_init(ep);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+         /* from us to MGW */</span><br><span style="color: hsl(120, 100%, 40%);">+          flow[0] := valueof(t_RtpFlow(mp_local_ip, mp_remote_ip, 98, "AMR/8000"));</span><br><span style="color: hsl(120, 100%, 40%);">+           /* bind local RTP emulation sockets */</span><br><span style="color: hsl(120, 100%, 40%);">+                flow[0].em.portnr := 10000;</span><br><span style="color: hsl(120, 100%, 40%);">+           f_flow_create(RTPEM[0], ep, call_id, "sendrecv", flow[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                /* from MGW back to us */</span><br><span style="color: hsl(120, 100%, 40%);">+             flow[1] := valueof(t_RtpFlow(mp_local_ip, mp_remote_ip, 98, "AMR/8000"));</span><br><span style="color: hsl(120, 100%, 40%);">+           flow[1].em.portnr := 20000;</span><br><span style="color: hsl(120, 100%, 40%);">+           f_flow_create(RTPEM[1], ep, call_id, "sendrecv", flow[1]);</span><br><span> </span><br><span>             f_rtpem_mode(RTPEM[1], RTPEM_MODE_RXONLY);</span><br><span>           f_rtpem_mode(RTPEM[0], RTPEM_MODE_TXONLY);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-          f_sleep(1.0);</span><br><span style="color: hsl(120, 100%, 40%);">+         f_sleep(0.5);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-               f_rtpem_mode(RTPEM[0], RTPEM_MODE_NONE);</span><br><span style="color: hsl(0, 100%, 40%);">-                f_sleep(0.1);</span><br><span style="color: hsl(120, 100%, 40%);">+         /* Start inserting unsolicited RTP packets */</span><br><span style="color: hsl(120, 100%, 40%);">+         f_rtpem_bind(RTPEM[2], "127.0.0.1", unsolicited_port);</span><br><span style="color: hsl(120, 100%, 40%);">+              f_rtpem_connect(RTPEM[2], "127.0.0.1", flow[0].mgw.portnr);</span><br><span style="color: hsl(120, 100%, 40%);">+         f_rtpem_mode(RTPEM[2], RTPEM_MODE_TXONLY);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+          f_sleep(0.5);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               f_flow_delete(RTPEM[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+              f_flow_delete(RTPEM[1], ep, call_id);</span><br><span> </span><br><span>            stats[0] := f_rtpem_stats_get(RTPEM[0]);</span><br><span>             stats[1] := f_rtpem_stats_get(RTPEM[1]);</span><br><span>@@ -898,9 +1179,68 @@</span><br><span>                     setverdict(fail, "RTP endpoint statistics don't match");</span><br><span>               }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-           f_dlcx_ok(ep, call_id);</span><br><span>              setverdict(pass);</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ /* Test a handover situation. We first create two connections transmit</span><br><span style="color: hsl(120, 100%, 40%);">+         * some data bidirectionally. Then we will simulate a handover situation. */</span><br><span style="color: hsl(120, 100%, 40%);">+  testcase TC_two_crcx_and_one_mdcx_rtp_ho() runs on dummy_CT {</span><br><span style="color: hsl(120, 100%, 40%);">+         var RtpFlowData flow[2];</span><br><span style="color: hsl(120, 100%, 40%);">+              var RtpemStats stats[3];</span><br><span style="color: hsl(120, 100%, 40%);">+              var MgcpResponse resp;</span><br><span style="color: hsl(120, 100%, 40%);">+                var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "4@" & c_mgw_domain;</span><br><span style="color: hsl(120, 100%, 40%);">+            var MgcpCallId call_id := '76338'H;</span><br><span style="color: hsl(120, 100%, 40%);">+           var integer port_old;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               f_init(ep);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+         /* First connection (BTS) */</span><br><span style="color: hsl(120, 100%, 40%);">+          flow[0] := valueof(t_RtpFlow(mp_local_ip, mp_remote_ip, 110, "GSM-EFR/8000"));</span><br><span style="color: hsl(120, 100%, 40%);">+              /* bind local RTP emulation sockets */</span><br><span style="color: hsl(120, 100%, 40%);">+                flow[0].em.portnr := 10000;</span><br><span style="color: hsl(120, 100%, 40%);">+           f_flow_create(RTPEM[0], ep, call_id, "sendrecv", flow[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                /* Second connection (PBX) */</span><br><span style="color: hsl(120, 100%, 40%);">+         flow[1] := valueof(t_RtpFlow(mp_local_ip, mp_remote_ip, 110, "GSM-EFR/8000"));</span><br><span style="color: hsl(120, 100%, 40%);">+              flow[1].em.portnr := 20000;</span><br><span style="color: hsl(120, 100%, 40%);">+           f_flow_create(RTPEM[1], ep, call_id, "sendrecv", flow[1]);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                /* Normal rtp flow for one second */</span><br><span style="color: hsl(120, 100%, 40%);">+          f_rtpem_mode(RTPEM[0], RTPEM_MODE_BIDIR);</span><br><span style="color: hsl(120, 100%, 40%);">+             f_rtpem_mode(RTPEM[1], RTPEM_MODE_BIDIR);</span><br><span style="color: hsl(120, 100%, 40%);">+             f_sleep(1.0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               /* Now switch the flow over to a new port (BTS) */</span><br><span style="color: hsl(120, 100%, 40%);">+            port_old := flow[0].em.portnr;</span><br><span style="color: hsl(120, 100%, 40%);">+                flow[0].em.portnr := 10002;</span><br><span style="color: hsl(120, 100%, 40%);">+           f_flow_modify(RTPEM[0], ep, call_id, "sendrecv", flow[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                /* When handing over a call, the old source may still keep</span><br><span style="color: hsl(120, 100%, 40%);">+             * transmitting for a while. We simulate this by injecting</span><br><span style="color: hsl(120, 100%, 40%);">+             * some unsolicited packets on the behalf of the old source,</span><br><span style="color: hsl(120, 100%, 40%);">+           * (old remote port) */</span><br><span style="color: hsl(120, 100%, 40%);">+               f_rtpem_bind(RTPEM[2], "127.0.0.1", port_old);</span><br><span style="color: hsl(120, 100%, 40%);">+              f_rtpem_connect(RTPEM[2], "127.0.0.1", flow[0].mgw.portnr);</span><br><span style="color: hsl(120, 100%, 40%);">+         f_rtpem_mode(RTPEM[2], RTPEM_MODE_TXONLY);</span><br><span style="color: hsl(120, 100%, 40%);">+            f_sleep(1.0);</span><br><span style="color: hsl(120, 100%, 40%);">+         f_rtpem_mode(RTPEM[2], RTPEM_MODE_NONE);</span><br><span style="color: hsl(120, 100%, 40%);">+              f_sleep(1.0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               /* Terminate call */</span><br><span style="color: hsl(120, 100%, 40%);">+          f_flow_delete(RTPEM[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+              f_flow_delete(RTPEM[1], ep, call_id);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               stats[0] := f_rtpem_stats_get(RTPEM[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+              stats[1] := f_rtpem_stats_get(RTPEM[1]);</span><br><span style="color: hsl(120, 100%, 40%);">+              if (not f_rtpem_stats_compare(stats[0], stats[1], 5)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       setverdict(fail, "RTP endpoint statistics don't match");</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+             stats[2] := f_rtpem_stats_get(RTPEM[2]);</span><br><span style="color: hsl(120, 100%, 40%);">+              if (stats[2].num_pkts_rx_err_disabled != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 setverdict(fail, "received packets on old leg after handover");</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           setverdict(pass);</span><br><span>    }</span><br><span> </span><br><span>        /* TODO: Double-DLCX (no retransmission) */</span><br><span>@@ -943,6 +1283,13 @@</span><br><span>          execute(TC_crcx_dlcx_30ep());</span><br><span> </span><br><span>            execute(TC_rtpem_selftest());</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               execute(TC_one_crcx_receive_only_rtp());</span><br><span style="color: hsl(120, 100%, 40%);">+              execute(TC_one_crcx_loopback_rtp());</span><br><span>                 execute(TC_two_crcx_and_rtp());</span><br><span style="color: hsl(120, 100%, 40%);">+               execute(TC_two_crcx_and_rtp_bidir());</span><br><span style="color: hsl(120, 100%, 40%);">+         execute(TC_two_crcx_mdcx_and_rtp());</span><br><span style="color: hsl(120, 100%, 40%);">+          execute(TC_two_crcx_and_unsolicited_rtp());</span><br><span style="color: hsl(120, 100%, 40%);">+           execute(TC_two_crcx_and_one_mdcx_rtp_ho());</span><br><span>  }</span><br><span> }</span><br><span>diff --git a/mgw/expected-results.xml b/mgw/expected-results.xml</span><br><span>index 03c8fd2..f201099 100644</span><br><span>--- a/mgw/expected-results.xml</span><br><span>+++ b/mgw/expected-results.xml</span><br><span>@@ -31,4 +31,10 @@</span><br><span>   <testcase classname='MGCP_Test' name='TC_crcx_dlcx_30ep' time='MASKED'/></span><br><span>   <testcase classname='MGCP_Test' name='TC_rtpem_selftest' time='MASKED'/></span><br><span>   <testcase classname='MGCP_Test' name='TC_two_crcx_and_rtp' time='MASKED'/></span><br><span style="color: hsl(120, 100%, 40%);">+  <testcase classname='MGCP_Test' name='TC_one_crcx_receive_only_rtp' time='MASKED'/></span><br><span style="color: hsl(120, 100%, 40%);">+  <testcase classname='MGCP_Test' name='TC_one_crcx_loopback_rtp' time='MASKED'/></span><br><span style="color: hsl(120, 100%, 40%);">+  <testcase classname='MGCP_Test' name='TC_two_crcx_and_rtp_bidir' time='MASKED'/></span><br><span style="color: hsl(120, 100%, 40%);">+  <testcase classname='MGCP_Test' name='TC_two_crcx_mdcx_and_rtp' time='MASKED'/></span><br><span style="color: hsl(120, 100%, 40%);">+  <testcase classname='MGCP_Test' name='TC_two_crcx_and_unsolicited_rtp' time='MASKED'/></span><br><span style="color: hsl(120, 100%, 40%);">+  <testcase classname='MGCP_Test' name='TC_two_crcx_and_one_mdcx_rtp_ho' time='MASKED'/></span><br><span> </testsuite></span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/9768">change 9768</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/9768"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: osmo-ttcn3-hacks </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-MessageType: merged </div>
<div style="display:none"> Gerrit-Change-Id: I556a6efff0e74aab897bd8165200eec36e46629f </div>
<div style="display:none"> Gerrit-Change-Number: 9768 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: dexter <pmaier@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: Harald Welte <laforge@gnumonks.org> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins Builder </div>