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

org.jitsi.service.neomedia.rtp.RTCPExtendedReport Maven / Gradle / Ivy

Go to download

libjitsi is an advanced Java media library for secure real-time audio/video communication

The newest version!
/*
 * 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.service.neomedia.rtp;

import java.io.*;
import java.util.*;

import net.sf.fmj.media.rtp.*;

/**
 * Represents an RTP Control Protocol Extended Report (RTCP XR) packet in the
 * terms of FMJ i.e. as an RTCPPacket sub-class.
 *
 * @author Lyubomir Marinov
 */
public class RTCPExtendedReport
    extends RTCPPacket
{
    /**
     * Represents an abstract, base extended report block.
     *
     * @author Lyubomir Marinov
     */
    public static abstract class ReportBlock
    {
        /**
         * The block type/format of this report block.
         */
        public final short blockType;

        /**
         * Initializes a new ReportBlock instance of a specific block
         * type.
         *
         * @param blockType the block type/format of the new instance
         */
        protected ReportBlock(short blockType)
        {
            this.blockType = blockType;
        }

        /**
         * Serializes/writes the binary representation of this
         * ReportBlock into a specific DataOutputStream.
         *
         * @param dataoutputstream the DataOutputStream into which the
         * binary representation of this ReportBlock is to be
         * serialized/written.
         * @throws IOException if an input/output error occurs during the
         * serialization/writing of the binary representation of this
         * ReportBlock
         */
        protected abstract void assemble(DataOutputStream dataoutputstream)
            throws IOException;

        /**
         * Computes the length in bytes of this ReportBlock,
         * including the header and any padding.
         * 

* The implementation of ReportBlock returns the length in * bytes of the header of an extended report block i.e. * 4. The implementation is provided as a convenience because * RFC 3611 defines that the type-specific block contents of an extended * report block may be zero bits long if the block type definition * permits. * * @return the length in bytes of this ReportBlock, * including the header and any padding. */ public int calcLength() { return 1 /* block type (BT) */ + 1 /* type-specific */ + 2 /* block length */; } } /** * Implements "VoIP Metrics Report Block" i.e. an extended report * block which provides metrics for monitoring voice over IP (VoIP) calls. * * @author Lyubomir Marinov */ public static class VoIPMetricsReportBlock extends ReportBlock { /** * The jitter buffer size is being dynamically adjusted to deal with * varying levels of jitter. */ public static final byte ADAPTIVE_JITTER_BUFFER_ADAPTIVE = 3; /** * Silence is being inserted in place of lost packets. */ public static final byte DISABLED_PACKET_LOSS_CONCEALMENT = 1; /** * An enhanced interpolation algorithm is being used; algorithms of this * type are able to conceal high packet loss rates effectively. */ public static final byte ENHANCED_PACKET_LOSS_CONCEALMENT = 2; /** * The jitter buffer size is maintained at a fixed level. */ public static final byte NON_ADAPTIVE_JITTER_BUFFER_ADAPTIVE = 2; public static final byte RESERVED_JITTER_BUFFER_ADAPTIVE = 1; public static final String SDP_PARAMETER = "voip-metrics"; /** * A simple replay or interpolation algorithm is being used to fill-in * the missing packet; this approach is typically able to conceal * isolated lost packets at low packet loss rates. */ public static final byte STANDARD_PACKET_LOSS_CONCEALMENT = 3; public static final byte UNKNOWN_JITTER_BUFFER_ADAPTIVE = 0; /** * No information is available concerning the use of packet loss * concealment (PLC); however, for some codecs this may be inferred. */ public static final byte UNSPECIFIED_PACKET_LOSS_CONCEALMENT = 0; public static final short VOIP_METRICS_REPORT_BLOCK_TYPE = 7; /** * The fraction of RTP data packets within burst periods since the * beginning of reception that were either lost or discarded. The value * is expressed as a fixed point number with the binary point at the * left edge of the field. It is calculated by dividing the total number * of packets lost or discarded (excluding duplicate packet discards) * within burst periods by the total number of packets expected within * the burst periods, multiplying the result of the division by 256, * limiting the maximum value to 255 (to avoid overflow), and taking the * integer part. The field MUST be populated and MUST be set to zero if * no packets have been received. */ private short burstDensity = 0; private int burstDuration = 0; /** * The fraction of RTP data packets from the source that have been * discarded since the beginning of reception, due to late or early * arrival, under-run or overflow at the receiving jitter buffer. The * value is expressed as a fixed point number with the binary point at * the left edge of the field. It is calculated by dividing the total * number of packets discarded (excluding duplicate packet discards) by * the total number of packets expected, multiplying the result of the * division by 256, limiting the maximum value to 255 (to avoid * overflow), and taking the integer part. */ private short discardRate = 0; private int endSystemDelay = 0; private byte extRFactor = 127; /** * The fraction of RTP data packets within inter-burst gaps since the * beginning of reception that were either lost or discarded. The value * is expressed as a fixed point number with the binary point at the * left edge of the field. It is calculated by dividing the total number * of packets lost or discarded (excluding duplicate packet discards) * within gap periods by the total number of packets expected within the * gap periods, multiplying the result of the division by 256, limiting * the maximum value to 255 (to avoid overflow), and taking the integer * part. The field MUST be populated and MUST be set to zero if no * packets have been received. */ private short gapDensity = 0; private int gapDuration = 0; private short gMin = 16; private int jitterBufferAbsoluteMaximumDelay; /** * Whether the jitter buffer is adaptive. The value is one of the * constants {@link #ADAPTIVE_JITTER_BUFFER_ADAPTIVE}, * {@link #NON_ADAPTIVE_JITTER_BUFFER_ADAPTIVE}, * {@link #RESERVED_JITTER_BUFFER_ADAPTIVE}, and * {@link #UNKNOWN_JITTER_BUFFER_ADAPTIVE}. */ private byte jitterBufferAdaptive = UNKNOWN_JITTER_BUFFER_ADAPTIVE; private int jitterBufferMaximumDelay; private int jitterBufferNominalDelay; /** * The implementation specific adjustment rate of a jitter buffer in * adaptive mode. Defined in terms of the approximate time taken to * fully adjust to a step change in peak to peak jitter from 30 ms to * 100 ms such that: adjustment time = 2 * J * frame size (ms) * where J = adjustment rate (0-15). The parameter is intended * only to provide a guide to the degree of "aggressiveness" * of an adaptive jitter buffer and may be estimated. A value of * 0 indicates that the adjustment time is unknown for this * implementation. */ private byte jitterBufferRate = 0; /** * The fraction of RTP data packets from the source lost since the * beginning of reception, expressed as a fixed point number with the * binary point at the left edge of the field. This value is calculated * by dividing the total number of packets lost (after the effects of * applying any error protection such as FEC) by the total number of * packets expected, multiplying the result of the division by 256, * limiting the maximum value to 255 (to avoid overflow), and taking the * integer part. The numbers of duplicated packets and discarded packets * do not enter into this calculation. Since receivers cannot be * required to maintain unlimited buffers, a receiver MAY categorize * late-arriving packets as lost. The degree of lateness that triggers a * loss SHOULD be significantly greater than that which triggers a * discard. */ private short lossRate = 0; private byte mosCq = 127; private byte mosLq = 127; private byte noiseLevel = 127; /** * The type of packet loss concealment (PLC). The value is one of the * constants {@link #STANDARD_PACKET_LOSS_CONCEALMENT}, * {@link #ENHANCED_PACKET_LOSS_CONCEALMENT}, * {@link #DISABLED_PACKET_LOSS_CONCEALMENT}, and * {@link #UNSPECIFIED_PACKET_LOSS_CONCEALMENT}. */ private byte packetLossConcealment = UNSPECIFIED_PACKET_LOSS_CONCEALMENT; private byte residualEchoReturnLoss = 127; private byte rFactor = 127; private int roundTripDelay = 0; private byte signalLevel = 127; /** * The synchronization source identifier (SSRC) of the RTP data packet * source being reported upon by this report block. */ private int sourceSSRC; /** * Initializes a new VoIPMetricsReportBlock instance. */ public VoIPMetricsReportBlock() { super(VOIP_METRICS_REPORT_BLOCK_TYPE); } /** * Initializes a new VoIPMetricsReportBlock instance by * deserializing/reading a binary representation from a * DataInputStream. * * @param blockLength the length of the extended report block to read, * not including the header, in bytes. * @param datainputstream the binary representation from which the new * instance is to be initialized. The datainputstream is asumed * to contain type-specific block contents without extended report block * header i.e. no block type (BT), type-specific, and block length * fields will be read from datainputstream. * @throws IOException if an input/output error occurs while * deserializing/reading the new instance from datainputstream * or the binary representation does not parse into an * VoIPMetricsReportBlock instance */ public VoIPMetricsReportBlock( int blockLength, DataInputStream datainputstream) throws IOException { this(); // block length (RFC 3611, Section 4.7) if (blockLength != 8 * 4) { throw new IOException( "Invalid RTCP XR VoIP Metrics block length."); } // SSRC of source setSourceSSRC(datainputstream.readInt()); // lost rate setLossRate((short) datainputstream.readUnsignedByte()); // discard rate setDiscardRate((short) datainputstream.readUnsignedByte()); // burst density setBurstDensity((short) datainputstream.readUnsignedByte()); // gap density setGapDensity((short) datainputstream.readUnsignedByte()); // burst duration setBurstDuration(datainputstream.readUnsignedShort()); // gap duration setGapDuration(datainputstream.readUnsignedShort()); // round trip delay setRoundTripDelay(datainputstream.readUnsignedShort()); // end system delay setEndSystemDelay(datainputstream.readUnsignedShort()); // signal level setSignalLevel(datainputstream.readByte()); // noise level setNoiseLevel(datainputstream.readByte()); // residual echo return loss (RERL) setResidualEchoReturnLoss(datainputstream.readByte()); // Gmin setGMin((short) datainputstream.readUnsignedByte()); // R factor setRFactor(datainputstream.readByte()); // ext. R factor setExtRFactor(datainputstream.readByte()); // MOS-LQ setMosLq(datainputstream.readByte()); // MOS-CQ setMosCq(datainputstream.readByte()); // receiver configuration byte (RX config) int rxConfig = datainputstream.readUnsignedByte(); setPacketLossConcealment((byte) ((rxConfig & 0xC0) >>> 6)); setJitterBufferAdaptive((byte) ((rxConfig & 0x30) >>> 4)); setJitterBufferRate((byte) (rxConfig & 0x0F)); // reserved datainputstream.readByte(); // jitter buffer nominal delay (JB nominal) setJitterBufferNominalDelay(datainputstream.readUnsignedShort()); // jitter buffer maximum delay (JB maximum) setJitterBufferMaximumDelay(datainputstream.readUnsignedShort()); // jitter buffer absolute maximum delay (JB abs max) setJitterBufferAbsoluteMaximumDelay( datainputstream.readUnsignedShort()); } /** * {@inheritDoc} */ @Override protected void assemble(DataOutputStream dataoutputstream) throws IOException { // BT=7 dataoutputstream.writeByte(VOIP_METRICS_REPORT_BLOCK_TYPE); // reserved dataoutputstream.writeByte(0); // block length = 8 dataoutputstream.writeShort(8); // SSRC of source dataoutputstream.writeInt(getSourceSSRC()); // loss rate dataoutputstream.writeByte(getLossRate()); // discard rate dataoutputstream.writeByte(getDiscardRate()); // burst density dataoutputstream.writeByte(getBurstDensity()); // gap density dataoutputstream.writeByte(getGapDensity()); // burst duration dataoutputstream.writeShort(getBurstDuration()); // gap duration dataoutputstream.writeShort(getGapDuration()); // round trip delay dataoutputstream.writeShort(getRoundTripDelay()); // end system delay dataoutputstream.writeShort(getEndSystemDelay()); // signal level dataoutputstream.writeByte(getSignalLevel()); // noise level dataoutputstream.writeByte(getNoiseLevel()); // residual echo return loss (RERL) dataoutputstream.writeByte(getResidualEchoReturnLoss()); // Gmin dataoutputstream.writeByte(getGMin()); // R factor dataoutputstream.writeByte(getRFactor()); // ext. R factor dataoutputstream.writeByte(getExtRFactor()); // MOS-LQ dataoutputstream.writeByte(getMosLq()); // MOS-CQ dataoutputstream.writeByte(getMosCq()); // receiver configuration byte (RX config) dataoutputstream.writeByte( ((getPacketLossConcealment() & 0x03) << 6) | ((getJitterBufferAdaptive() & 0x03) << 4) | (getJitterBufferRate() & 0x0F)); // reserved dataoutputstream.writeByte(0); // jitter buffer nominal delay (JB nominal) dataoutputstream.writeShort(getJitterBufferNominalDelay()); // jitter buffer maximum delay (JB maximum) dataoutputstream.writeShort(getJitterBufferMaximumDelay()); // jitter buffer absolute maximum delay (JB abs max) dataoutputstream.writeShort(getJitterBufferAbsoluteMaximumDelay()); } /** * {@inheritDoc} * * As defined by RFC 3611, a VoIP Metrics Report Block has a length in * bytes equal to 36, including the extended report * block header. */ @Override public int calcLength() { return (8 /* block length */ + 1) * 4; } /** * Gets the fraction of RTP data packets within burst periods since the * beginning of reception that were either lost or discarded. * * @return the fraction of RTP data packets within burst periods since * the beginning of reception that were either lost or discarded */ public short getBurstDensity() { return burstDensity; } public int getBurstDuration() { return burstDuration; } /** * Gets the fraction of RTP data packets from the source that have been * discarded since the beginning of reception, due to late or early * arrival, under-run or overflow at the receiving jitter buffer. * * @return the fraction of RTP data packets from the source that have * been discarded since the beginning of reception, due to late or early * arrival, under-run or overflow at the receiving jitter buffer * @see #discardRate */ public short getDiscardRate() { return discardRate; } public int getEndSystemDelay() { return endSystemDelay; } public byte getExtRFactor() { return extRFactor; } /** * Get the fraction of RTP data packets within inter-burst gaps since * the beginning of reception that were either lost or discarded. * * @return the fraction of RTP data packets within inter-burst gaps * since the beginning of reception that were either lost or discarded */ public short getGapDensity() { return gapDensity; } public int getGapDuration() { return gapDuration; } public short getGMin() { return gMin; } public int getJitterBufferAbsoluteMaximumDelay() { return jitterBufferAbsoluteMaximumDelay; } /** * Gets whether the jitter buffer is adaptive. * * @return {@link #ADAPTIVE_JITTER_BUFFER_ADAPTIVE}, * {@link #NON_ADAPTIVE_JITTER_BUFFER_ADAPTIVE}, * {@link #RESERVED_JITTER_BUFFER_ADAPTIVE}, or * {@link #UNKNOWN_JITTER_BUFFER_ADAPTIVE} */ public byte getJitterBufferAdaptive() { return jitterBufferAdaptive; } public int getJitterBufferMaximumDelay() { return jitterBufferMaximumDelay; } public int getJitterBufferNominalDelay() { return jitterBufferNominalDelay; } /** * Gets the implementation specific adjustment rate of a jitter buffer * in adaptive mode. * * @return the implementation specific adjustment rate of a jitter * buffer in adaptive mode */ public byte getJitterBufferRate() { return jitterBufferRate; } /** * Gets the fraction of RTP data packets from the source lost since the * beginning of reception. * * @return the fraction of RTP data packets from the source lost since * the beginning of reception * @see #lossRate */ public short getLossRate() { return lossRate; } public byte getMosCq() { return mosCq; } public byte getMosLq() { return mosLq; } public byte getNoiseLevel() { return noiseLevel; } /** * Gets the type of packet loss concealment (PLC). * * @return {@link #STANDARD_PACKET_LOSS_CONCEALMENT}, * {@link #ENHANCED_PACKET_LOSS_CONCEALMENT}, * {@link #DISABLED_PACKET_LOSS_CONCEALMENT}, or * {@link #UNSPECIFIED_PACKET_LOSS_CONCEALMENT} */ public byte getPacketLossConcealment() { return packetLossConcealment; } public byte getResidualEchoReturnLoss() { return residualEchoReturnLoss; } public byte getRFactor() { return rFactor; } public int getRoundTripDelay() { return roundTripDelay; } public byte getSignalLevel() { return signalLevel; } /** * Gets the synchronization source identifier (SSRC) of the RTP data * packet source being reported upon by this report block. * * @return the synchronization source identifier (SSRC) of the RTP data * packet source being reported upon by this report block */ public int getSourceSSRC() { return sourceSSRC; } /** * Sets the fraction of RTP data packets within burst periods since the * beginning of reception that were either lost or discarded. * * @param burstDensity the fraction of RTP data packets within burst * periods since the beginning of reception that were either lost or * discarded */ public void setBurstDensity(short burstDensity) { this.burstDensity = burstDensity; } public void setBurstDuration(int burstDuration) { this.burstDuration = burstDuration; } /** * Sets the fraction of RTP data packets from the source that have been * discarded since the beginning of reception, due to late or early * arrival, under-run or overflow at the receiving jitter buffer. * * @param discardRate the fraction of RTP data packets from the source * that have been discarded since the beginning of reception, due to * late or early arrival, under-run or overflow at the receiving jitter * buffer * @see #discardRate */ public void setDiscardRate(short discardRate) { this.discardRate = discardRate; } public void setEndSystemDelay(int endSystemDelay) { this.endSystemDelay = endSystemDelay; } public void setExtRFactor(byte extRFactor) { this.extRFactor = extRFactor; } /** * Sets the fraction of RTP data packets within inter-burst gaps since * the beginning of reception that were either lost or discarded. * * @param gapDensity the fraction of RTP data packets within inter-burst * gaps since the beginning of reception that were either lost or * discarded */ public void setGapDensity(short gapDensity) { this.gapDensity = gapDensity; } public void setGapDuration(int gapDuration) { this.gapDuration = gapDuration; } public void setGMin(short gMin) { this.gMin = gMin; } public void setJitterBufferAbsoluteMaximumDelay( int jitterBufferAbsoluteMaximumDelay) { this.jitterBufferAbsoluteMaximumDelay = jitterBufferAbsoluteMaximumDelay; } /** * Sets whether the jitter buffer is adaptive. * * @param jitterBufferAdaptive {@link #ADAPTIVE_JITTER_BUFFER_ADAPTIVE}, * {@link #NON_ADAPTIVE_JITTER_BUFFER_ADAPTIVE}, * {@link #RESERVED_JITTER_BUFFER_ADAPTIVE}, or * {@link #UNKNOWN_JITTER_BUFFER_ADAPTIVE} * @throws IllegalArgumentException if the specified * jitterBufferAdapter is not one of the constants * ADAPTIVE_JITTER_BUFFER_ADAPTIVE, * NON_ADAPTIVE_JITTER_BUFFER_ADAPTIVE, * RESERVED_JITTER_BUFFER_ADAPTIVE, and * UNKNOWN_JITTER_BUFFER_ADAPTIVE */ public void setJitterBufferAdaptive(byte jitterBufferAdaptive) { switch (jitterBufferAdaptive) { case ADAPTIVE_JITTER_BUFFER_ADAPTIVE: case NON_ADAPTIVE_JITTER_BUFFER_ADAPTIVE: case RESERVED_JITTER_BUFFER_ADAPTIVE: case UNKNOWN_JITTER_BUFFER_ADAPTIVE: this.jitterBufferAdaptive = jitterBufferAdaptive; break; default: throw new IllegalArgumentException("jitterBufferAdaptive"); } } public void setJitterBufferMaximumDelay(int jitterBufferMaximumDelay) { this.jitterBufferMaximumDelay = jitterBufferMaximumDelay; } public void setJitterBufferNominalDelay(int jitterBufferNominalDelay) { this.jitterBufferNominalDelay = jitterBufferNominalDelay; } /** * Sets the implementation specific adjustment rate of a jitter buffer * in adaptive mode. * * @param jitterBufferRate the implementation specific adjustment rate * of a jitter buffer in adaptive mode */ public void setJitterBufferRate(byte jitterBufferRate) { this.jitterBufferRate = jitterBufferRate; } /** * Sets the fraction of RTP data packets from the source lost since the * beginning of reception. * * @param lossRate the fraction of RTP data packets from the source lost * since the beginning of reception * @see #lossRate */ public void setLossRate(short lossRate) { this.lossRate = lossRate; } public void setMosCq(byte mosCq) { this.mosCq = mosCq; } public void setMosLq(byte mosLq) { this.mosLq = mosLq; } public void setNoiseLevel(byte noiseLevel) { this.noiseLevel = noiseLevel; } /** * Sets the type of packet loss concealment (PLC). * * @param packetLossConcealment * {@link #STANDARD_PACKET_LOSS_CONCEALMENT}, * {@link #ENHANCED_PACKET_LOSS_CONCEALMENT}, * {@link #DISABLED_PACKET_LOSS_CONCEALMENT}, or * {@link #UNSPECIFIED_PACKET_LOSS_CONCEALMENT} * @throws IllegalArgumentException if the specified * packetLossConcealment is not one of the constants * STANDARD_PACKET_LOSS_CONCEALMENT, * ENHANCED_PACKET_LOSS_CONCEALMENT, * DISABLED_PACKET_LOSS_CONCEALMENT, and * UNSPECIFIED_PACKET_LOSS_CONCEALMENT */ public void setPacketLossConcealment(byte packetLossConcealment) { switch (packetLossConcealment) { case STANDARD_PACKET_LOSS_CONCEALMENT: case ENHANCED_PACKET_LOSS_CONCEALMENT: case DISABLED_PACKET_LOSS_CONCEALMENT: case UNSPECIFIED_PACKET_LOSS_CONCEALMENT: this.packetLossConcealment = packetLossConcealment; break; default: throw new IllegalArgumentException("packetLossConcealment"); } } public void setResidualEchoReturnLoss(byte residualEchoReturnLoss) { this.residualEchoReturnLoss = residualEchoReturnLoss; } public void setRFactor(byte rFactor) { this.rFactor = rFactor; } public void setRoundTripDelay(int roundTripDelay) { this.roundTripDelay = roundTripDelay; } public void setSignalLevel(byte signalLevel) { this.signalLevel = signalLevel; } /** * Sets the synchronization source identifier (SSRC) of the RTP data * packet source being reported upon by this report block. * * @param sourceSSRC the synchronization source identifier (SSRC) of the * RTP data packet source being reported upon by this report block */ public void setSourceSSRC(int sourceSSRC) { this.sourceSSRC = sourceSSRC; } /** * {@inheritDoc} */ @Override public String toString() { StringBuilder s = new StringBuilder("VoIP Metrics"); s.append(", SSRC of source ") .append(getSourceSSRC() & 0xFFFFFFFFL); s.append(", loss rate ").append(getLossRate()); s.append(", discard rate ").append(getDiscardRate()); s.append(", burst density ").append(getBurstDensity()); s.append(", gap density ").append(getGapDensity()); s.append(", burst duration ").append(getBurstDuration()); s.append(", gap duration ").append(getGapDuration()); s.append(", round trip delay ").append(getRoundTripDelay()); // TODO Auto-generated method stub return s.toString(); } } public static final String SDP_ATTRIBUTE = "rtcp-xr"; /** * The packet type (PT) constant 207 which identifies RTCP XR * packets. */ public static final int XR = 207; /** * The list of zero or more extended report blocks carried by this * RTCPExtendedReport. */ private final List reportBlocks = new LinkedList(); /** * The synchronization source identifier (SSRC) of the originator of this XR * packet. */ private int ssrc; /** * The System time in milliseconds at which this * RTCPExtendedReport has been received or sent by the local * endpoint. */ private long systemTimeStamp; /** * Initializes a new RTCPExtendedReport instance. */ public RTCPExtendedReport() { type = XR; } /** * Initializes a new RTCPExtendedReport instance by * deserializing/reading a binary representation from a byte array. * * @param buf the binary representation from which the new instance is to be * initialized * @param off the offset in buf at which the binary representation * starts * @param len the number of bytes in buf starting at * off which comprise the binary representation * @throws IOException if an input/output error occurs while * deserializing/reading the new instance from buf or the binary * representation does not parse into an RTCPExtendedReport * instance */ public RTCPExtendedReport(byte[] buf, int off, int len) throws IOException { this(new DataInputStream(new ByteArrayInputStream(buf, off, len))); } /** * Initializes a new RTCPExtendedReport instance by * deserializing/reading a binary representation from a * DataInputStream. * * @param datainputstream the binary representation from which the new * instance is to be initialized. * @throws IOException if an input/output error occurs while * deserializing/reading the new instance from datainputstream or * the binary representation does not parse into an * RTCPExtendedReport instance. */ public RTCPExtendedReport(DataInputStream datainputstream) throws IOException { this(); // V=2, P, reserved int b0 = datainputstream.readUnsignedByte(); // PT=XR=207 int pt = datainputstream.readUnsignedByte(); // length int length = datainputstream.readUnsignedShort(); if (length < 1) throw new IOException("Invalid RTCP length."); parse(b0, pt, length, datainputstream); } /** * Initializes a new RTCPExtendedReport instance by * deserializing/reading a binary representation of part of the packet from * a DataInputStream, and taking the values found in the * first 4 bytes of the binary representation as arguments. * * @param b0 the first byte of the binary representation. * @param pt the value of the {@code packet type} field. * @param length the value of the {@code length} field. * @param datainputstream the binary representation from which the new * instance is to be initialized, excluding the first 4 bytes. * @throws IOException if an input/output error occurs while * deserializing/reading the new instance from datainputstream or * the binary representation does not parse into an * RTCPExtendedReport instance. */ public RTCPExtendedReport(int b0, int pt, int length, DataInputStream datainputstream) throws IOException { this(); parse(b0, pt, length, datainputstream); } /** * Initializes a new RTCPExtendedReport instance by * deserializing/reading a binary representation of part of the packet from * a DataInputStream, and taking the values normally found in the * first 4 bytes of the binary representation as arguments. * * @param b0 the first byte of the binary representation. * @param pt the value of the {@code packet type} field. * @param length the length in bytes of the RTCP packet, including all of * it's headers and excluding any padding. * @param datainputstream the binary representation from which the new * instance is to be initialized, excluding the first 4 bytes. * @throws IOException if an input/output error occurs while * deserializing/reading the new instance from datainputstream or * the binary representation does not parse into an * RTCPExtendedReport instance. */ private void parse(int b0, int pt, int length, DataInputStream datainputstream) throws IOException { // The first 4 bytes have already been read. length -= 4; // V=2 if ((b0 & 0xc0) != 128) throw new IOException("Invalid RTCP version (V)."); if (pt != XR) throw new IOException("Invalid RTCP packet type (PT)."); // SSRC setSSRC(datainputstream.readInt()); length = length - 4; // report blocks. A block is at least 4 bytes long. while (length >= 4) { // block type (BT) int bt = datainputstream.readUnsignedByte(); // type-specific datainputstream.readByte(); // block length in bytes, including the block header int blockLength = datainputstream.readUnsignedShort() + 1 << 2; if (length < blockLength) { throw new IOException("Invalid extended block"); } if (bt == VoIPMetricsReportBlock.VOIP_METRICS_REPORT_BLOCK_TYPE) { addReportBlock( new VoIPMetricsReportBlock( blockLength - 4, datainputstream)); } else { // The implementation reads and ignores any extended report // blocks other than VoIP Metrics Report Block. // Already read 4 bytes datainputstream.skip(blockLength - 4); } length = length - blockLength; } // If we didn't read all bytes of the packet, the stream is probably in // an inconsistent state. if (length != 0) { throw new IOException("Invalid XR packet, unread bytes"); } } /** * Adds an extended report block to this extended report. * * @param reportBlock the extended report block to add to this extended * report * @return true if the list of extended report blocks carried by * this extended report changed because of the method invocation; otherwise, * false * @throws NullPointerException if reportBlock is null */ public boolean addReportBlock(ReportBlock reportBlock) { if (reportBlock == null) throw new NullPointerException("reportBlock"); else return reportBlocks.add(reportBlock); } /** * {@inheritDoc} */ @Override public void assemble(DataOutputStream dataoutputstream) throws IOException { // V=2, P, reserved dataoutputstream.writeByte(128); // PT=XR=207 dataoutputstream.writeByte(XR); // length dataoutputstream.writeShort(calcLength() / 4 - 1); // SSRC dataoutputstream.writeInt(getSSRC()); // report blocks for (ReportBlock reportBlock : getReportBlocks()) reportBlock.assemble(dataoutputstream); } /** * {@inheritDoc} */ @Override public int calcLength() { int length = 1 /* V=2, P, reserved */ + 1 /* PT */ + 2 /* length */ + 4 /* SSRC */; // report blocks for (ReportBlock reportBlock : getReportBlocks()) length += reportBlock.calcLength(); return length; } /** * Gets the number of the extended report blocks carried by this * RTCPExtendedReport. * * @return the number of the extended report blocks carried by this * RTCPExtendedReport */ public int getReportBlockCount() { return reportBlocks.size(); } /** * Gets a list of the extended report blocks carried by this * RTCPExtendedReport. * * @return a list of the extended repot blocks carried by this * RTCPExtendedReport */ public List getReportBlocks() { return Collections.unmodifiableList(reportBlocks); } /** * Gets the synchronization source identifier (SSRC) of the originator of * this XR packet. * * @return the synchronization source identifier (SSRC) of the originator of * this XR packet */ public int getSSRC() { return ssrc; } /** * Gets the System time in milliseconds at which this * RTCPExtendedReport has been received or sent by the local * endpoint. * * @return the System time in milliseconds at which this * RTCPExtendedReport has been received or sent by the local * endpoint */ public long getSystemTimeStamp() { return systemTimeStamp; } /** * Removes an extended report block from this extended report. * * @param reportBlock the extended report block to remove from this extended * report * @return true if the list of extended report blocks carried by * this extended report changed because of the method invocation; otherwise, * false */ public boolean removeReportBlock(ReportBlock reportBlock) { if (reportBlock == null) return false; else return reportBlocks.remove(reportBlock); } /** * Sets the synchronization source identifier (SSRC) of the originator of * this XR packet. * * @param ssrc the synchronization source identifier (SSRC) of the * originator of this XR packet */ public void setSSRC(int ssrc) { this.ssrc = ssrc; } /** * Sets the System time in milliseconds at which this * RTCPExtendedReport has been received or sent by the local * endpoint. * * @param systemTimeStamp the System time in milliseconds at which * this RTCPExtendedReport has been received or sent by the local * endpoint */ public void setSystemTimeStamp(long systemTimeStamp) { this.systemTimeStamp = systemTimeStamp; } /** * {@inheritDoc} */ @Override public String toString() { StringBuilder s = new StringBuilder("RTCP XR"); // SSRC s.append(", SSRC ").append(getSSRC() & 0xFFFFFFFFL); List reportBlocks = getReportBlocks(); boolean b = false; // report blocks s.append(", report blocks ["); for (ReportBlock reportBlock : reportBlocks) { if (b) s.append("; "); else b = true; s.append(reportBlock); } s.append("]"); return s.toString(); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy