/** * Gets the first RED block in the RED payload. * * @param buffer the byte buffer that contains the RED payload. * @param offset the offset in the buffer where the RED payload begins. * @param length the length of the RED payload. * @return the primary RED block if it exists, null otherwise. */ public static REDBlock getPrimaryBlock(byte[] buffer, int offset, int length) { // Chrome is typically sending RED packets with a single block carrying // either VP8 or FEC. This is unusual, and probably wrong as it messes // up the sequence numbers and packet loss computations but it's just // the way it is. Here we detect this situation and avoid looping // through the blocks if there is a single block. if (isMultiBlock(buffer, offset, length)) { REDBlock block = null; REDBlockIterator redBlockIterator = new REDBlockIterator(buffer, offset, length); while (redBlockIterator.hasNext()) { block = redBlockIterator.next(); } if (block == null) { logger.warn("No primary block found."); } return block; } else { if (buffer == null || offset < 0 || length < 0 || buffer.length < offset + length) { logger.warn( "Prevented an array out of bounds exception: " + "buffer length: " + buffer.length + ", offset: " + offset + ", len: " + length); return null; } byte blockPT = (byte) (buffer[offset] & 0x7f); int blockOff = offset + 1; // + 1 for the primary block header. int blockLen = length - blockOff; if (buffer.length < blockOff + blockLen) { logger.warn("Primary block doesn't fit in RED packet."); return null; } return new REDBlock(buffer, blockOff, blockLen, blockPT); } }
/** * Matches a RED block in the RED payload. * * @param predicate the predicate that is used to match the RED block. * @param buffer the byte buffer that contains the RED payload. * @param offset the offset in the buffer where the RED payload begins. * @param length the length of the RED payload. * @return the first RED block that matches the given predicate, null otherwise. */ public static REDBlock matchFirst( Predicate<REDBlock> predicate, byte[] buffer, int offset, int length) { if (isMultiBlock(buffer, offset, length)) { REDBlockIterator it = new REDBlockIterator(buffer, offset, length); while (it.hasNext()) { REDBlock b = it.next(); if (b != null && predicate.test(b)) { return b; } } return null; } else { REDBlock b = getPrimaryBlock(buffer, offset, length); if (b != null && predicate.test(b)) { return b; } else { return null; } } }