EMMA Coverage Report (generated Tue Dec 18 20:38:46 CET 2007)
[all classes][cz.vutbr.feec.session.rtprtcp.internal]

## COVERAGE SUMMARY FOR SOURCE FILE [RTCPInThread.java]

name | class, % | method, % | block, % | line, %
--- | --- | --- | --- | ---
RTCPInThread.java | 0% (0/1) | 0% (0/10) | 0% (0/719) | 0% (0/143)

### COVERAGE BREAKDOWN BY CLASS AND METHOD

name | class, % | method, % | block, % | line, %
--- | --- | --- | --- | ---
class RTCPInThread | 0% (0/1) | 0% (0/10) | 0% (0/719) | 0% (0/143)
<static initializer> |  | 0% (0/1) | 0% (0/12) | 0% (0/3)
RTCPInThread (SessionType, Session3550, SocketStrategy, int, String): void |  | 0% (0/1) | 0% (0/47) | 0% (0/12)
isSender (): boolean |  | 0% (0/1) | 0% (0/8) | 0% (0/1)
processAppPacket (int): int |  | 0% (0/1) | 0% (0/18) | 0% (0/4)
processByePacket (int): int |  | 0% (0/1) | 0% (0/103) | 0% (0/16)
processRR (int): int |  | 0% (0/1) | 0% (0/19) | 0% (0/4)
processRsiPacket (int): int |  | 0% (0/1) | 0% (0/33) | 0% (0/6)
processSDES (int): int |  | 0% (0/1) | 0% (0/17) | 0% (0/4)
processSR (int): int |  | 0% (0/1) | 0% (0/19) | 0% (0/4)
run (): void |  | 0% (0/1) | 0% (0/443) | 0% (0/89)

1 | package cz.vutbr.feec.session.rtprtcp.internal;
2 |
3 | import java.net.DatagramPacket;
4 |
5 | import org.apache.log4j.Logger;
6 |
7 | import cz.vutbr.feec.packets.PacketParseException;
8 | import cz.vutbr.feec.packets.rsi.RSIPacket;
9 | import cz.vutbr.feec.packets.rtcp.AppPacket;
10 | import cz.vutbr.feec.packets.rtcp.ByePacket;
11 | import cz.vutbr.feec.packets.rtcp.ReceiverReportPacket;
12 | import cz.vutbr.feec.packets.rtcp.ReportPacket;
13 | import cz.vutbr.feec.packets.rtcp.SenderReportPacket;
14 | import cz.vutbr.feec.packets.rtcp.SDESPacket;
15 | import cz.vutbr.feec.session.SessionThread;
16 |
17 | /**
18 | * This class encapsulates the functionality to receive and parse out RTCP
19 | * packets. This class provides a seperate thread to receive these RTCP Packets.
20 | * Depending on the kind of RTCP packet received (e.g. SR, RR, SDES, BYE) the
21 | * receiver parses them out correctly and updates several session and source
22 | * level statistics. Each packet having been parsed posts an event to the
23 | * application corresponding to the packet that the receiver received
24 | */
25 |
26 | public class RTCPInThread extends SessionThread {
27 |
28 | /** The logger. */
29 | private static Logger logger = Logger.getLogger(RTCPInThread.class
30 | .getName());
31 |
32 | /** The socket. */
33 | private SocketStrategy socket;
34 |
35 | /** Session to be operated with. */
36 | private Session3550 session;
37 |
38 | // /** Counts bytes of packet (not compound). */
39 | // private int offset = 0;
40 |
41 | private final int BUFFER_LENGTH = 1024;
42 | /** The packet. */
43 | private byte buffer[] = new byte[BUFFER_LENGTH];
44 |
45 | private final SessionType type;
46 |
47 | /**
48 | * Constructor for sender session.
49 | *
50 | * @param rtpSession
51 | * the rtp session
52 | * @param rtcpPort
53 | * the rtcp port
54 | * @param sock
55 | * the sock
56 | */
57 | public RTCPInThread(SessionType type, Session3550 rtpSession,
58 | SocketStrategy sock, int rtcpPort, String name) {
59 | this.session = rtpSession;
60 | this.type = type;
61 | if (sock.isMulticastSocket()) {
62 | logger.debug("CREATING RTCP-IN THREAD (RECEIVER)");
63 | setName("RTCP-in(R)" + name);
64 | } else {
65 | logger.debug("CREATING RTCP-IN THREAD (SENDER)");
66 | setName("RTCP-in(S)" + name);
67 | }
68 | this.socket = sock;
69 | }
70 |
71 | /**
72 | * Checks if is sender.
73 | *
74 | * @return true, if is sender
75 | */
76 | private boolean isSender() {
77 | return !socket.isMulticastSocket();
78 | }
79 |
80 | /**
81 | * Starts the RTCP Receiver Thread. The thread creates a new multicast
82 | * socket according to the Multicast address and port provided in the
83 | * constructor. Then the thread waits in idle state for the reception of a
84 | * RTCP Packet. As soon as a RTCP Packet is received, the receiver first
85 | * validates the RTCP Packet accoring to the following rules RTCP Header
86 | * Validity Checks 1) Version should always =2 2) The payload type field of
87 | * the first RTCP Packet should be SR or RR 3) The Padding Bit (P) should be
88 | * zero for the first packet 4) The length fields of individual RTCP Packets
89 | * must total to the overall length of the compound RTCP Packet
90 | *
91 | * After the packet has been validated, it is parsed differently according
92 | * to the type of packet (e.g. Sender Report, Receive Report, BYE, SDES)
93 | * etc. For each packet parsed, session and source level statistics are
94 | * updated and an event is posted for the application corresponding to the
95 | * type of packet that was parsed.
96 | */
97 | public void run() {
98 | // byte[] mirrorPacket = new byte[72];
99 | // #################################################################
100 |
101 | DatagramPacket header;
102 | header = new DatagramPacket(buffer, buffer.length);
103 |
104 | int offset = 0;
105 | // #################################################################
106 | // LISTEN FOR PACKETS
107 | while (!isStopped()) {
108 | int recvLen;
109 | recvLen = socket.receiveFrom(header);
110 |
111 | // every 500 miliseconds will be thrown this excpetion
112 | // to checked if thread has not been stoped
113 | if (recvLen == -1) {
114 | // So timeout expired
115 | continue;
116 | }
117 | logger.info("RTCP packet received. MC:"
118 | + socket.isMulticastSocket() + " PORT:"
119 | + socket.getBindedPort());
120 | /*******************************************************************
121 | * RTCP Header Validity Checks 1) Version should always =2 2) The
122 | * payload type field of the first RTCP Packet should be SR or RR 3)
123 | * The Padding Bit (P) should be zero for the first packet 4) The
124 | * length fields of individual RTCP Packets must total to the
125 | * overall length of the compound RTCP Packet
126 | ******************************************************************/
127 |
128 | // RTCP Header Validity Check 2
129 | int payLoadType = (int) (buffer[1] & 0xff);
130 | if ((payLoadType != RTCPConstants.RTCP_SR)
131 | & (payLoadType != RTCPConstants.RTCP_RR)) {
132 | // RTCP Header Validity Check 3
133 | if ((((buffer[0] & 0xff) >> 5) & 0x01) != 0) {
134 | logger.warn("RTCP Header Check Fail :"
135 | + " First Padding bit not zero\n");
136 | }
137 | }
138 |
139 | // Since a RTCP Packet may contain many types of RTCP Packets
140 | // Keep parsing the packets until the no. of bytes parsed =
141 | // total no of bytes read
142 | int totalBytesRead = 0;
143 | offset = 0;
144 |
145 | // read SSRC from first SSRC or CSRC packet
146 | long SSRC = ((buffer[4] & 0xff) << 24) | ((buffer[5] & 0xff) << 16)
147 | | ((buffer[6] & 0xff) << 8) | (buffer[7] & 0xff);
148 |
149 | if (SSRC == session.getSSRC()) {
150 | // own packet - so skip its processing
151 | continue;
152 | }
153 |
154 | int i = -1;
155 | boolean errorEccured = false;
156 | while (totalBytesRead < recvLen && !errorEccured) {
157 | // RTCP Header Validity Check 1
158 | i++;
159 | byte version = (byte) ((buffer[offset] & 0xff) >> 6);
160 | int pt = ((buffer[offset + 1] & 0xff));
161 | if (version != 0x02) {
162 | logger.warn("RTCP Header Check Fail :" + " version:"
163 | + version + " pt:" + pt + " SSRC:" + SSRC + " MC:"
164 | + socket.isMulticastSocket() + " binded:"
165 | + socket.getBindedPort() + "." + "i:" + i);
166 | break;
167 |
168 | }
169 |
170 | // Check the length of this particular packet
171 | // int length = (short) ((packet[bytesRead + 2] << 8) |
172 | // (packet[bytesRead + 3] & 0xff));
173 |
174 | // Check the Payload type of this packet
175 | if (pt < 200) {
176 | logger.warn("RTCP Header Check Fail :" + " Wrong PT :" + pt
177 | + " SSRC:" + SSRC + " MC:"
178 | + socket.isMulticastSocket() + " binded:"
179 | + socket.getBindedPort() + ".");
180 | break;
181 | }
182 |
183 | try {
184 | if (pt == RTCPConstants.RTCP_SR) {
185 | logger.debug("Sender Report (part:" + i
186 | + " of compound packet)");
187 | offset += processSR(offset);
188 | } else if (pt == RTCPConstants.RTCP_RR) {
189 | logger.debug("Receiver Report (part:" + i
190 | + " of compound packet)");
191 | offset += processRR(offset);
192 | } else if (pt == RTCPConstants.RTCP_SDES) {
193 | logger
194 | .debug("SDES (part:" + i
195 | + " of compound packet)");
196 | offset += processSDES(offset);
197 | } else if (pt == RTCPConstants.RTCP_BYE) {
198 | logger.debug("BYE (part:" + i + " of compound packet)");
199 | offset += processByePacket(offset);
200 | } else if (pt == RTCPConstants.RTCP_APP) {
201 | logger.debug("APP (part:" + i + " of compound packet)");
202 | offset += processAppPacket(offset);
203 | } else if (pt == RTCPConstants.RTCP_RSI) {
204 | logger.debug("RSI (part:" + i + " of compound packet)");
205 | offset += processRsiPacket(offset);
206 | } else {
207 | logger.warn("Unknown packet received.");
208 | break;
209 | }
210 | } catch (PacketParseException e) {
211 | logger.warn("Parsing of packet failed:" + e);
212 | if (logger.isDebugEnabled()) {
213 | e.printStackTrace();
214 | }
215 | errorEccured = true;
216 | }
217 |
218 | // length reperesents 32-bit blocks + 32-bit header
219 | // length needs to be computed in octets RFC 3550, ch 6.3
220 |
221 | totalBytesRead = offset;
222 | }
223 |
224 | // Update avg RTCP size
225 | logger.debug(" ## R ## " + totalBytesRead);
226 | session.updateAvgPktLength(totalBytesRead);
227 |
228 | // RTCP Header Validity Check 4
229 | if (totalBytesRead < recvLen) {
230 | // not yet whole compound packet processed
231 |
232 | logger
233 | .info("TotalBytesRead: "
234 | + totalBytesRead
235 | + " Header.getLength"
236 | + recvLen
237 | + "(2) RTCP Header Check Fail : "
238 | + "Bytes Read do not Match Total Packet Length TotalRead:"
239 | + totalBytesRead + " Header:"
240 | + header.getLength() + "\n");
241 | continue;
242 | } else {
243 | // mirror the received RTCP compound packet to the multicast
244 | // group
245 | if (totalBytesRead == recvLen) {
246 | if (isSender()) {
247 | session.mirrorPacketToMcastGroup(buffer, recvLen);
248 | logger.debug("Mirroring -> multicast, port:"
249 | + session.getMirrorPacketDestPort());
250 | }
251 | } else {
252 | logger.warn("Received packet length does not match.");
253 | break;
254 | }
255 | }
256 | }
257 | }
258 |
259 | /**
260 | * Process SDES.
261 | *
262 | * @throws PacketParseException
263 | */
264 | private int processSDES(int offset) throws PacketParseException {
265 | SDESPacket sdes = new SDESPacket();
266 | int len = sdes.parse(buffer, offset, BUFFER_LENGTH);
267 |
268 | session.onSDESReceive(sdes);
269 |
270 | return len;
271 | }
272 |
273 | /**
274 | * Process bye packet.
275 | *
276 | * @throws PacketParseException
277 | */
278 | private int processByePacket(int offset) throws PacketParseException {
279 | ByePacket bye = new ByePacket();
280 | int len = bye.parse(buffer, offset, BUFFER_LENGTH);
281 | session.onBYEReceive(bye);
282 |
283 | final int max = bye.getSSRCCount();
284 |
285 | // for every SSRC/CSRC received
286 | for (int i = 0; i < max; i++) {
287 | // remove member from all lists
288 | Source src = session.getMemberOrInvalid(bye.getSSRC(i));
289 | assert src != null : "BYE odhlasuje clena ktery neni v session obsazen";
290 | session.removeMember(src.ssrc);
291 |
292 | // TODO: se odesila ByePacket a prichazi Bye od jinych, musi pribyvat members !!!
293 |
294 | // according rfc 3550, ch 6.3.4
295 | session.tn = session.tc
296 | + ((double) session.members / (double) session.pmembers)
297 | * (session.tn - session.tc);
298 | session.tp = session.tc
299 | - ((double) session.members / (double) session.pmembers)
300 | * (session.tc - session.tp);
301 | session.pmembers = session.members;
302 | }
303 | return len;
304 | }
305 |
306 | /**
307 | * Process app packet.
308 | * @throws PacketParseException
309 | */
310 | private int processAppPacket(int offset) throws PacketParseException {
311 | AppPacket pkt = new AppPacket();
312 | int len = pkt.parse(buffer, offset, buffer.length);
313 |
314 | logger.warn("Warning parsing Application packet is not supported.");
315 |
316 | return len;
317 | }
318 |
319 | /**
320 | * Process app packet.
321 | */
322 | private int processRsiPacket(int offset) {
323 | assert !type.equals(SessionType.RECEIVER) : "Receiver nesmi prijimat RSI pakety";
324 |
325 | RSIPacket rsi = new RSIPacket();
326 | try {
327 | offset += rsi.parse(buffer, 0, offset);
328 | session.onRSIReceive(rsi);
329 | } catch (PacketParseException e) {
330 | // it is ok
331 | }
332 | return offset;
333 | }
334 |
335 | /**
336 | * Process SR.
337 | *
338 | * @throws PacketParseException
339 | */
340 | private int processSR(int offset) throws PacketParseException {
341 | SenderReportPacket sr = new SenderReportPacket();
342 | offset += sr.parse(buffer, offset, BUFFER_LENGTH);
343 |
344 | session.onSRReceive(sr);
345 |
346 | if (ConfigDebug.RTCP_RECEIVER_SR) {
347 | System.out.println("### R ###" + sr);
348 | }
349 | return offset;
350 | }
351 |
352 | /**
353 | * Process RR.
354 | *
355 | * @throws PacketParseException
356 | */
357 | private int processRR(int offset) throws PacketParseException {
358 | ReportPacket rr = new ReceiverReportPacket();
359 | offset += rr.parse(buffer, offset, BUFFER_LENGTH);
360 |
361 | session.onRRReceive(rr);
362 |
363 | if (ConfigDebug.RTCP_RECEIVER_SR) {
364 | System.out.println("### R ###" + rr);
365 | }
366 | return offset;
367 | }
368 | }

[all classes][cz.vutbr.feec.session.rtprtcp.internal]
EMMA 2.0.5312 EclEmma Fix 1 (C) Vladimir Roubtsov