All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jitsi.impl.neomedia.rtcp.NACKPacket Maven / Gradle / Ivy

/*
 * Copyright @ 2015 Atlassian Pty Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.jitsi.impl.neomedia.rtcp;

import java.util.*;
import net.sf.fmj.media.rtp.*;
import org.jitsi.service.neomedia.*;
import org.jitsi.util.*;
import org.jitsi.utils.*;

/**
 * A class which represents an RTCP Generic NACK feedback message, as defined
 * in RFC4585 Section 6.2.1.
 *
 * The RTCP packet structure is:
 *
 * 
{@code
 * 0                   1                   2                   3
 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |V=2|P| FMT=1   |   PT=205      |             length            |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |                  SSRC of packet sender                        |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |                  SSRC of media source                         |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |                           FCI                                 |
 * |                          [...]                                |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *
 * The Feedback Control Information (FCI) field consists of one or more
 * 32-bit words, each with the following structure:
 *
 * 0                   1                   2                   3
 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |             PID               |             BLP               |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * }
* * @author Boris Grozev * @author George Politis */ public class NACKPacket extends RTCPFBPacket { /** * Gets a boolean indicating whether or not the RTCP packet specified in the * {@link ByteArrayBuffer} that is passed as an argument is a NACK packet or * not. * * @param baf the {@link ByteArrayBuffer} * @return true if the byte array buffer holds a NACK packet, otherwise * false. */ public static boolean isNACKPacket(ByteArrayBuffer baf) { int rc = RTCPUtils.getReportCount(baf); return rc == FMT && isRTPFBPacket(baf); } /** * @return the set of sequence numbers reported lost in a NACK packet * represented by a {@link ByteArrayBuffer}. * @param baf the NACK packet. */ public static Collection getLostPackets(ByteArrayBuffer baf) { return getLostPacketsFci(getFCI(baf)); } /** * @return the set of sequence numbers reported lost in the FCI field of a * NACK packet represented by a {@link ByteArrayBuffer}. * @param fciBuffer the {@link ByteArrayBuffer} which represents the FCI * field of a NACK packet. */ public static Collection getLostPacketsFci(ByteArrayBuffer fciBuffer) { Collection lostPackets = new LinkedList<>(); if (fciBuffer == null) { return lostPackets; } byte[] fci = fciBuffer.getBuffer(); int off = fciBuffer.getOffset(), len = fciBuffer.getLength(); for (int i = 0; i < (len / 4); i++) { int pid = (0xFF & fci[off + i * 4 + 0]) << 8 | (0xFF & fci[off + i * 4 + 1]); lostPackets.add(pid); // First byte of the BLP for (int j = 0; j < 8; j++) { if (0 != (fci[off + i * 4 + 2] & (1 << j))) { lostPackets.add((pid + 1 + 8 + j) % (1 << 16)); } } // Second byte of the BLP for (int j = 0; j < 8; j++) { if (0 != (fci[off + i * 4 + 3] & (1 << j))) { lostPackets.add((pid + 1 + j) % (1 << 16)); } } } return lostPackets; } /** * The value of the "fmt" field for a NACK packet. */ public static final int FMT = 1; /** * The set of sequence numbers described by this packet. */ private Collection lostPackets = null; /** * Initializes a new NACKPacket instance. * @param base */ public NACKPacket(RTCPCompoundPacket base) { super(base); } /** * Initializes a new NACKPacket instance with specific "packet * sender SSRC" and "media source SSRC" values and which describes a * specific set of sequence numbers. * @param senderSSRC the value to use for the "packet sender SSRC" field. * @param sourceSSRC the value to use for the "media source SSRC" field. * @param lostPackets the set of RTP sequence numbers which this NACK * packet is to describe. * * Note that this implementation is not optimized and might not always use * the minimal possible number of bytes to describe a given set of packets. * Specifically, it does not take into account that sequence numbers wrap * at 2^16 and fails to pack numbers close to 2^16 with those close to 0. */ public NACKPacket(long senderSSRC, long sourceSSRC, Collection lostPackets) { super(FMT, RTPFB, senderSSRC, sourceSSRC); List sorted = new LinkedList<>(lostPackets); Collections.sort(sorted); List nackList = new LinkedList<>(); int currentPid = -1; byte[] currentNack = null; for (int seq : sorted) { if (currentPid == -1 || currentPid + 16 <= seq) { currentPid = seq; currentNack = new byte[4]; currentNack[0] = (byte) ((seq & 0xff00) >> 8); currentNack[1] = (byte) (seq & 0x00ff); currentNack[2] = 0; currentNack[3] = 0; nackList.add(currentNack); continue; } // Add seq to the current fci int diff = seq - currentPid; if (diff <= 8) { currentNack[3] |= (byte) (1 << (diff - 1)); } else { currentNack[2] |= (byte) (1 << (diff - 8 - 1)); } } // Set the fci field, which is used when assembling fci = new byte[nackList.size() * 4]; for (int i = 0; i < nackList.size(); i++) { System.arraycopy(nackList.get(i), 0, fci, i * 4, 4); } this.lostPackets = sorted; } /** * @return the set of sequence numbers reported lost in this NACK packet. */ synchronized public Collection getLostPackets() { if (lostPackets == null) { // parse this.fci as containing NACK entries and initialize // this.lostPackets lostPackets = getLostPacketsFci(new RawPacket(fci, 0, fci.length)); } return lostPackets; } @Override public String toString() { return "RTCP NACK packet; packet sender: " + senderSSRC + "; media sources: " + sourceSSRC + "; NACK entries: " + (fci == null ? "none" : (fci.length / 4)) + "; lost packets: " + (lostPackets == null ? "none" : Arrays.toString(lostPackets.toArray())); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy