<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>