mgw: Add sockets for RTP packets + code for bind/connect/send RTP
diff --git a/mgw/MGCP_Test.ttcn b/mgw/MGCP_Test.ttcn
index dc44304..07086c9 100644
--- a/mgw/MGCP_Test.ttcn
+++ b/mgw/MGCP_Test.ttcn
@@ -1,8 +1,12 @@
 module MGCP_Test {
+	import from Osmocom_Types all;
 	import from MGCP_Types all;
 	import from SDP_Types all;
 	import from MGCP_CodecPort all;
 	import from MGCP_CodecPort_CtrlFunct all;
+	import from RTP_CodecPort all;
+	import from RTP_CodecPort_CtrlFunct all;
+	import from RTP_Endpoint all;
 	import from IPL4asp_Types all;
 
 	/* any variables declared in the component will be available to
@@ -10,9 +14,12 @@
 	 * class members in C++ */
 	type component dummy_CT {
 		port MGCP_CODEC_PT MGCP;
+		port RTP_CODEC_PT RTP;
 		var boolean initialized := false;
 		var ConnectionId g_mgcp_conn_id := -1;
 		var integer g_trans_id;
+
+		var RtpEndpoint	g_rtp_ep[2];
 	};
 
 	function get_next_trans_id() runs on dummy_CT return MgcpTransId {
@@ -30,6 +37,7 @@
 		charstring mp_local_ip := "127.0.0.1";
 		PortNumber mp_remote_udp_port := 2427;
 		charstring mp_remote_ip := "127.0.0.1";
+		PortNumber mp_local_rtp_port_base := 10000;
 	}
 
 	/* initialization function, called by each test case at the
@@ -37,6 +45,7 @@
 	 * only executed once */
 	private function f_init()runs on dummy_CT {
 		var Result res;
+		var uint32_t ssrc;
 		if (initialized == true) {
 			return;
 		}
@@ -50,6 +59,13 @@
 		 * */
 		res := MGCP_CodecPort_CtrlFunct.f_IPL4_connect(MGCP, mp_remote_ip, mp_remote_udp_port, mp_local_ip, mp_local_udp_port, 0, { udp := {} });
 		g_mgcp_conn_id := res.connId;
+
+		map(self:RTP, system:RTP_CODEC_PT);
+		ssrc := float2int(rnd()*4294967296.0);
+		rtp_endpoint_init(g_rtp_ep[0], mp_local_ip, mp_local_rtp_port_base, ssrc);
+		rtp_endpoint_bind(RTP, g_rtp_ep[0]);
+		rtp_endpoint_init(g_rtp_ep[1], mp_local_ip, mp_local_rtp_port_base+2, ssrc);
+		rtp_endpoint_bind(RTP, g_rtp_ep[1]);
 	}
 
 	/* 3.2.2.6 Connection Mode (sendonly, recvonly, sendrecv, confrnce, inactive, loopback,
diff --git a/mgw/RTP_Endpoint.ttcn b/mgw/RTP_Endpoint.ttcn
new file mode 100644
index 0000000..d33423a
--- /dev/null
+++ b/mgw/RTP_Endpoint.ttcn
@@ -0,0 +1,156 @@
+module RTP_Endpoint {
+
+	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;
+
+	/* state for one of the two UDP sockets in and endpoint */
+	type record RtpEndpointSub {
+		ConnectionId	connection_id,
+		HostName	local_name,
+		PortNumber	local_port,
+		HostName	remote_name,
+		PortNumber	remote_port
+	}
+	/* state for one RTP+RTCP endpoint */
+	type record RtpEndpoint {
+		/* static configuration */
+		INT7b		payload_type,
+		integer		sample_rate,		/* e.g. 8000 */
+		integer		samples_per_pkt,	/* e.g. 160 */
+		BIT32_BO_LAST	ssrc,
+
+		/* dynamic state */
+		uint32_t	next_ts,
+		LIN2_BO_LAST	next_seq_no,
+		RtpEndpointSub	rtp,
+		RtpEndpointSub	rtcp
+	}
+
+/*
+	type component RTP_CT {
+		port RTP_CODEC_PT RTP;
+		ConnectionId	g_conn_id := 1;
+	}
+
+	modulepar {
+		HostName rtp_local_ip := "127.0.0.1";
+		PortNumber rtp_local_base_port := 10000;
+	}
+*/
+
+	template RTP_messages_union ts_RTP(BIT1 marker, INT7b pt, LIN2_BO_LAST seq, uint32_t ts,
+					   BIT32_BO_LAST ssrc, octetstring data) := {
+		rtp := {
+			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, 32),
+			SSRC_id := ssrc,
+			CSRCs := omit,
+			ext_header := omit,
+			data := data
+		}
+	}
+
+	template RTP_messages_union tr_RTP(template INT7b pt, template octetstring data,
+					   template BIT32_BO_LAST ssrc := ?,
+					   template LIN2_BO_LAST seq := ?,
+					   template BIT32_BO_LAST ts := ?) := {
+		rtp := {
+			version := 2,
+			padding_ind := ?,
+			extension_ind := ?,
+			CSRC_count := ?,
+			marker_bit := ?,
+			payload_type := pt,
+			sequence_number := seq,
+			time_stamp := ts,
+			SSRC_id := ssrc,
+			CSRCs := *,
+			ext_header := *,
+			data := data
+		}
+	}
+
+	function rtp_endpoint_init(inout RtpEndpoint ep, charstring local_name, PortNumber local_port,
+				   uint32_t ssrc) {
+		ep.rtp.local_name := local_name;
+		ep.rtp.local_port := local_port;
+		ep.rtp.connection_id := -1;
+		ep.rtcp.local_name := local_name;
+		ep.rtcp.local_port := local_port + 1;
+		ep.rtcp.connection_id := -1;
+		ep.ssrc := int2bit(ssrc, 32);
+
+		ep.payload_type := 99;
+		ep.sample_rate := 8000;
+		ep.samples_per_pkt := 160;
+		ep.next_ts := float2int(rnd()*4294967295.0);
+		ep.next_seq_no := float2int(rnd()*65535.0);
+	}
+
+	function rtp_endpoint_sub_close(inout RTP_CODEC_PT RTP, inout RtpEndpointSub sub) {
+		if (sub.connection_id != -1) {
+			f_IPL4_close(RTP, sub.connection_id, { udp := {} });
+			sub.connection_id := -1;
+		}
+	}
+
+	function rtp_endpoint_sub_connect(inout RTP_CODEC_PT RTP, inout RtpEndpointSub sub) {
+		var Result res;
+
+		res := f_IPL4_connect(RTP, sub.remote_name, sub.remote_port,
+					sub.local_name, sub.local_port, sub.connection_id, { udp := {} });
+		/* FIXME: Check for success (no res.errorCode) */
+
+		/* connect without previous bind: save conenction id allocated by IPL4asp */
+		if (sub.connection_id == -1) {
+			sub.connection_id := res.connId;
+		}
+	}
+
+	function rtp_endpoint_close(inout RTP_CODEC_PT RTP, inout RtpEndpoint ep) {
+		rtp_endpoint_sub_close(RTP, ep.rtp);
+		rtp_endpoint_sub_close(RTP, ep.rtcp);
+	}
+
+	/* connect the RTP and RTCP */
+	function rtp_endpoint_connect(inout RTP_CODEC_PT RTP, inout RtpEndpoint ep) {
+		rtp_endpoint_sub_connect(RTP, ep.rtp);
+		rtp_endpoint_sub_connect(RTP, ep.rtcp);
+	}
+
+	function rtp_endpoint_sub_bind(inout RTP_CODEC_PT RTP, inout RtpEndpointSub sub) {
+		var Result res;
+		rtp_endpoint_sub_close(RTP, sub);
+		res := f_IPL4_listen(RTP, sub.local_name, sub.local_port, { udp := {} });
+		/* FIXME: Check for success (no res.errorCode) */
+		sub.connection_id := res.connId;
+	}
+
+	function rtp_endpoint_bind(inout RTP_CODEC_PT RTP, inout RtpEndpoint ep) {
+		rtp_endpoint_sub_bind(RTP, ep.rtp);
+		rtp_endpoint_sub_bind(RTP, ep.rtcp);
+	}
+
+	/* send user-specified data through given endpoint, incrementing seq_no and timestamp */
+	function rtp_endpoint_send(inout RTP_CODEC_PT RTP, inout RtpEndpoint ep,
+				   octetstring data := '00'O) {
+		var RTP_messages_union rtp;
+		/* generate RTP packet as abstract TTCN-3 type */
+		rtp := valueof(ts_RTP('0'B, ep.payload_type, ep.next_seq_no, ep.next_ts, ep.ssrc, data));
+		/* increment for next packet */
+		ep.next_seq_no := ep.next_seq_no + 1;
+		ep.next_ts := ep.next_ts + ep.samples_per_pkt;
+		/* encode and send */
+		RTP.send(t_RTP_Send(ep.rtp.connection_id, rtp));
+	}
+}
diff --git a/mgw/gen_links.sh b/mgw/gen_links.sh
index 37c42a0..1bc2abf 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"
+FILES="General_Types.ttcn Osmocom_Types.ttcn"
 gen_links $DIR $FILES