/** * Tries to find an SSRC paired with {@code ssrc} in an FID group in one of the channels from * {@link #channel}'s {@code Content}. Returns -1 on failure. * * @param pkt the {@code RawPacket} that holds the RTP packet for which to find a paired SSRC. * @return An SSRC paired with {@code ssrc} in an FID group, or -1. */ private long getRtxSsrc(RawPacket pkt) { StreamRTPManager receiveRTPManager = channel.getStream().getRTPTranslator().findStreamRTPManagerByReceiveSSRC(pkt.getSSRC()); MediaStreamTrackReceiver receiver = null; if (receiveRTPManager != null) { MediaStream receiveStream = receiveRTPManager.getMediaStream(); if (receiveStream != null) { receiver = receiveStream.getMediaStreamTrackReceiver(); } } if (receiver == null) { return -1; } RTPEncoding encoding = receiver.resolveRTPEncoding(pkt); if (encoding == null) { logger.warn( "encoding_not_found" + ",stream_hash=" + channel.getStream().hashCode() + " ssrc=" + pkt.getSSRCAsLong()); return -1; } return encoding.getRTXSSRC(); }
/** * Retransmits a packet to {@link #channel}. If the destination supports the RTX format, the * packet will be encapsulated in RTX, otherwise, the packet will be retransmitted as-is. * * @param pkt the packet to retransmit. * @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. */ public boolean retransmit(RawPacket pkt, TransformEngine after) { boolean destinationSupportsRtx = rtxPayloadType != -1; boolean retransmitPlain; if (destinationSupportsRtx) { long rtxSsrc = getRtxSsrc(pkt); if (rtxSsrc == -1) { logger.warn( "Cannot find SSRC for RTX, retransmitting plain. " + "SSRC=" + pkt.getSSRCAsLong()); retransmitPlain = true; } else { retransmitPlain = !encapsulateInRtxAndTransmit(pkt, rtxSsrc, after); } } else { retransmitPlain = true; } if (retransmitPlain) { MediaStream mediaStream = channel.getStream(); if (mediaStream != null) { try { mediaStream.injectPacket(pkt, /* data */ true, after); } catch (TransmissionFailedException tfe) { logger.warn("Failed to retransmit a packet."); return false; } } } return true; }
/** * Removes the RTX encapsulation from a packet. * * @param pkt the packet to remove the RTX encapsulation from. * @return the original media packet represented by {@code pkt}, or null if we couldn't * reconstruct the original packet. */ private RawPacket deRtx(RawPacket pkt) { boolean success = false; if (pkt.getPayloadLength() - pkt.getPaddingSize() < 2) { // We need at least 2 bytes to read the OSN field. if (logger.isDebugEnabled()) { logger.debug("Dropping an incoming RTX packet with padding only: " + pkt); } return null; } long mediaSsrc = getPrimarySsrc(pkt); if (mediaSsrc != -1) { if (rtxAssociatedPayloadType != -1) { int osn = pkt.getOriginalSequenceNumber(); // Remove the RTX header by moving the RTP header two bytes // right. byte[] buf = pkt.getBuffer(); int off = pkt.getOffset(); System.arraycopy(buf, off, buf, off + 2, pkt.getHeaderLength()); pkt.setOffset(off + 2); pkt.setLength(pkt.getLength() - 2); pkt.setSSRC((int) mediaSsrc); pkt.setSequenceNumber(osn); pkt.setPayloadType(rtxAssociatedPayloadType); success = true; } else { logger.warn( "RTX packet received, but no APT is defined. Packet " + "SSRC " + pkt.getSSRCAsLong() + ", associated media" + " SSRC " + mediaSsrc); } } // If we failed to handle the RTX packet, drop it. return success ? pkt : null; }