mgw: Add sockets for RTP packets + code for bind/connect/send RTP
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));
+	}
+}