Harald Welte | f07c286 | 2017-11-18 17:16:24 +0100 | [diff] [blame] | 1 | module RTP_Endpoint { |
| 2 | |
| 3 | import from General_Types all; |
| 4 | import from Osmocom_Types all; |
| 5 | import from IPL4asp_Types all; |
| 6 | import from RTP_Types all; |
| 7 | import from RTP_CodecPort all; |
| 8 | import from RTP_CodecPort_CtrlFunct all; |
| 9 | |
| 10 | /* state for one of the two UDP sockets in and endpoint */ |
| 11 | type record RtpEndpointSub { |
| 12 | ConnectionId connection_id, |
| 13 | HostName local_name, |
| 14 | PortNumber local_port, |
| 15 | HostName remote_name, |
| 16 | PortNumber remote_port |
| 17 | } |
| 18 | /* state for one RTP+RTCP endpoint */ |
| 19 | type record RtpEndpoint { |
| 20 | /* static configuration */ |
| 21 | INT7b payload_type, |
| 22 | integer sample_rate, /* e.g. 8000 */ |
| 23 | integer samples_per_pkt, /* e.g. 160 */ |
| 24 | BIT32_BO_LAST ssrc, |
| 25 | |
| 26 | /* dynamic state */ |
| 27 | uint32_t next_ts, |
| 28 | LIN2_BO_LAST next_seq_no, |
| 29 | RtpEndpointSub rtp, |
| 30 | RtpEndpointSub rtcp |
| 31 | } |
| 32 | |
| 33 | /* |
| 34 | type component RTP_CT { |
| 35 | port RTP_CODEC_PT RTP; |
| 36 | ConnectionId g_conn_id := 1; |
| 37 | } |
| 38 | |
| 39 | modulepar { |
| 40 | HostName rtp_local_ip := "127.0.0.1"; |
| 41 | PortNumber rtp_local_base_port := 10000; |
| 42 | } |
| 43 | */ |
| 44 | |
| 45 | template RTP_messages_union ts_RTP(BIT1 marker, INT7b pt, LIN2_BO_LAST seq, uint32_t ts, |
| 46 | BIT32_BO_LAST ssrc, octetstring data) := { |
| 47 | rtp := { |
| 48 | version := 2, |
| 49 | padding_ind := '0'B, |
| 50 | extension_ind := '0'B, |
| 51 | CSRC_count := 0, |
| 52 | marker_bit := marker, |
| 53 | payload_type := pt, |
| 54 | sequence_number := seq, |
| 55 | time_stamp := int2bit(ts, 32), |
| 56 | SSRC_id := ssrc, |
| 57 | CSRCs := omit, |
| 58 | ext_header := omit, |
| 59 | data := data |
| 60 | } |
| 61 | } |
| 62 | |
| 63 | template RTP_messages_union tr_RTP(template INT7b pt, template octetstring data, |
| 64 | template BIT32_BO_LAST ssrc := ?, |
| 65 | template LIN2_BO_LAST seq := ?, |
| 66 | template BIT32_BO_LAST ts := ?) := { |
| 67 | rtp := { |
| 68 | version := 2, |
| 69 | padding_ind := ?, |
| 70 | extension_ind := ?, |
| 71 | CSRC_count := ?, |
| 72 | marker_bit := ?, |
| 73 | payload_type := pt, |
| 74 | sequence_number := seq, |
| 75 | time_stamp := ts, |
| 76 | SSRC_id := ssrc, |
| 77 | CSRCs := *, |
| 78 | ext_header := *, |
| 79 | data := data |
| 80 | } |
| 81 | } |
| 82 | |
| 83 | function rtp_endpoint_init(inout RtpEndpoint ep, charstring local_name, PortNumber local_port, |
| 84 | uint32_t ssrc) { |
| 85 | ep.rtp.local_name := local_name; |
| 86 | ep.rtp.local_port := local_port; |
| 87 | ep.rtp.connection_id := -1; |
| 88 | ep.rtcp.local_name := local_name; |
| 89 | ep.rtcp.local_port := local_port + 1; |
| 90 | ep.rtcp.connection_id := -1; |
| 91 | ep.ssrc := int2bit(ssrc, 32); |
| 92 | |
| 93 | ep.payload_type := 99; |
| 94 | ep.sample_rate := 8000; |
| 95 | ep.samples_per_pkt := 160; |
| 96 | ep.next_ts := float2int(rnd()*4294967295.0); |
| 97 | ep.next_seq_no := float2int(rnd()*65535.0); |
| 98 | } |
| 99 | |
| 100 | function rtp_endpoint_sub_close(inout RTP_CODEC_PT RTP, inout RtpEndpointSub sub) { |
| 101 | if (sub.connection_id != -1) { |
| 102 | f_IPL4_close(RTP, sub.connection_id, { udp := {} }); |
| 103 | sub.connection_id := -1; |
| 104 | } |
| 105 | } |
| 106 | |
| 107 | function rtp_endpoint_sub_connect(inout RTP_CODEC_PT RTP, inout RtpEndpointSub sub) { |
| 108 | var Result res; |
| 109 | |
| 110 | res := f_IPL4_connect(RTP, sub.remote_name, sub.remote_port, |
| 111 | sub.local_name, sub.local_port, sub.connection_id, { udp := {} }); |
| 112 | /* FIXME: Check for success (no res.errorCode) */ |
| 113 | |
| 114 | /* connect without previous bind: save conenction id allocated by IPL4asp */ |
| 115 | if (sub.connection_id == -1) { |
| 116 | sub.connection_id := res.connId; |
| 117 | } |
| 118 | } |
| 119 | |
| 120 | function rtp_endpoint_close(inout RTP_CODEC_PT RTP, inout RtpEndpoint ep) { |
| 121 | rtp_endpoint_sub_close(RTP, ep.rtp); |
| 122 | rtp_endpoint_sub_close(RTP, ep.rtcp); |
| 123 | } |
| 124 | |
| 125 | /* connect the RTP and RTCP */ |
| 126 | function rtp_endpoint_connect(inout RTP_CODEC_PT RTP, inout RtpEndpoint ep) { |
| 127 | rtp_endpoint_sub_connect(RTP, ep.rtp); |
| 128 | rtp_endpoint_sub_connect(RTP, ep.rtcp); |
| 129 | } |
| 130 | |
| 131 | function rtp_endpoint_sub_bind(inout RTP_CODEC_PT RTP, inout RtpEndpointSub sub) { |
| 132 | var Result res; |
| 133 | rtp_endpoint_sub_close(RTP, sub); |
| 134 | res := f_IPL4_listen(RTP, sub.local_name, sub.local_port, { udp := {} }); |
| 135 | /* FIXME: Check for success (no res.errorCode) */ |
| 136 | sub.connection_id := res.connId; |
| 137 | } |
| 138 | |
| 139 | function rtp_endpoint_bind(inout RTP_CODEC_PT RTP, inout RtpEndpoint ep) { |
| 140 | rtp_endpoint_sub_bind(RTP, ep.rtp); |
| 141 | rtp_endpoint_sub_bind(RTP, ep.rtcp); |
| 142 | } |
| 143 | |
| 144 | /* send user-specified data through given endpoint, incrementing seq_no and timestamp */ |
| 145 | function rtp_endpoint_send(inout RTP_CODEC_PT RTP, inout RtpEndpoint ep, |
| 146 | octetstring data := '00'O) { |
| 147 | var RTP_messages_union rtp; |
| 148 | /* generate RTP packet as abstract TTCN-3 type */ |
| 149 | rtp := valueof(ts_RTP('0'B, ep.payload_type, ep.next_seq_no, ep.next_ts, ep.ssrc, data)); |
| 150 | /* increment for next packet */ |
| 151 | ep.next_seq_no := ep.next_seq_no + 1; |
| 152 | ep.next_ts := ep.next_ts + ep.samples_per_pkt; |
| 153 | /* encode and send */ |
| 154 | RTP.send(t_RTP_Send(ep.rtp.connection_id, rtp)); |
| 155 | } |
| 156 | } |