pespin submitted this change.
asterisk: Introduce test TC_ims_call_mo_holdresume_mo
Related: SYS#7002
Change-Id: Ifffa1c4021f324871f11a60264c17b640569e18b
---
M asterisk/Asterisk_Tests.ttcn
M asterisk/IMS_ConnectionHandler.ttcn
M asterisk/SIP_ConnectionHandler.ttcn
M asterisk/expected-results.xml
M library/SDP_Templates.ttcn
5 files changed, 187 insertions(+), 24 deletions(-)
diff --git a/asterisk/Asterisk_Tests.ttcn b/asterisk/Asterisk_Tests.ttcn
index ec55254..0796d99 100644
--- a/asterisk/Asterisk_Tests.ttcn
+++ b/asterisk/Asterisk_Tests.ttcn
@@ -226,6 +226,16 @@
f_TC_internal_hangup_call_mo_unregister();
setverdict(pass);
}
+private function f_TC_internal_call_mo_with_holdresume(charstring id) runs on SIPConnHdlr {
+ f_TC_internal_register_establish_call_mo();
+ f_sleep(1.0);
+ f_SIP_do_call_hold();
+ f_sleep(1.0);
+ f_SIP_do_call_resume();
+ f_TC_internal_hangup_call_mo_unregister();
+ setverdict(pass);
+}
+
private function f_TC_internal_call_mt(charstring id) runs on SIPConnHdlr {
f_create_sip_expect(valueof(ts_SipUrl_from_Addr_Union(g_pars.cp.called.addr)));
@@ -756,6 +766,14 @@
f_TC_ims_call_mo_IMS_ConnHdlr_hangup_call_unregister();
}
+private function f_TC_ims_call_mo_IMS_ConnHdlr_with_holdresume(charstring id) runs on IMS_ConnHdlr {
+ f_TC_ims_call_mo_IMS_ConnHdlr_register_establish_call();
+ as_IMS_exp_call_hold();
+ f_sleep(1.0);
+ as_IMS_exp_call_resume();
+ f_TC_ims_call_mo_IMS_ConnHdlr_hangup_call_unregister();
+}
+
private function f_TC_ims_call_mo(boolean use_precondition_ext := true, boolean use_session_timer := false,
void_fn sip_fn := refers(f_TC_internal_call_mo),
ims_void_fn ims_fn := refers(f_TC_ims_call_mo_IMS_ConnHdlr)) runs on test_CT {
@@ -825,6 +843,10 @@
testcase TC_ims_call_mo_noprecondition() runs on test_CT {
f_TC_ims_call_mo(use_precondition_ext := false);
}
+testcase TC_ims_call_mo_holdresume_mo() runs on test_CT {
+ f_TC_ims_call_mo(sip_fn := refers(f_TC_internal_call_mo_with_holdresume),
+ ims_fn := refers(f_TC_ims_call_mo_IMS_ConnHdlr_with_holdresume));
+}
/* Test SIP registration of local clients */
private function f_TC_ims_call_mt_IMS_ConnHdlr(charstring id) runs on IMS_ConnHdlr {
@@ -942,6 +964,7 @@
execute( TC_ims_call_mo() );
execute( TC_ims_call_mo_session_timer() );
execute( TC_ims_call_mo_noprecondition() );
+ execute( TC_ims_call_mo_holdresume_mo() );
execute( TC_ims_call_mt() );
execute( TC_ims_call_mt_noprecondition() );
}
diff --git a/asterisk/IMS_ConnectionHandler.ttcn b/asterisk/IMS_ConnectionHandler.ttcn
index dd187ad..14e6cd4 100644
--- a/asterisk/IMS_ConnectionHandler.ttcn
+++ b/asterisk/IMS_ConnectionHandler.ttcn
@@ -650,7 +650,7 @@
IMS_GEN_SDP_MT_UPDATE_200OK
}
-private function f_gen_sdp(IMS_gen_sdp_state st := IMS_GEN_SDP_None) runs on IMS_ConnHdlr return charstring {
+private function f_gen_sdp(IMS_gen_sdp_state st := IMS_GEN_SDP_None, charstring dir := "sendrecv") runs on IMS_ConnHdlr return charstring {
var charstring sdp :=
"v=0\r\n" &
"o=0502 2390 1824 IN IP4 " & g_pars.subscr.cp.local_rtp_addr & "\r\n" &
@@ -659,15 +659,8 @@
"t=0 0\r\n" &
"a=rtcp-xr:rcvr-rtt=all:10000 stat-summary=loss,dup,jitt,TTL voip-metrics\r\n" &
"a=record:off\r\n" &
- "m=audio " & int2str(g_pars.subscr.cp.local_rtp_port) & " RTP/AVP 8 96 97 98 0 18 99 100 101\r\n" &
+ "m=audio " & int2str(g_pars.subscr.cp.local_rtp_port) & " RTP/AVP 8 99 100 101\r\n" &
"a=rtpmap:8 PCMA/8000\r\n" &
- "a=rtpmap:96 opus/48000/2\r\n" &
- "a=fmtp:96 useinbandfec=1\r\n" &
- "a=rtpmap:97 speex/16000\r\n" &
- "a=fmtp:97 vbr=on\r\n" &
- "a=rtpmap:98 speex/8000\r\n" &
- "a=fmtp:98 vbr=on\r\n" &
- "a=fmtp:18 annexb=yes\r\n" &
"a=rtpmap:99 telephone-event/48000\r\n" &
"a=rtpmap:100 telephone-event/16000\r\n" &
"a=rtpmap:101 telephone-event/8000\r\n" &
@@ -707,6 +700,8 @@
"a=des:qos mandatory remote sendrecv\r\n";
}
}
+
+ sdp := sdp & "a=" & dir & "\r\n";
return sdp;
}
@@ -1708,10 +1703,10 @@
tx_resp := ts_SIP_Response(g_pars.subscr.cp.sip_call_id,
g_pars.subscr.cp.from_addr,
g_pars.subscr.cp.to_addr,
- g_rx_sip_req.msgHeader.cSeq.method, 200,
- g_rx_sip_req.msgHeader.cSeq.seqNumber,
+ req.msgHeader.cSeq.method, 200,
+ req.msgHeader.cSeq.seqNumber,
"OK",
- g_rx_sip_req.msgHeader.via,
+ req.msgHeader.via,
session_expires := ts_Session_expires(int2str(g_pars.subscr.cp.mo.support_timer_session_expires),
{ts_Param("refresher", "uac")}),
supported := ts_Supported({"timer"}),
@@ -1750,4 +1745,66 @@
g_pars.subscr.cp.sip_seq_nr := g_rx_sip_req.msgHeader.cSeq.seqNumber;
}
}
+
+private altstep as_IMS_exp_call_holdresume(template (present) SDP_attribute exp_dir := tr_SDP_sendonly,
+ charstring tx_dir := "recvonly") runs on IMS_ConnHdlr
+{
+ /* RFC4028 section 7.4. It can be either INVITE or UPDATE: */
+ var template (present) PDU_SIP_Request exp_req_invite :=
+ tr_SIP_INVITE(f_tr_SipUrl_opt_defport(ts_SipUrl_from_Addr_Union(g_pars.subscr.cp.called.addr)),
+ ?,
+ tr_From(tr_Addr_Union_from_val(g_pars.subscr.cp.calling.addr), *),
+ tr_To(tr_Addr_Union_from_val(g_pars.subscr.cp.called.addr), *),
+ tr_Via_from(f_tr_HostPort(g_pars.subscr.remote_sip_host, g_pars.subscr.ipsec_remote_port_s)),
+ ?,
+ body := ?);
+
+ [] SIP.receive(exp_req_invite) -> value g_rx_sip_req {
+ var template (present) PDU_SIP_Request exp_req;
+ var template (value) PDU_SIP_Response tx_resp;
+ var charstring tx_sdp;
+
+ f_SDP_decodeMessage(g_rx_sip_req.messageBody, g_pars.subscr.cp.peer_sdp);
+ g_pars.subscr.cp.sip_seq_nr := g_rx_sip_req.msgHeader.cSeq.seqNumber;
+
+ /* Check a=$exp_dir in SDP */
+ if (not ispresent(g_pars.subscr.cp.peer_sdp.media_list[0].attributes) or
+ not match (g_pars.subscr.cp.peer_sdp.media_list[0].attributes, superset(exp_dir))) {
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
+ log2str(g_name & ": Expected re-INVITE SDP attribute a=", exp_dir, " in: ",
+ g_pars.subscr.cp.peer_sdp.media_list[0].attributes));
+ }
+
+ tx_sdp := f_gen_sdp(dir := tx_dir);
+ /* Tx 200 OK response*/
+ tx_resp := ts_SIP_Response(g_pars.subscr.cp.sip_call_id,
+ g_pars.subscr.cp.from_addr,
+ g_pars.subscr.cp.to_addr,
+ g_rx_sip_req.msgHeader.cSeq.method, 200,
+ g_rx_sip_req.msgHeader.cSeq.seqNumber,
+ "OK",
+ g_rx_sip_req.msgHeader.via,
+ body := tx_sdp);
+ SIP.send(tx_resp);
+
+ /* Wait for ACK */
+ exp_req := tr_SIP_ACK(f_tr_SipUrl_opt_defport(ts_SipUrl_from_Addr_Union(g_pars.subscr.cp.called.addr)),
+ g_pars.subscr.cp.sip_call_id,
+ g_pars.subscr.cp.from_addr,
+ g_pars.subscr.cp.to_addr,
+ f_tr_Via_response(g_rx_sip_req.msgHeader.via),
+ g_rx_sip_req.msgHeader.cSeq.seqNumber,
+ body := omit);
+ as_SIP_expect_req(exp_req);
+ }
+}
+altstep as_IMS_exp_call_hold() runs on IMS_ConnHdlr
+{
+ [] as_IMS_exp_call_holdresume(tr_SDP_sendonly, "recvonly");
+}
+altstep as_IMS_exp_call_resume() runs on IMS_ConnHdlr
+{
+ [] as_IMS_exp_call_holdresume(tr_SDP_sendrecv, "sendrecv");
+}
+
}
diff --git a/asterisk/SIP_ConnectionHandler.ttcn b/asterisk/SIP_ConnectionHandler.ttcn
index f688fe0..ad76296 100644
--- a/asterisk/SIP_ConnectionHandler.ttcn
+++ b/asterisk/SIP_ConnectionHandler.ttcn
@@ -239,7 +239,7 @@
}
}
-private function f_gen_sdp() runs on SIPConnHdlr return charstring {
+private function f_gen_sdp(charstring dir := "sendrecv") runs on SIPConnHdlr return charstring {
var charstring sdp :=
"v=0\r\n" &
"o=0502 2390 1824 IN IP4 " & g_pars.cp.local_rtp_addr & "\r\n" &
@@ -248,18 +248,9 @@
"t=0 0\r\n" &
"a=rtcp-xr:rcvr-rtt=all:10000 stat-summary=loss,dup,jitt,TTL voip-metrics\r\n" &
"a=record:off\r\n" &
- "m=audio " & int2str(g_pars.cp.local_rtp_port) & " RTP/AVP 8 96 97 98 0 18 99 100 101\r\n" &
+ "m=audio " & int2str(g_pars.cp.local_rtp_port) & " RTP/AVP 8\r\n" &
+ "a=" & dir & "\r\n" &
"a=rtpmap:8 PCMA/8000\r\n" &
- "a=rtpmap:96 opus/48000/2\r\n" &
- "a=fmtp:96 useinbandfec=1\r\n" &
- "a=rtpmap:97 speex/16000\r\n" &
- "a=fmtp:97 vbr=on\r\n" &
- "a=rtpmap:98 speex/8000\r\n" &
- "a=fmtp:98 vbr=on\r\n" &
- "a=fmtp:18 annexb=yes\r\n" &
- "a=rtpmap:99 telephone-event/48000\r\n" &
- "a=rtpmap:100 telephone-event/16000\r\n" &
- "a=rtpmap:101 telephone-event/8000\r\n" &
"a=rtcp:" & int2str(g_pars.cp.local_rtp_port + 1) & "\r\n" &
"a=rtcp-fb:* trr-int 1000\r\n" &
"a=rtcp-fb:* ccm tmmbr\r\n";
@@ -815,4 +806,81 @@
[fail_others] as_SIP_fail_req(sip_expect_str);
}
+/* initiate HOLD Tx RE-INVITE (3GPP TS 24.610 A.1.1): */
+private function f_SIP_do_call_holdresume(charstring dir := "sendonly",
+ template (present) SDP_attribute exp_resp_dir := tr_SDP_recvonly) runs on SIPConnHdlr
+{
+ var template (value) PDU_SIP_Request req;
+ var template (present) PDU_SIP_Response exp_resp;
+ var template (present) From from_addr_exp;
+ var template (present) To to_addr_exp;
+ var Via via;
+ var charstring branch_value;
+ var charstring tx_sdp := f_gen_sdp(dir := dir);
+
+ /* Reuse g_pars.cp.from_addr and g_pars.cp.to_addr from established called */
+ from_addr_exp := tr_From(tr_Addr_Union_from_val(g_pars.cp.from_addr.addressField), *);
+ to_addr_exp := tr_To(tr_Addr_Union_from_val(g_pars.cp.to_addr.addressField), *);
+ branch_value := f_sip_gen_branch(f_sip_Addr_Union_to_str(g_pars.cp.from_addr.addressField),
+ f_sip_Addr_Union_to_str(valueof(g_pars.cp.to_addr.addressField)),
+ g_pars.cp.sip_call_id,
+ g_pars.cp.sip_seq_nr);
+
+ via := g_pars.local_via;
+ via.viaBody[0].viaParams := f_sip_param_set(via.viaBody[0].viaParams, "branch", branch_value);
+
+ /* Transmit re-INVITE (HOLD) */
+ req := ts_SIP_INVITE(g_pars.cp.sip_call_id,
+ g_pars.cp.from_addr,
+ g_pars.cp.to_addr,
+ via,
+ g_pars.local_contact,
+ g_pars.cp.sip_seq_nr,
+ body := tx_sdp);
+ SIP.send(req);
+
+ /* Wait for OK answer */
+ exp_resp := tr_SIP_Response(
+ g_pars.cp.sip_call_id,
+ from_addr_exp,
+ to_addr_exp,
+ f_tr_Via_response(via),
+ *,
+ "INVITE", 200,
+ g_pars.cp.sip_seq_nr, "OK",
+ body := ?);
+ as_SIP_expect_resp(exp_resp);
+ f_SDP_decodeMessage(g_rx_sip_resp.messageBody, g_pars.cp.peer_sdp);
+
+ /* Check a=$exp_resp_dir in SDP */
+ if (not ispresent(g_pars.cp.peer_sdp.media_list[0].attributes) or
+ not match (g_pars.cp.peer_sdp.media_list[0].attributes, superset(exp_resp_dir))) {
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
+ log2str(g_name & ": Expected 200 OK (re-INVITE) SDP attribute a=", exp_resp_dir, " in: ",
+ g_pars.cp.peer_sdp.media_list[0].attributes));
+ }
+
+ /* Update To with the tags received from peer: */
+ g_pars.cp.to_addr := g_rx_sip_resp.msgHeader.toField;
+
+ /* Transmit ACK */
+ req := ts_SIP_ACK(g_pars.cp.to_addr.addressField.nameAddr.addrSpec,
+ g_pars.cp.sip_call_id,
+ g_pars.cp.from_addr,
+ g_pars.cp.to_addr,
+ via,
+ g_pars.cp.sip_seq_nr,
+ omit);
+ SIP.send(req);
+ g_pars.cp.sip_seq_nr := g_pars.cp.sip_seq_nr + 1;
+}
+function f_SIP_do_call_hold() runs on SIPConnHdlr
+{
+ f_SIP_do_call_holdresume(dir := "sendonly", exp_resp_dir := tr_SDP_recvonly);
+}
+function f_SIP_do_call_resume() runs on SIPConnHdlr
+{
+ f_SIP_do_call_holdresume(dir := "sendrecv", exp_resp_dir := tr_SDP_sendrecv);
+}
+
}
diff --git a/asterisk/expected-results.xml b/asterisk/expected-results.xml
index 179ee70..1819072 100644
--- a/asterisk/expected-results.xml
+++ b/asterisk/expected-results.xml
@@ -17,6 +17,7 @@
<testcase classname='Asterisk_Tests' name='TC_ims_call_mo' time='MASKED'/>
<testcase classname='Asterisk_Tests' name='TC_ims_call_mo_session_timer' time='MASKED'/>
<testcase classname='Asterisk_Tests' name='TC_ims_call_mo_noprecondition' time='MASKED'/>
+ <testcase classname='Asterisk_Tests' name='TC_ims_call_mo_holdresume_mo' time='MASKED'/>
<testcase classname='Asterisk_Tests' name='TC_ims_call_mt' time='MASKED'/>
<testcase classname='Asterisk_Tests' name='TC_ims_call_mt_noprecondition' time='MASKED'/>
</testsuite>
diff --git a/library/SDP_Templates.ttcn b/library/SDP_Templates.ttcn
index 782c672..b8fc6c8 100644
--- a/library/SDP_Templates.ttcn
+++ b/library/SDP_Templates.ttcn
@@ -155,6 +155,10 @@
sendonly := {}
}
+template (present) SDP_attribute tr_SDP_sendrecv := {
+ sendrecv := {}
+}
+
/* rfc3312 */
const charstring c_SDP_PRECON_TYPE_qos := "qos";
const charstring c_SDP_PRECON_STRENGTH_TAG_mandatory := "mandatory";
To view, visit change 37426. To unsubscribe, or for help writing mail filters, visit settings.