/**
   * Encapsulates {@code pkt} in the RTX format, using {@code rtxSsrc} as its SSRC, and transmits it
   * to {@link #channel} by injecting it in the {@code MediaStream}.
   *
   * @param pkt the packet to transmit.
   * @param rtxSsrc the SSRC for the RTX stream.
   * @return {@code true} if the packet was successfully retransmitted, {@code false} otherwise.
   */
  private boolean encapsulateInRtxAndTransmit(RawPacket pkt, long rtxSsrc) {
    byte[] buf = pkt.getBuffer();
    int len = pkt.getLength();
    int off = pkt.getOffset();
    byte[] newBuf = buf;
    if (buf.length < len + 2) {
      // FIXME The byte array newly allocated and assigned to newBuf must
      // be made known to pkt eventually.
      newBuf = new byte[len + 2];
    }

    int osn = pkt.getSequenceNumber();
    int headerLength = pkt.getHeaderLength();
    int payloadLength = len - headerLength;
    System.arraycopy(buf, off, newBuf, 0, headerLength);
    // FIXME If newBuf is actually buf, then we will override the first two
    // bytes of the payload bellow.
    newBuf[headerLength] = (byte) ((osn >> 8) & 0xff);
    newBuf[headerLength + 1] = (byte) (osn & 0xff);
    System.arraycopy(buf, off + headerLength, newBuf, headerLength + 2, payloadLength);
    // FIXME We tried to extend the payload of pkt by two bytes above but
    // we never told pkt that its length has increased by these two bytes.

    MediaStream mediaStream = channel.getStream();
    if (mediaStream != null) {
      pkt.setSSRC((int) rtxSsrc);
      // Only call getNextRtxSequenceNumber() when we're sure we're going
      // to transmit a packet, because it consumes a sequence number.
      pkt.setSequenceNumber(getNextRtxSequenceNumber(rtxSsrc));
      try {
        mediaStream.injectPacket(pkt, /* data */ true, /* after */ null);
      } catch (TransmissionFailedException tfe) {
        logger.warn("Failed to transmit an RTX packet.");
        return false;
      }
    }

    return true;
  }
  /**
   * Handles an RTX packet and returns it.
   *
   * @param pkt the packet to handle.
   * @return the packet
   */
  private RawPacket handleRtxPacket(RawPacket pkt) {
    boolean destinationSupportsRtx = channel.getRtxPayloadType() != -1;
    RawPacket mediaPacket = createMediaPacket(pkt);

    if (mediaPacket != null) {
      RawPacketCache cache = channel.getStream().getPacketCache();
      if (cache != null) {
        cache.cachePacket(mediaPacket);
      }
    }

    if (destinationSupportsRtx) {
      pkt.setSequenceNumber(
          getNextRtxSequenceNumber(pkt.getSSRC() & 0xffffffffL, pkt.getSequenceNumber()));
    } else {
      // If the media packet was not reconstructed, drop the RTX packet
      // (by returning null).
      return mediaPacket;
    }

    return pkt;
  }
  /**
   * Encapsulates {@code pkt} in the RTX format, using {@code rtxSsrc} as its SSRC, and transmits it
   * to {@link #channel} by injecting it in the {@code MediaStream}.
   *
   * @param pkt the packet to transmit.
   * @param rtxSsrc the SSRC for the RTX stream.
   * @param after the {@code TransformEngine} in the chain of {@code TransformEngine}s of the
   *     associated {@code MediaStream} after which the injection of {@code pkt} is to begin
   * @return {@code true} if the packet was successfully retransmitted, {@code false} otherwise.
   */
  private boolean encapsulateInRtxAndTransmit(RawPacket pkt, long rtxSsrc, TransformEngine after) {
    byte[] buf = pkt.getBuffer();
    int len = pkt.getLength();
    int off = pkt.getOffset();

    byte[] newBuf = new byte[len + 2];
    RawPacket rtxPkt = new RawPacket(newBuf, 0, len + 2);

    int osn = pkt.getSequenceNumber();
    int headerLength = pkt.getHeaderLength();
    int payloadLength = pkt.getPayloadLength();

    // Copy the header.
    System.arraycopy(buf, off, newBuf, 0, headerLength);

    // Set the OSN field.
    newBuf[headerLength] = (byte) ((osn >> 8) & 0xff);
    newBuf[headerLength + 1] = (byte) (osn & 0xff);

    // Copy the payload.
    System.arraycopy(buf, off + headerLength, newBuf, headerLength + 2, payloadLength);

    MediaStream mediaStream = channel.getStream();
    if (mediaStream != null) {
      rtxPkt.setSSRC((int) rtxSsrc);
      rtxPkt.setPayloadType(rtxPayloadType);
      // Only call getNextRtxSequenceNumber() when we're sure we're going
      // to transmit a packet, because it consumes a sequence number.
      rtxPkt.setSequenceNumber(getNextRtxSequenceNumber(rtxSsrc));
      try {
        mediaStream.injectPacket(rtxPkt, /* data */ true, after);
      } catch (TransmissionFailedException tfe) {
        logger.warn("Failed to transmit an RTX packet.");
        return false;
      }
    }

    return true;
  }