Merge changes I53ffe442,Ic0750bdc,Ic5499a0b,I67343f01
* changes:
bsc: Run three virtual BTSs (2 in one lac, 1 in another)
Add RTP_Emulation (stream source/sink) on top of RTP_CodecPort
Add missing RTP_CodecPort_CtrlFunct TTCN and C++ files
move RTP_CodecPort.ttcn to library
diff --git a/bsc/BSC_Tests.ttcn b/bsc/BSC_Tests.ttcn
index 926e8cc..2e48e0b 100644
--- a/bsc/BSC_Tests.ttcn
+++ b/bsc/BSC_Tests.ttcn
@@ -22,7 +22,7 @@
import from RSL_Tests all;
-const integer NUM_BTS := 1;
+const integer NUM_BTS := 3;
const float T3101_MAX := 12.0;
@@ -88,7 +88,7 @@
map(clnt.vc_IPA:IPA_PORT, system:IPA_CODEC_PT);
connect(clnt.vc_IPA:IPA_RSL_PORT, self:IPA_RSL[i]);
- clnt.vc_IPA.start(IPA_Emulation.main_client(bsc_host, bsc_port, "", -1, clnt.ccm_pars));
+ clnt.vc_IPA.start(IPA_Emulation.main_client(bsc_host, bsc_port, "", 10000+i, clnt.ccm_pars));
/* wait for IPA RSL link to connect and send ID ACK */
T.start;
@@ -606,10 +606,21 @@
};
private const Cell_Identity cid := { '001'H, '001'H, 1, 0 };
+type set of integer BtsIdList;
+
+private function f_bts_in_list(integer bts_id, BtsIdList bts_ids) return boolean {
+ for (var integer j := 0; j < sizeof(bts_ids); j := j + 1) {
+ if (bts_id == bts_ids[j]) {
+ return true;
+ }
+ }
+ return false;
+}
/* core paging test helper function; used by most paging test cases */
private function f_pageing_helper(hexstring imsi,
template BSSMAP_FIELD_CellIdentificationList cid_list,
+ BtsIdList bts_ids := { 0 },
template RSL_ChanNeeded rsl_chneed := omit,
template OCT4 tmsi := omit) runs on test_CT
{
@@ -618,12 +629,15 @@
var template octetstring id_enc; /* FIXME */
var RSL_Message rx_rsl;
var integer paging_group := hex2int(imsi[lengthof(imsi)-1]);
+ var integer i;
f_init();
f_bssap_reset();
/* Clear the queue, it might still contain stuff like BCCH FILLING */
- IPA_RSL[0].clear;
+ for (i := 0; i < sizeof(bts_ids); i := i + 1) {
+ IPA_RSL[bts_ids[i]].clear;
+ }
if (isvalue(rsl_chneed)) {
/* The values of 08.08 3.2.2.36 and 08.58 9.3.40 are luckily identical */
@@ -643,95 +657,116 @@
id_enc := enc_MobileIdentity(mi);
*/
id_enc := ?;
- rx_rsl := f_exp_ipa_rx(0, tr_RSL_PAGING_CMD(id_enc));
- /* check channel type, paging group */
- if (rx_rsl.ies[1].body.paging_group != paging_group) {
- setverdict(fail, "Paging for wrong paging group");
+ for (i := 0; i < sizeof(bts_ids); i := i + 1) {
+ rx_rsl := f_exp_ipa_rx(bts_ids[i], tr_RSL_PAGING_CMD(id_enc));
+ /* check channel type, paging group */
+ if (rx_rsl.ies[1].body.paging_group != paging_group) {
+ setverdict(fail, "Paging for wrong paging group");
+ }
+ if (ispresent(rsl_chneed) and
+ rx_rsl.ies[3].body.chan_needed.chan_needed != valueof(rsl_chneed)) {
+ setverdict(fail, "RSL Channel Needed != BSSMAP Channel Needed");
+ }
}
- if (ispresent(rsl_chneed) and
- rx_rsl.ies[3].body.chan_needed.chan_needed != valueof(rsl_chneed)) {
- setverdict(fail, "RSL Channel Needed != BSSMAP Channel Needed");
+ /* do a quick check on all not-included BTSs if they received paging */
+ for (i := 0; i < NUM_BTS; i := i + 1) {
+ timer T := 0.1;
+ if (f_bts_in_list(i, bts_ids)) {
+ continue;
+ }
+ T.start;
+ alt {
+ [] IPA_RSL[i].receive(tr_ASP_RSL_UD(IPAC_PROTO_RSL_TRX0, tr_RSL_PAGING_CMD(id_enc))) {
+ setverdict(fail, "Paging on BTS ", i, " which is not part of ", bts_ids);
+ }
+ [] IPA_RSL[i].receive { repeat; }
+ [] T.timeout { }
+ }
}
setverdict(pass);
}
+const BtsIdList c_BtsId_all := { 0, 1, 2 };
+const BtsIdList c_BtsId_LAC1 := { 0, 1 };
+const BtsIdList c_BtsId_LAC2 := { 2 };
+
/* PAGING by IMSI + TMSI */
testcase TC_paging_imsi_nochan() runs on test_CT {
var BSSMAP_FIELD_CellIdentificationList cid_list;
cid_list := valueof(ts_BSSMAP_CIL_noCell);
- f_pageing_helper('001010123456789'H, cid_list);
+ f_pageing_helper('001010123456789'H, cid_list, c_BtsId_all);
}
/* PAGING by IMSI + TMSI */
testcase TC_paging_tmsi_nochan() runs on test_CT {
var BSSMAP_FIELD_CellIdentificationList cid_list;
cid_list := valueof(ts_BSSMAP_CIL_noCell);
- f_pageing_helper('001010100000001'H, cid_list, omit, 'A1B2C301'O);
+ f_pageing_helper('001010100000001'H, cid_list, c_BtsId_all, omit, 'A1B2C301'O);
}
/* Paging with different "channel needed' values */
testcase TC_paging_tmsi_any() runs on test_CT {
var BSSMAP_FIELD_CellIdentificationList cid_list;
cid_list := valueof(ts_BSSMAP_CIL_noCell);
- f_pageing_helper('001010100000002'H, cid_list, RSL_CHANNEED_ANY, 'A1B2C302'O);
+ f_pageing_helper('001010100000002'H, cid_list, c_BtsId_all, RSL_CHANNEED_ANY, 'A1B2C302'O);
}
testcase TC_paging_tmsi_sdcch() runs on test_CT {
var BSSMAP_FIELD_CellIdentificationList cid_list;
cid_list := valueof(ts_BSSMAP_CIL_noCell);
- f_pageing_helper('001010100000003'H, cid_list, RSL_CHANNEED_SDCCH, 'A1B2C303'O);
+ f_pageing_helper('001010100000003'H, cid_list, c_BtsId_all, RSL_CHANNEED_SDCCH, 'A1B2C303'O);
}
testcase TC_paging_tmsi_tch_f() runs on test_CT {
var BSSMAP_FIELD_CellIdentificationList cid_list;
cid_list := valueof(ts_BSSMAP_CIL_noCell);
- f_pageing_helper('001010000000004'H, cid_list, RSL_CHANNEED_TCH_F, 'A1B2C304'O);
+ f_pageing_helper('001010000000004'H, cid_list, c_BtsId_all, RSL_CHANNEED_TCH_F, 'A1B2C304'O);
}
testcase TC_paging_tmsi_tch_hf() runs on test_CT {
var BSSMAP_FIELD_CellIdentificationList cid_list;
cid_list := valueof(ts_BSSMAP_CIL_noCell);
- f_pageing_helper('001010000000005'H, cid_list, RSL_CHANNEED_TCH_ForH, 'A1B2C305'O);
+ f_pageing_helper('001010000000005'H, cid_list, c_BtsId_all, RSL_CHANNEED_TCH_ForH, 'A1B2C305'O);
}
/* Paging by CGI */
testcase TC_paging_imsi_nochan_cgi() runs on test_CT {
var template BSSMAP_FIELD_CellIdentificationList cid_list;
cid_list := { cIl_CGI := { ts_BSSMAP_CI_CGI(cid.mcc, cid.mnc, cid.lac, cid.ci) } };
- f_pageing_helper('001010000000006'H, cid_list);
+ f_pageing_helper('001010000000006'H, cid_list, { 0 });
}
/* Paging by LAC+CI */
testcase TC_paging_imsi_nochan_lac_ci() runs on test_CT {
var template BSSMAP_FIELD_CellIdentificationList cid_list;
cid_list := { cIl_LAC_CI := { ts_BSSMAP_CI_LAC_CI(cid.lac, cid.ci) } };
- f_pageing_helper('001010000000007'H, cid_list);
+ f_pageing_helper('001010000000007'H, cid_list, { 0 });
}
/* Paging by CI */
testcase TC_paging_imsi_nochan_ci() runs on test_CT {
var template BSSMAP_FIELD_CellIdentificationList cid_list;
cid_list := { cIl_CI := { ts_BSSMAP_CI_CI(cid.ci) } };
- f_pageing_helper('001010000000008'H, cid_list);
+ f_pageing_helper('001010000000008'H, cid_list, { 0 });
}
/* Paging by LAI */
testcase TC_paging_imsi_nochan_lai() runs on test_CT {
var template BSSMAP_FIELD_CellIdentificationList cid_list;
cid_list := { cIl_LAI := { ts_BSSMAP_CI_LAI(cid.mcc, cid.mnc, cid.lac) } };
- f_pageing_helper('001010000000009'H, cid_list);
+ f_pageing_helper('001010000000009'H, cid_list, c_BtsId_LAC1);
}
/* Paging by LAC */
testcase TC_paging_imsi_nochan_lac() runs on test_CT {
var template BSSMAP_FIELD_CellIdentificationList cid_list;
cid_list := { cIl_LAC := { ts_BSSMAP_CI_LAC(cid.lac) } };
- f_pageing_helper('001010000000010'H, cid_list);
+ f_pageing_helper('001010000000010'H, cid_list, c_BtsId_LAC1);
}
/* Paging by "all in BSS" */
testcase TC_paging_imsi_nochan_all() runs on test_CT {
var template BSSMAP_FIELD_CellIdentificationList cid_list;
cid_list := { cIl_allInBSS := ''O };
- f_pageing_helper('001010000000011'H, cid_list);
+ f_pageing_helper('001010000000011'H, cid_list, c_BtsId_all);
}
/* Paging by PLMN+LAC+RNC */
@@ -749,7 +784,7 @@
var BSSMAP_FIELD_CellIdentificationList cid_list;
timer T := 4.0;
cid_list := valueof(ts_BSSMAP_CIL_noCell);
- f_pageing_helper('001010123456789'H, cid_list);
+ f_pageing_helper('001010123456789'H, cid_list, c_BtsId_all);
/* tell BSC there is no paging space anymore */
f_ipa_tx(0, ts_RSL_PAGING_LOAD_IND(0));
@@ -773,7 +808,7 @@
var BSSMAP_FIELD_CellIdentificationList cid_list;
timer T := 3.0;
cid_list := valueof(ts_BSSMAP_CIL_noCell);
- f_pageing_helper('001010123456789'H, cid_list);
+ f_pageing_helper('001010123456789'H, cid_list, c_BtsId_all);
/* Perform a BSSMAP Reset and wait for ACK */
BSSAP.send(ts_BSSAP_UNITDATA_req(g_sccp_addr_peer, g_sccp_addr_own, ts_BSSMAP_Reset(0)));
@@ -792,6 +827,14 @@
setverdict(fail, "Received PAGING after A-RESET");
self.stop;
}
+ [] IPA_RSL[1].receive(tr_ASP_RSL_UD(IPAC_PROTO_RSL_TRX0, tr_RSL_PAGING_CMD(?))) {
+ setverdict(fail, "Received PAGING after A-RESET");
+ self.stop;
+ }
+ [] IPA_RSL[2].receive(tr_ASP_RSL_UD(IPAC_PROTO_RSL_TRX0, tr_RSL_PAGING_CMD(?))) {
+ setverdict(fail, "Received PAGING after A-RESET");
+ self.stop;
+ }
[] T.timeout {
setverdict(pass);
}
diff --git a/bsc/osmo-bsc.cfg b/bsc/osmo-bsc.cfg
index 488ba09..ac1553e 100644
--- a/bsc/osmo-bsc.cfg
+++ b/bsc/osmo-bsc.cfg
@@ -176,6 +176,186 @@
timeslot 7
phys_chan_config PDCH
hopping enabled 0
+ bts 1
+ type sysmobts
+ band DCS1800
+ cell_identity 1
+ location_area_code 2
+ dtx uplink force
+ dtx downlink
+ base_station_id_code 63
+ ms max power 15
+ cell reselection hysteresis 4
+ rxlev access min 0
+ radio-link-timeout 32
+ channel allocator ascending
+ rach tx integer 9
+ rach max transmission 7
+ channel-descrption attach 1
+ channel-descrption bs-pa-mfrms 5
+ channel-descrption bs-ag-blks-res 1
+ early-classmark-sending forbidden
+ ip.access unit_id 1235 0
+ oml ip.access stream_id 255 line 0
+ neighbor-list mode manual-si5
+ neighbor-list add arfcn 100
+ neighbor-list add arfcn 200
+ si5 neighbor-list add arfcn 10
+ si5 neighbor-list add arfcn 20
+ codec-support fr
+ gprs mode gprs
+ gprs 11bit_rach_support_for_egprs 0
+ gprs routing area 0
+ gprs network-control-order nc0
+ gprs cell bvci 1235
+ gprs cell timer blocking-timer 3
+ gprs cell timer blocking-retries 3
+ gprs cell timer unblocking-retries 3
+ gprs cell timer reset-timer 3
+ gprs cell timer reset-retries 3
+ gprs cell timer suspend-timer 10
+ gprs cell timer suspend-retries 3
+ gprs cell timer resume-timer 10
+ gprs cell timer resume-retries 3
+ gprs cell timer capability-update-timer 10
+ gprs cell timer capability-update-retries 3
+ gprs nsei 1235
+ gprs ns timer tns-block 3
+ gprs ns timer tns-block-retries 3
+ gprs ns timer tns-reset 3
+ gprs ns timer tns-reset-retries 3
+ gprs ns timer tns-test 30
+ gprs ns timer tns-alive 3
+ gprs ns timer tns-alive-retries 10
+ gprs nsvc 0 nsvci 1235
+ gprs nsvc 0 local udp port 23000
+ gprs nsvc 0 remote udp port 23000
+ gprs nsvc 0 remote ip 192.168.100.239
+ gprs nsvc 1 nsvci 0
+ gprs nsvc 1 local udp port 0
+ gprs nsvc 1 remote udp port 0
+ gprs nsvc 1 remote ip 0.0.0.0
+ no force-combined-si
+ trx 0
+ rf_locked 0
+ arfcn 871
+ nominal power 23
+ max_power_red 20
+ rsl e1 tei 0
+ timeslot 0
+ phys_chan_config CCCH+SDCCH4
+ hopping enabled 0
+ timeslot 1
+ phys_chan_config TCH/F
+ hopping enabled 0
+ timeslot 2
+ phys_chan_config TCH/F
+ hopping enabled 0
+ timeslot 3
+ phys_chan_config TCH/F
+ hopping enabled 0
+ timeslot 4
+ phys_chan_config TCH/F
+ hopping enabled 0
+ timeslot 5
+ phys_chan_config TCH/F
+ hopping enabled 0
+ timeslot 6
+ phys_chan_config PDCH
+ hopping enabled 0
+ timeslot 7
+ phys_chan_config PDCH
+ hopping enabled 0
+ bts 2
+ type sysmobts
+ band DCS1800
+ cell_identity 1
+ location_area_code 1
+ dtx uplink force
+ dtx downlink
+ base_station_id_code 63
+ ms max power 15
+ cell reselection hysteresis 4
+ rxlev access min 0
+ radio-link-timeout 32
+ channel allocator ascending
+ rach tx integer 9
+ rach max transmission 7
+ channel-descrption attach 1
+ channel-descrption bs-pa-mfrms 5
+ channel-descrption bs-ag-blks-res 1
+ early-classmark-sending forbidden
+ ip.access unit_id 1236 0
+ oml ip.access stream_id 255 line 0
+ neighbor-list mode manual-si5
+ neighbor-list add arfcn 100
+ neighbor-list add arfcn 200
+ si5 neighbor-list add arfcn 10
+ si5 neighbor-list add arfcn 20
+ codec-support fr
+ gprs mode gprs
+ gprs 11bit_rach_support_for_egprs 0
+ gprs routing area 0
+ gprs network-control-order nc0
+ gprs cell bvci 1236
+ gprs cell timer blocking-timer 3
+ gprs cell timer blocking-retries 3
+ gprs cell timer unblocking-retries 3
+ gprs cell timer reset-timer 3
+ gprs cell timer reset-retries 3
+ gprs cell timer suspend-timer 10
+ gprs cell timer suspend-retries 3
+ gprs cell timer resume-timer 10
+ gprs cell timer resume-retries 3
+ gprs cell timer capability-update-timer 10
+ gprs cell timer capability-update-retries 3
+ gprs nsei 1236
+ gprs ns timer tns-block 3
+ gprs ns timer tns-block-retries 3
+ gprs ns timer tns-reset 3
+ gprs ns timer tns-reset-retries 3
+ gprs ns timer tns-test 30
+ gprs ns timer tns-alive 3
+ gprs ns timer tns-alive-retries 10
+ gprs nsvc 0 nsvci 1236
+ gprs nsvc 0 local udp port 23000
+ gprs nsvc 0 remote udp port 23000
+ gprs nsvc 0 remote ip 192.168.100.239
+ gprs nsvc 1 nsvci 0
+ gprs nsvc 1 local udp port 0
+ gprs nsvc 1 remote udp port 0
+ gprs nsvc 1 remote ip 0.0.0.0
+ no force-combined-si
+ trx 0
+ rf_locked 0
+ arfcn 871
+ nominal power 23
+ max_power_red 20
+ rsl e1 tei 0
+ timeslot 0
+ phys_chan_config CCCH+SDCCH4
+ hopping enabled 0
+ timeslot 1
+ phys_chan_config TCH/F
+ hopping enabled 0
+ timeslot 2
+ phys_chan_config TCH/F
+ hopping enabled 0
+ timeslot 3
+ phys_chan_config TCH/F
+ hopping enabled 0
+ timeslot 4
+ phys_chan_config TCH/F
+ hopping enabled 0
+ timeslot 5
+ phys_chan_config TCH/F
+ hopping enabled 0
+ timeslot 6
+ phys_chan_config PDCH
+ hopping enabled 0
+ timeslot 7
+ phys_chan_config PDCH
+ hopping enabled 0
msc 0
ip.access rtp-base 4000
timeout-ping 20
diff --git a/library/BSSMAP_Templates.ttcn b/library/BSSMAP_Templates.ttcn
index 22fefdd..54e3f79 100644
--- a/library/BSSMAP_Templates.ttcn
+++ b/library/BSSMAP_Templates.ttcn
@@ -449,7 +449,7 @@
}
private function f_enc_mcc_mnc(GsmMcc mcc, GsmMnc mnc) return OCT3 {
- return hex2oct(mcc[1] & mcc[0] & mnc[0] & mnc[3] & mnc[2]);
+ return hex2oct(mcc[1] & mcc[0] & mnc[0] & mnc[2] & mnc[1]);
}
template BSSMAP_FIELD_CellIdentification_CGI ts_BSSMAP_CI_CGI(GsmMcc mcc, GsmMnc mnc, GsmLac lac, GsmCellId ci) := {
diff --git a/mgw/RTP_CodecPort.ttcn b/library/RTP_CodecPort.ttcn
similarity index 100%
rename from mgw/RTP_CodecPort.ttcn
rename to library/RTP_CodecPort.ttcn
diff --git a/library/RTP_CodecPort_CtrlFunct.ttcn b/library/RTP_CodecPort_CtrlFunct.ttcn
new file mode 100644
index 0000000..9f6cad2
--- /dev/null
+++ b/library/RTP_CodecPort_CtrlFunct.ttcn
@@ -0,0 +1,44 @@
+module RTP_CodecPort_CtrlFunct {
+
+ import from RTP_CodecPort all;
+ import from IPL4asp_Types all;
+
+ external function f_IPL4_listen(
+ inout RTP_CODEC_PT portRef,
+ in HostName locName,
+ in PortNumber locPort,
+ in ProtoTuple proto,
+ in OptionList options := {}
+ ) return Result;
+
+ external function f_IPL4_connect(
+ inout RTP_CODEC_PT portRef,
+ in HostName remName,
+ in PortNumber remPort,
+ in HostName locName,
+ in PortNumber locPort,
+ in ConnectionId connId,
+ in ProtoTuple proto,
+ in OptionList options := {}
+ ) return Result;
+
+ external function f_IPL4_close(
+ inout RTP_CODEC_PT portRef,
+ in ConnectionId id,
+ in ProtoTuple proto := { unspecified := {} }
+ ) return Result;
+
+ external function f_IPL4_setUserData(
+ inout RTP_CODEC_PT portRef,
+ in ConnectionId id,
+ in UserData userData
+ ) return Result;
+
+ external function f_IPL4_getUserData(
+ inout RTP_CODEC_PT portRef,
+ in ConnectionId id,
+ out UserData userData
+ ) return Result;
+
+}
+
diff --git a/library/RTP_CodecPort_CtrlFunctDef.cc b/library/RTP_CodecPort_CtrlFunctDef.cc
new file mode 100644
index 0000000..ce8e176
--- /dev/null
+++ b/library/RTP_CodecPort_CtrlFunctDef.cc
@@ -0,0 +1,56 @@
+#include "IPL4asp_PortType.hh"
+#include "RTP_CodecPort.hh"
+#include "IPL4asp_PT.hh"
+
+namespace RTP__CodecPort__CtrlFunct {
+
+ IPL4asp__Types::Result f__IPL4__listen(
+ RTP__CodecPort::RTP__CODEC__PT& portRef,
+ const IPL4asp__Types::HostName& locName,
+ const IPL4asp__Types::PortNumber& locPort,
+ const IPL4asp__Types::ProtoTuple& proto,
+ const IPL4asp__Types::OptionList& options)
+ {
+ return f__IPL4__PROVIDER__listen(portRef, locName, locPort, proto, options);
+ }
+
+ IPL4asp__Types::Result f__IPL4__connect(
+ RTP__CodecPort::RTP__CODEC__PT& portRef,
+ const IPL4asp__Types::HostName& remName,
+ const IPL4asp__Types::PortNumber& remPort,
+ const IPL4asp__Types::HostName& locName,
+ const IPL4asp__Types::PortNumber& locPort,
+ const IPL4asp__Types::ConnectionId& connId,
+ const IPL4asp__Types::ProtoTuple& proto,
+ const IPL4asp__Types::OptionList& options)
+ {
+ return f__IPL4__PROVIDER__connect(portRef, remName, remPort,
+ locName, locPort, connId, proto, options);
+ }
+
+ IPL4asp__Types::Result f__IPL4__close(
+ RTP__CodecPort::RTP__CODEC__PT& portRef,
+ const IPL4asp__Types::ConnectionId& connId,
+ const IPL4asp__Types::ProtoTuple& proto)
+ {
+ return f__IPL4__PROVIDER__close(portRef, connId, proto);
+ }
+
+ IPL4asp__Types::Result f__IPL4__setUserData(
+ RTP__CodecPort::RTP__CODEC__PT& portRef,
+ const IPL4asp__Types::ConnectionId& connId,
+ const IPL4asp__Types::UserData& userData)
+ {
+ return f__IPL4__PROVIDER__setUserData(portRef, connId, userData);
+ }
+
+ IPL4asp__Types::Result f__IPL4__getUserData(
+ RTP__CodecPort::RTP__CODEC__PT& portRef,
+ const IPL4asp__Types::ConnectionId& connId,
+ IPL4asp__Types::UserData& userData)
+ {
+ return f__IPL4__PROVIDER__getUserData(portRef, connId, userData);
+ }
+
+}
+
diff --git a/library/RTP_Emulation.ttcn b/library/RTP_Emulation.ttcn
new file mode 100644
index 0000000..b8b1dbe
--- /dev/null
+++ b/library/RTP_Emulation.ttcn
@@ -0,0 +1,209 @@
+module RTP_Emulation {
+
+/* Functionalities that we want this module to imeplement:
+ * * act as a RTP source that generates a RTP Stream
+ * * act asaa RTP sink that consumes a RTP Stream
+ *
+ * for all of the above, we want to be able to
+ * * specify the payload type
+ * * specify the interval / sample rate
+ * * create drop-outs in the stream
+ * * detect reordered or lost frames
+ * * validate if the size of the frames matches epectations
+ * * play back real audio (at least some tones?)
+ * * enable/disable generation/verification of RTCP
+ */
+
+import from General_Types all;
+import from Osmocom_Types all;
+import from IPL4asp_Types all;
+import from RTP_Types all;
+import from RTP_CodecPort all;
+import from RTP_CodecPort_CtrlFunct all;
+
+type component RTP_Emulation_CT {
+ /* down-facing ports for RTP and RTCP codec ports on top of IPL4asp */
+ port RTP_CODEC_PT RTP;
+ var integer g_rtp_conn_id := -1;
+ port RTP_CODEC_PT RTCP;
+ var integer g_rtcp_conn_id := -1;
+
+ /* user-facing port for controlling the binding */
+ port RTPEM_CTRL_PT CTRL;
+
+ /* configurable by user, should be fixed */
+ var INT7b g_tx_payload_type := 0;
+ var integer g_tx_samplerate_hz := 8000;
+ var integer g_tx_duration_ms := 20;
+ var BIT32_BO_LAST g_tx_ssrc := hex2bit('DEADBEEF'H);
+
+ var HostName g_remote_host;
+ var PortNumber g_remote_port;
+ var HostName g_local_host;
+ var PortNumber g_local_port;
+
+ /* state variables, change over time */
+ var boolean g_rx_enabled := false;
+ var LIN2_BO_LAST g_tx_next_seq := 0;
+ var uint32_t g_tx_next_ts := 0;
+
+ var INT7b g_rx_payload_type := 0;
+ var LIN2_BO_LAST g_rx_last_seq;
+ var uint32_t g_rx_last_ts;
+}
+
+type enumerated RtpemMode {
+ RTPEM_MODE_NONE,
+ RTPEM_MODE_TXONLY,
+ RTPEM_MODE_RXONLY,
+ RTPEM_MODE_BIDIR
+};
+
+signature RTPEM_bind(in HostName local_host, inout PortNumber local_port);
+signature RTPEM_connect(in HostName remote_host, in PortNumber remote_port);
+signature RTPEM_mode(in RtpemMode mode);
+
+type port RTPEM_CTRL_PT procedure {
+ inout RTPEM_bind, RTPEM_connect, RTPEM_mode;
+} with { extension "internal" };
+
+template PDU_RTP ts_RTP(BIT32_BO_LAST ssrc, INT7b pt, LIN2_BO_LAST seq, uint32_t ts,
+ octetstring payload, BIT1 marker := '0'B) := {
+ version := 2,
+ padding_ind := '0'B,
+ extension_ind := '0'B,
+ CSRC_count := 0,
+ marker_bit := marker,
+ payload_type := pt,
+ sequence_number := seq,
+ time_stamp := int2bit(ts, 4),
+ SSRC_id := ssrc,
+ CSRCs := omit,
+ ext_header := omit,
+ data := payload
+}
+
+private function f_tx_rtp(octetstring payload, BIT1 marker := '0'B) runs on RTP_Emulation_CT {
+ var PDU_RTP rtp := valueof(ts_RTP(g_tx_ssrc, g_tx_payload_type, g_tx_next_seq,
+ g_tx_next_ts, payload, marker));
+ RTP.send(t_RTP_Send(g_rtp_conn_id, RTP_messages_union:{rtp:=rtp}));
+ /* increment sequence + timestamp for next transmit */
+ g_tx_next_seq := g_tx_next_seq + 1;
+ g_tx_next_ts := g_tx_next_ts + (g_tx_samplerate_hz mod (1000 mod g_tx_duration_ms));
+}
+
+function f_main() runs on RTP_Emulation_CT
+{
+ var Result res;
+
+ timer T_transmit := 1000.0/int2float(g_tx_duration_ms);
+ var RTP_RecvFrom rx_rtp;
+ var template RTP_RecvFrom tr := {
+ connId := ?,
+ remName := ?,
+ remPort := ?,
+ locName := ?,
+ locPort := ?,
+ msg := ?
+ };
+ var template RTP_RecvFrom tr_rtp := tr;
+ var template RTP_RecvFrom tr_rtcp := tr;
+ tr_rtp.connId := g_rtp_conn_id;
+ tr_rtp.msg := { rtp := ? };
+ tr_rtp.connId := g_rtcp_conn_id;
+ tr_rtcp.msg := { rtcp := ? };
+
+ while (true) {
+ alt {
+ /* control procedures (calls) from the user */
+ [] CTRL.getcall(RTPEM_bind:{?,?}) -> param(g_local_host, g_local_port) {
+ if (g_local_port rem 2 == 1) {
+ //CTRL.raise(RTPEM_bind, "Local Port is not an even port number!");
+ log("Local Port is not an even port number!");
+ continue;
+ }
+ res := RTP_CodecPort_CtrlFunct.f_IPL4_listen(RTP, g_local_host,
+ g_local_port, {udp:={}});
+ g_rtp_conn_id := res.connId;
+ res := RTP_CodecPort_CtrlFunct.f_IPL4_listen(RTP, g_local_host,
+ g_local_port+1, {udp:={}});
+ g_rtcp_conn_id := res.connId;
+ CTRL.reply(RTPEM_bind:{g_local_host, g_local_port});
+ }
+ [] CTRL.getcall(RTPEM_connect:{?,?}) -> param (g_remote_host, g_remote_port) {
+ if (g_remote_port rem 2 == 1) {
+ //CTRL.raise(RTPEM_connect, "Remote Port is not an even number!");
+ log("Remote Port is not an even number!");
+ continue;
+ }
+ res := RTP_CodecPort_CtrlFunct.f_IPL4_connect(RTP, g_remote_host,
+ g_remote_port,
+ g_local_host, g_local_port,
+ g_rtp_conn_id, {udp:={}});
+ res := RTP_CodecPort_CtrlFunct.f_IPL4_connect(RTCP, g_remote_host,
+ g_remote_port+1,
+ g_local_host, g_local_port+1,
+ g_rtcp_conn_id, {udp:={}});
+ CTRL.reply(RTPEM_connect:{g_remote_host, g_remote_port});
+ }
+ [] CTRL.getcall(RTPEM_mode:{RTPEM_MODE_NONE}) {
+ T_transmit.stop;
+ g_rx_enabled := false;
+ }
+ [] CTRL.getcall(RTPEM_mode:{RTPEM_MODE_TXONLY}) {
+ /* start transmit timer */
+ T_transmit.start;
+ g_rx_enabled := false;
+ }
+ [] CTRL.getcall(RTPEM_mode:{RTPEM_MODE_RXONLY}) {
+
+ T_transmit.stop;
+ if (g_rx_enabled == false) {
+ /* flush queues */
+ RTP.clear;
+ RTCP.clear;
+ g_rx_enabled := true;
+ }
+ }
+ [] CTRL.getcall(RTPEM_mode:{RTPEM_MODE_BIDIR}) {
+ T_transmit.start;
+ if (g_rx_enabled == false) {
+ /* flush queues */
+ RTP.clear;
+ RTCP.clear;
+ g_rx_enabled := true;
+ }
+ }
+
+ /* simply ignore any RTTP/RTCP if receiver not enabled */
+ [g_rx_enabled==false] RTP.receive(tr_rtp) { }
+ [g_rx_enabled==false] RTCP.receive(tr_rtp) { }
+
+ /* process received RTCP/RTP if receiver enabled */
+ [g_rx_enabled] RTP.receive(tr_rtp) -> value rx_rtp {
+ log("RX RTP: ", rx_rtp);
+ }
+ [g_rx_enabled] RTCP.receive(tr_rtcp) -> value rx_rtp {
+ log("RX RTCP: ", rx_rtp);
+ }
+
+ /* transmit if timer has expired */
+ [] T_transmit.timeout {
+ /* send one RTP frame, re-start timer */
+ f_tx_rtp('01020304'O);
+ T_transmit.start;
+ }
+
+ /* fail on any unexpected messages */
+ [] RTP.receive {
+ setverdict(fail, "Received unexpected type from RTP");
+ }
+ [] RTCP.receive {
+ setverdict(fail, "Received unexpected type from RTCP");
+ }
+ }
+ }
+}
+
+
+}
diff --git a/mgw/gen_links.sh b/mgw/gen_links.sh
index 0b8195e..acdeb40 100755
--- a/mgw/gen_links.sh
+++ b/mgw/gen_links.sh
@@ -37,5 +37,5 @@
gen_links $DIR $FILES
DIR=../library
-FILES="General_Types.ttcn Osmocom_Types.ttcn MGCP_Types.ttcn MGCP_Templates.ttcn MGCP_CodecPort.ttcn MGCP_CodecPort_CtrlFunct.ttcn MGCP_CodecPort_CtrlFunctDef.cc"
+FILES="General_Types.ttcn Osmocom_Types.ttcn MGCP_Types.ttcn MGCP_Templates.ttcn MGCP_CodecPort.ttcn MGCP_CodecPort_CtrlFunct.ttcn MGCP_CodecPort_CtrlFunctDef.cc RTP_CodecPort.ttcn"
gen_links $DIR $FILES