Add separate LC_ASSERT_VT() for asserts that only apply for valid traffic
This commit is contained in:
parent
574ad6e676
commit
620b4be477
7 changed files with 89 additions and 74 deletions
|
|
@ -197,14 +197,14 @@ static void decodeInputData(PQUEUED_AUDIO_PACKET packet) {
|
||||||
(unsigned char*)(rtp + 1), dataLength,
|
(unsigned char*)(rtp + 1), dataLength,
|
||||||
decryptedOpusData, &dataLength)) {
|
decryptedOpusData, &dataLength)) {
|
||||||
Limelog("Failed to decrypt audio packet (sequence number: %u)\n", rtp->sequenceNumber);
|
Limelog("Failed to decrypt audio packet (sequence number: %u)\n", rtp->sequenceNumber);
|
||||||
LC_ASSERT(false);
|
LC_ASSERT_VT(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef LC_DEBUG
|
#ifdef LC_DEBUG
|
||||||
if (opusHeaderByte == INVALID_OPUS_HEADER) {
|
if (opusHeaderByte == INVALID_OPUS_HEADER) {
|
||||||
opusHeaderByte = decryptedOpusData[0];
|
opusHeaderByte = decryptedOpusData[0];
|
||||||
LC_ASSERT(opusHeaderByte != INVALID_OPUS_HEADER);
|
LC_ASSERT_VT(opusHeaderByte != INVALID_OPUS_HEADER);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Opus header should stay constant for the entire stream.
|
// Opus header should stay constant for the entire stream.
|
||||||
|
|
@ -212,7 +212,7 @@ static void decodeInputData(PQUEUED_AUDIO_PACKET packet) {
|
||||||
// incorrectly recovered a data shard or the decryption
|
// incorrectly recovered a data shard or the decryption
|
||||||
// of the audio packet failed. Sunshine violates this for
|
// of the audio packet failed. Sunshine violates this for
|
||||||
// surround sound in some cases, so just ignore it.
|
// surround sound in some cases, so just ignore it.
|
||||||
LC_ASSERT(decryptedOpusData[0] == opusHeaderByte || IS_SUNSHINE());
|
LC_ASSERT_VT(decryptedOpusData[0] == opusHeaderByte || IS_SUNSHINE());
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -222,13 +222,13 @@ static void decodeInputData(PQUEUED_AUDIO_PACKET packet) {
|
||||||
#ifdef LC_DEBUG
|
#ifdef LC_DEBUG
|
||||||
if (opusHeaderByte == INVALID_OPUS_HEADER) {
|
if (opusHeaderByte == INVALID_OPUS_HEADER) {
|
||||||
opusHeaderByte = ((uint8_t*)(rtp + 1))[0];
|
opusHeaderByte = ((uint8_t*)(rtp + 1))[0];
|
||||||
LC_ASSERT(opusHeaderByte != INVALID_OPUS_HEADER);
|
LC_ASSERT_VT(opusHeaderByte != INVALID_OPUS_HEADER);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Opus header should stay constant for the entire stream.
|
// Opus header should stay constant for the entire stream.
|
||||||
// If it doesn't, it may indicate that the RtpAudioQueue
|
// If it doesn't, it may indicate that the RtpAudioQueue
|
||||||
// incorrectly recovered a data shard.
|
// incorrectly recovered a data shard.
|
||||||
LC_ASSERT(((uint8_t*)(rtp + 1))[0] == opusHeaderByte);
|
LC_ASSERT_VT(((uint8_t*)(rtp + 1))[0] == opusHeaderByte);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -425,7 +425,7 @@ void connectionSendFrameFecStatus(PSS_FRAME_FEC_STATUS fecStatus) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void connectionSawFrame(int frameIndex) {
|
void connectionSawFrame(int frameIndex) {
|
||||||
LC_ASSERT(!isBefore16(frameIndex, lastSeenFrame));
|
LC_ASSERT_VT(!isBefore16(frameIndex, lastSeenFrame));
|
||||||
|
|
||||||
uint64_t now = PltGetMillis();
|
uint64_t now = PltGetMillis();
|
||||||
|
|
||||||
|
|
@ -1123,7 +1123,7 @@ static void controlReceiveThreadFunc(void* context) {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// What do we do here???
|
// What do we do here???
|
||||||
LC_ASSERT(false);
|
LC_ASSERT_VT(false);
|
||||||
packetLength = (int)event.packet->dataLength;
|
packetLength = (int)event.packet->dataLength;
|
||||||
event.packet->data = NULL;
|
event.packet->data = NULL;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -86,6 +86,17 @@
|
||||||
#define LC_ASSERT(x) assert(x)
|
#define LC_ASSERT(x) assert(x)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// If we're fuzzing, we don't want to enable asserts that can be affected by
|
||||||
|
// bad input from the remote host. LC_ASSERT_VT() is used for assertions that
|
||||||
|
// check data that comes from the host. These checks are enabled for normal
|
||||||
|
// debug builds, since they indicate an error in Moonlight or on the host.
|
||||||
|
// These are disabled when fuzzing, since the traffic is intentionally invalid.
|
||||||
|
#ifdef LC_FUZZING
|
||||||
|
#define LC_ASSERT_VT(x)
|
||||||
|
#else
|
||||||
|
#define LC_ASSERT_VT(x) LC_ASSERT(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#pragma intrinsic(_byteswap_ushort)
|
#pragma intrinsic(_byteswap_ushort)
|
||||||
#define BSWAP16(x) _byteswap_ushort(x)
|
#define BSWAP16(x) _byteswap_ushort(x)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#include "Limelight-internal.h"
|
#include "Limelight-internal.h"
|
||||||
|
|
||||||
#ifdef LC_DEBUG
|
#if defined(LC_DEBUG) && !defined(LC_FUZZING)
|
||||||
// This enables FEC validation mode with a synthetic drop
|
// This enables FEC validation mode with a synthetic drop
|
||||||
// and recovered packet checks vs the original input. It
|
// and recovered packet checks vs the original input. It
|
||||||
// is on by default for debug builds.
|
// is on by default for debug builds.
|
||||||
|
|
@ -86,12 +86,12 @@ static void validateFecBlockState(PRTP_AUDIO_QUEUE queue) {
|
||||||
while (block != NULL) {
|
while (block != NULL) {
|
||||||
// Ensure the list is sorted correctly
|
// Ensure the list is sorted correctly
|
||||||
LC_ASSERT(isBefore16(lastSeqNum, block->fecHeader.baseSequenceNumber));
|
LC_ASSERT(isBefore16(lastSeqNum, block->fecHeader.baseSequenceNumber));
|
||||||
LC_ASSERT(isBefore32(lastTs, block->fecHeader.baseTimestamp));
|
LC_ASSERT_VT(isBefore32(lastTs, block->fecHeader.baseTimestamp));
|
||||||
|
|
||||||
// Ensure entry invariants are satisfied
|
// Ensure entry invariants are satisfied
|
||||||
LC_ASSERT(block->blockSize == lastBlock->blockSize);
|
LC_ASSERT_VT(block->blockSize == lastBlock->blockSize);
|
||||||
LC_ASSERT(block->fecHeader.payloadType == lastBlock->fecHeader.payloadType);
|
LC_ASSERT_VT(block->fecHeader.payloadType == lastBlock->fecHeader.payloadType);
|
||||||
LC_ASSERT(block->fecHeader.ssrc == lastBlock->fecHeader.ssrc);
|
LC_ASSERT_VT(block->fecHeader.ssrc == lastBlock->fecHeader.ssrc);
|
||||||
|
|
||||||
// Ensure the list itself is consistent
|
// Ensure the list itself is consistent
|
||||||
LC_ASSERT(block->prev == lastBlock);
|
LC_ASSERT(block->prev == lastBlock);
|
||||||
|
|
@ -205,7 +205,7 @@ static PRTPA_FEC_BLOCK getFecBlockForRtpPacket(PRTP_AUDIO_QUEUE queue, PRTP_PACK
|
||||||
if (packet->packetType == RTP_PAYLOAD_TYPE_AUDIO) {
|
if (packet->packetType == RTP_PAYLOAD_TYPE_AUDIO) {
|
||||||
if (length < sizeof(RTP_PACKET)) {
|
if (length < sizeof(RTP_PACKET)) {
|
||||||
Limelog("RTP audio data packet too small: %u\n", length);
|
Limelog("RTP audio data packet too small: %u\n", length);
|
||||||
LC_ASSERT(false);
|
LC_ASSERT_VT(false);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -239,7 +239,7 @@ static PRTPA_FEC_BLOCK getFecBlockForRtpPacket(PRTP_AUDIO_QUEUE queue, PRTP_PACK
|
||||||
|
|
||||||
if (length < sizeof(RTP_PACKET) + sizeof(AUDIO_FEC_HEADER)) {
|
if (length < sizeof(RTP_PACKET) + sizeof(AUDIO_FEC_HEADER)) {
|
||||||
Limelog("RTP audio FEC packet too small: %u\n", length);
|
Limelog("RTP audio FEC packet too small: %u\n", length);
|
||||||
LC_ASSERT(false);
|
LC_ASSERT_VT(false);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -253,7 +253,7 @@ static PRTPA_FEC_BLOCK getFecBlockForRtpPacket(PRTP_AUDIO_QUEUE queue, PRTP_PACK
|
||||||
// later during recovery.
|
// later during recovery.
|
||||||
if (fecHeader->fecShardIndex >= RTPA_FEC_SHARDS) {
|
if (fecHeader->fecShardIndex >= RTPA_FEC_SHARDS) {
|
||||||
Limelog("Too many audio FEC shards: %u\n", fecHeader->fecShardIndex);
|
Limelog("Too many audio FEC shards: %u\n", fecHeader->fecShardIndex);
|
||||||
LC_ASSERT(false);
|
LC_ASSERT_VT(false);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -264,7 +264,7 @@ static PRTPA_FEC_BLOCK getFecBlockForRtpPacket(PRTP_AUDIO_QUEUE queue, PRTP_PACK
|
||||||
Limelog("Invalid FEC block base sequence number (got %u, expected %u)\n",
|
Limelog("Invalid FEC block base sequence number (got %u, expected %u)\n",
|
||||||
fecBlockBaseSeqNum, (fecBlockBaseSeqNum / RTPA_DATA_SHARDS) * RTPA_DATA_SHARDS);
|
fecBlockBaseSeqNum, (fecBlockBaseSeqNum / RTPA_DATA_SHARDS) * RTPA_DATA_SHARDS);
|
||||||
Limelog("Audio FEC has been disabled due to an incompatibility with your host's old software!\n");
|
Limelog("Audio FEC has been disabled due to an incompatibility with your host's old software!\n");
|
||||||
LC_ASSERT(fecBlockBaseSeqNum % RTPA_DATA_SHARDS == 0);
|
LC_ASSERT_VT(fecBlockBaseSeqNum % RTPA_DATA_SHARDS == 0);
|
||||||
queue->incompatibleServer = true;
|
queue->incompatibleServer = true;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
@ -273,7 +273,7 @@ static PRTPA_FEC_BLOCK getFecBlockForRtpPacket(PRTP_AUDIO_QUEUE queue, PRTP_PACK
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Limelog("Invalid RTP audio payload type: %u\n", packet->packetType);
|
Limelog("Invalid RTP audio payload type: %u\n", packet->packetType);
|
||||||
LC_ASSERT(false);
|
LC_ASSERT_VT(false);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -296,9 +296,9 @@ static PRTPA_FEC_BLOCK getFecBlockForRtpPacket(PRTP_AUDIO_QUEUE queue, PRTP_PACK
|
||||||
while (existingBlock != NULL) {
|
while (existingBlock != NULL) {
|
||||||
if (existingBlock->fecHeader.baseSequenceNumber == fecBlockBaseSeqNum) {
|
if (existingBlock->fecHeader.baseSequenceNumber == fecBlockBaseSeqNum) {
|
||||||
// The FEC header data should match for all packets
|
// The FEC header data should match for all packets
|
||||||
LC_ASSERT(existingBlock->fecHeader.payloadType == fecBlockPayloadType);
|
LC_ASSERT_VT(existingBlock->fecHeader.payloadType == fecBlockPayloadType);
|
||||||
LC_ASSERT(existingBlock->fecHeader.baseTimestamp == fecBlockBaseTs);
|
LC_ASSERT_VT(existingBlock->fecHeader.baseTimestamp == fecBlockBaseTs);
|
||||||
LC_ASSERT(existingBlock->fecHeader.ssrc == fecBlockSsrc);
|
LC_ASSERT_VT(existingBlock->fecHeader.ssrc == fecBlockSsrc);
|
||||||
|
|
||||||
// The block size must match in order to safely copy shards into it
|
// The block size must match in order to safely copy shards into it
|
||||||
if (existingBlock->blockSize != blockSize) {
|
if (existingBlock->blockSize != blockSize) {
|
||||||
|
|
@ -306,7 +306,7 @@ static PRTPA_FEC_BLOCK getFecBlockForRtpPacket(PRTP_AUDIO_QUEUE queue, PRTP_PACK
|
||||||
// constant size for audio packets.
|
// constant size for audio packets.
|
||||||
Limelog("Audio block size mismatch (got %u, expected %u)\n", blockSize, existingBlock->blockSize);
|
Limelog("Audio block size mismatch (got %u, expected %u)\n", blockSize, existingBlock->blockSize);
|
||||||
Limelog("Audio FEC has been disabled due to an incompatibility with your host's old software!\n");
|
Limelog("Audio FEC has been disabled due to an incompatibility with your host's old software!\n");
|
||||||
LC_ASSERT(existingBlock->blockSize == blockSize);
|
LC_ASSERT_VT(existingBlock->blockSize == blockSize);
|
||||||
queue->incompatibleServer = true;
|
queue->incompatibleServer = true;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
@ -464,11 +464,11 @@ static bool completeFecBlock(PRTP_AUDIO_QUEUE queue, PRTPA_FEC_BLOCK block) {
|
||||||
|
|
||||||
#ifdef FEC_VALIDATION_MODE
|
#ifdef FEC_VALIDATION_MODE
|
||||||
// Check the RTP header values
|
// Check the RTP header values
|
||||||
LC_ASSERT(block->dataPackets[dropIndex]->header == droppedRtpPacket->header);
|
LC_ASSERT_VT(block->dataPackets[dropIndex]->header == droppedRtpPacket->header);
|
||||||
LC_ASSERT(block->dataPackets[dropIndex]->packetType == droppedRtpPacket->packetType);
|
LC_ASSERT_VT(block->dataPackets[dropIndex]->packetType == droppedRtpPacket->packetType);
|
||||||
LC_ASSERT(block->dataPackets[dropIndex]->sequenceNumber == droppedRtpPacket->sequenceNumber);
|
LC_ASSERT_VT(block->dataPackets[dropIndex]->sequenceNumber == droppedRtpPacket->sequenceNumber);
|
||||||
LC_ASSERT(block->dataPackets[dropIndex]->timestamp == droppedRtpPacket->timestamp);
|
LC_ASSERT_VT(block->dataPackets[dropIndex]->timestamp == droppedRtpPacket->timestamp);
|
||||||
LC_ASSERT(block->dataPackets[dropIndex]->ssrc == droppedRtpPacket->ssrc);
|
LC_ASSERT_VT(block->dataPackets[dropIndex]->ssrc == droppedRtpPacket->ssrc);
|
||||||
|
|
||||||
// Check the data itself - use memcmp() and only loop if an error is detected
|
// Check the data itself - use memcmp() and only loop if an error is detected
|
||||||
if (memcmp(block->dataPackets[dropIndex] + 1, droppedRtpPacket + 1, block->blockSize)) {
|
if (memcmp(block->dataPackets[dropIndex] + 1, droppedRtpPacket + 1, block->blockSize)) {
|
||||||
|
|
@ -484,7 +484,7 @@ static bool completeFecBlock(PRTP_AUDIO_QUEUE queue, PRTPA_FEC_BLOCK block) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LC_ASSERT(recoveryErrors == 0);
|
LC_ASSERT_VT(recoveryErrors == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(droppedRtpPacket);
|
free(droppedRtpPacket);
|
||||||
|
|
@ -523,7 +523,7 @@ static void handleMissingPackets(PRTP_AUDIO_QUEUE queue) {
|
||||||
// If we reach this point, we know the next packet resides in the first FEC block we're
|
// If we reach this point, we know the next packet resides in the first FEC block we're
|
||||||
// currently waiting on. In that case, we want to wait at least until we have a second FEC
|
// currently waiting on. In that case, we want to wait at least until we have a second FEC
|
||||||
// block to give up on the first one. If we don't have a second block now, just keep waiting.
|
// block to give up on the first one. If we don't have a second block now, just keep waiting.
|
||||||
LC_ASSERT(isBefore16(queue->nextRtpSequenceNumber, queue->blockHead->fecHeader.baseSequenceNumber + RTPA_DATA_SHARDS));
|
LC_ASSERT_VT(isBefore16(queue->nextRtpSequenceNumber, queue->blockHead->fecHeader.baseSequenceNumber + RTPA_DATA_SHARDS));
|
||||||
if (queue->blockHead == queue->blockTail) {
|
if (queue->blockHead == queue->blockTail) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#include "Limelight-internal.h"
|
#include "Limelight-internal.h"
|
||||||
#include "rs.h"
|
#include "rs.h"
|
||||||
|
|
||||||
#ifdef LC_DEBUG
|
#if defined(LC_DEBUG) && !defined(LC_FUZZING)
|
||||||
// This enables FEC validation mode with a synthetic drop
|
// This enables FEC validation mode with a synthetic drop
|
||||||
// and recovered packet checks vs the original input. It
|
// and recovered packet checks vs the original input. It
|
||||||
// is on by default for debug builds.
|
// is on by default for debug builds.
|
||||||
|
|
@ -376,15 +376,15 @@ cleanup_packets:
|
||||||
int j;
|
int j;
|
||||||
int recoveryErrors = 0;
|
int recoveryErrors = 0;
|
||||||
|
|
||||||
LC_ASSERT(droppedDataLength <= recoveredDataLength);
|
LC_ASSERT_VT(droppedDataLength <= recoveredDataLength);
|
||||||
LC_ASSERT(droppedDataLength == recoveredDataLength || (nvPacket->flags & FLAG_EOF));
|
LC_ASSERT_VT(droppedDataLength == recoveredDataLength || (nvPacket->flags & FLAG_EOF));
|
||||||
|
|
||||||
// Check all NV_VIDEO_PACKET fields except FEC stuff which differs in the recovered packet
|
// Check all NV_VIDEO_PACKET fields except FEC stuff which differs in the recovered packet
|
||||||
LC_ASSERT(nvPacket->flags == droppedNvPacket->flags);
|
LC_ASSERT_VT(nvPacket->flags == droppedNvPacket->flags);
|
||||||
LC_ASSERT(nvPacket->frameIndex == droppedNvPacket->frameIndex);
|
LC_ASSERT_VT(nvPacket->frameIndex == droppedNvPacket->frameIndex);
|
||||||
LC_ASSERT(nvPacket->streamPacketIndex == droppedNvPacket->streamPacketIndex);
|
LC_ASSERT_VT(nvPacket->streamPacketIndex == droppedNvPacket->streamPacketIndex);
|
||||||
LC_ASSERT(nvPacket->reserved == droppedNvPacket->reserved);
|
LC_ASSERT_VT(nvPacket->reserved == droppedNvPacket->reserved);
|
||||||
LC_ASSERT(!queue->multiFecCapable || nvPacket->multiFecBlocks == droppedNvPacket->multiFecBlocks);
|
LC_ASSERT_VT(!queue->multiFecCapable || nvPacket->multiFecBlocks == droppedNvPacket->multiFecBlocks);
|
||||||
|
|
||||||
// Check the data itself - use memcmp() and only loop if an error is detected
|
// Check the data itself - use memcmp() and only loop if an error is detected
|
||||||
if (memcmp(nvPacket + 1, droppedNvPacket + 1, droppedDataLength)) {
|
if (memcmp(nvPacket + 1, droppedNvPacket + 1, droppedDataLength)) {
|
||||||
|
|
@ -409,7 +409,7 @@ cleanup_packets:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LC_ASSERT(recoveryErrors == 0);
|
LC_ASSERT_VT(recoveryErrors == 0);
|
||||||
|
|
||||||
// This drop was fake, so we don't want to actually submit it to the depacketizer.
|
// This drop was fake, so we don't want to actually submit it to the depacketizer.
|
||||||
// It will get confused because it's already seen this packet before.
|
// It will get confused because it's already seen this packet before.
|
||||||
|
|
@ -542,7 +542,7 @@ int RtpvAddPacket(PRTP_VIDEO_QUEUE queue, PRTP_PACKET packet, int length, PRTPV_
|
||||||
}
|
}
|
||||||
|
|
||||||
// FLAG_EXTENSION is required for all supported versions of GFE.
|
// FLAG_EXTENSION is required for all supported versions of GFE.
|
||||||
LC_ASSERT(packet->header & FLAG_EXTENSION);
|
LC_ASSERT_VT(packet->header & FLAG_EXTENSION);
|
||||||
|
|
||||||
int dataOffset = sizeof(*packet);
|
int dataOffset = sizeof(*packet);
|
||||||
if (packet->header & FLAG_EXTENSION) {
|
if (packet->header & FLAG_EXTENSION) {
|
||||||
|
|
@ -567,11 +567,13 @@ int RtpvAddPacket(PRTP_VIDEO_QUEUE queue, PRTP_PACKET packet, int length, PRTPV_
|
||||||
nvPacket->multiFecFlags = 0x10;
|
nvPacket->multiFecFlags = 0x10;
|
||||||
nvPacket->multiFecBlocks = 0x00;
|
nvPacket->multiFecBlocks = 0x00;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef LC_FUZZING
|
||||||
if (isBefore16(nvPacket->frameIndex, queue->currentFrameNumber)) {
|
if (isBefore16(nvPacket->frameIndex, queue->currentFrameNumber)) {
|
||||||
// Reject frames behind our current frame number
|
// Reject frames behind our current frame number
|
||||||
return RTPF_RET_REJECTED;
|
return RTPF_RET_REJECTED;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
uint32_t fecIndex = (nvPacket->fecInfo & 0x3FF000) >> 12;
|
uint32_t fecIndex = (nvPacket->fecInfo & 0x3FF000) >> 12;
|
||||||
uint8_t fecCurrentBlockNumber = (nvPacket->multiFecBlocks >> 4) & 0x3;
|
uint8_t fecCurrentBlockNumber = (nvPacket->multiFecBlocks >> 4) & 0x3;
|
||||||
|
|
@ -666,7 +668,7 @@ int RtpvAddPacket(PRTP_VIDEO_QUEUE queue, PRTP_PACKET packet, int length, PRTPV_
|
||||||
// The check here looks weird, but that's because we increment the frame number
|
// The check here looks weird, but that's because we increment the frame number
|
||||||
// after successfully processing a frame.
|
// after successfully processing a frame.
|
||||||
if (queue->currentFrameNumber != nvPacket->frameIndex) {
|
if (queue->currentFrameNumber != nvPacket->frameIndex) {
|
||||||
LC_ASSERT(queue->currentFrameNumber < nvPacket->frameIndex);
|
LC_ASSERT_VT(queue->currentFrameNumber < nvPacket->frameIndex);
|
||||||
|
|
||||||
// If the frame immediately preceding this one was lost, we may have already
|
// If the frame immediately preceding this one was lost, we may have already
|
||||||
// reported it using our speculative RFI logic. Don't report it again.
|
// reported it using our speculative RFI logic. Don't report it again.
|
||||||
|
|
@ -707,19 +709,19 @@ int RtpvAddPacket(PRTP_VIDEO_QUEUE queue, PRTP_PACKET packet, int length, PRTPV_
|
||||||
return RTPF_RET_REJECTED;
|
return RTPF_RET_REJECTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
LC_ASSERT(!queue->fecPercentage || U16(packet->sequenceNumber - fecIndex) == queue->bufferLowestSequenceNumber);
|
LC_ASSERT_VT(!queue->fecPercentage || U16(packet->sequenceNumber - fecIndex) == queue->bufferLowestSequenceNumber);
|
||||||
LC_ASSERT((nvPacket->fecInfo & 0xFF0) >> 4 == queue->fecPercentage);
|
LC_ASSERT_VT((nvPacket->fecInfo & 0xFF0) >> 4 == queue->fecPercentage);
|
||||||
LC_ASSERT((nvPacket->fecInfo & 0xFFC00000) >> 22 == queue->bufferDataPackets);
|
LC_ASSERT_VT((nvPacket->fecInfo & 0xFFC00000) >> 22 == queue->bufferDataPackets);
|
||||||
|
|
||||||
// Verify that the legacy non-multi-FEC compatibility code works
|
// Verify that the legacy non-multi-FEC compatibility code works
|
||||||
LC_ASSERT(queue->multiFecCapable || fecCurrentBlockNumber == 0);
|
LC_ASSERT_VT(queue->multiFecCapable || fecCurrentBlockNumber == 0);
|
||||||
LC_ASSERT(queue->multiFecCapable || queue->multiFecLastBlockNumber == 0);
|
LC_ASSERT_VT(queue->multiFecCapable || queue->multiFecLastBlockNumber == 0);
|
||||||
|
|
||||||
// Multi-block FEC details must remain the same within a single frame
|
// Multi-block FEC details must remain the same within a single frame
|
||||||
LC_ASSERT(fecCurrentBlockNumber == queue->multiFecCurrentBlockNumber);
|
LC_ASSERT_VT(fecCurrentBlockNumber == queue->multiFecCurrentBlockNumber);
|
||||||
LC_ASSERT(((nvPacket->multiFecBlocks >> 6) & 0x3) == queue->multiFecLastBlockNumber);
|
LC_ASSERT_VT(((nvPacket->multiFecBlocks >> 6) & 0x3) == queue->multiFecLastBlockNumber);
|
||||||
|
|
||||||
LC_ASSERT((nvPacket->flags & FLAG_EOF) || length - dataOffset == StreamConfig.packetSize);
|
LC_ASSERT_VT((nvPacket->flags & FLAG_EOF) || length - dataOffset == StreamConfig.packetSize);
|
||||||
if (!queuePacket(queue, packetEntry, packet, length, !isBefore16(packet->sequenceNumber, queue->bufferFirstParitySequenceNumber), false)) {
|
if (!queuePacket(queue, packetEntry, packet, length, !isBefore16(packet->sequenceNumber, queue->bufferFirstParitySequenceNumber), false)) {
|
||||||
return RTPF_RET_REJECTED;
|
return RTPF_RET_REJECTED;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -198,27 +198,27 @@ void validateDecodeUnitForPlayback(PDECODE_UNIT decodeUnit) {
|
||||||
// IDR frames always start with codec configuration data
|
// IDR frames always start with codec configuration data
|
||||||
if (NegotiatedVideoFormat & VIDEO_FORMAT_MASK_H264) {
|
if (NegotiatedVideoFormat & VIDEO_FORMAT_MASK_H264) {
|
||||||
// H.264 IDR frames should have an SPS, PPS, then picture data
|
// H.264 IDR frames should have an SPS, PPS, then picture data
|
||||||
LC_ASSERT(decodeUnit->bufferList->bufferType == BUFFER_TYPE_SPS);
|
LC_ASSERT_VT(decodeUnit->bufferList->bufferType == BUFFER_TYPE_SPS);
|
||||||
LC_ASSERT(decodeUnit->bufferList->next != NULL);
|
LC_ASSERT_VT(decodeUnit->bufferList->next != NULL);
|
||||||
LC_ASSERT(decodeUnit->bufferList->next->bufferType == BUFFER_TYPE_PPS);
|
LC_ASSERT_VT(decodeUnit->bufferList->next->bufferType == BUFFER_TYPE_PPS);
|
||||||
LC_ASSERT(decodeUnit->bufferList->next->next != NULL);
|
LC_ASSERT_VT(decodeUnit->bufferList->next->next != NULL);
|
||||||
LC_ASSERT(decodeUnit->bufferList->next->next->bufferType == BUFFER_TYPE_PICDATA);
|
LC_ASSERT_VT(decodeUnit->bufferList->next->next->bufferType == BUFFER_TYPE_PICDATA);
|
||||||
}
|
}
|
||||||
else if (NegotiatedVideoFormat & VIDEO_FORMAT_MASK_H265) {
|
else if (NegotiatedVideoFormat & VIDEO_FORMAT_MASK_H265) {
|
||||||
// HEVC IDR frames should have an VPS, SPS, PPS, then picture data
|
// HEVC IDR frames should have an VPS, SPS, PPS, then picture data
|
||||||
LC_ASSERT(decodeUnit->bufferList->bufferType == BUFFER_TYPE_VPS);
|
LC_ASSERT_VT(decodeUnit->bufferList->bufferType == BUFFER_TYPE_VPS);
|
||||||
LC_ASSERT(decodeUnit->bufferList->next != NULL);
|
LC_ASSERT_VT(decodeUnit->bufferList->next != NULL);
|
||||||
LC_ASSERT(decodeUnit->bufferList->next->bufferType == BUFFER_TYPE_SPS);
|
LC_ASSERT_VT(decodeUnit->bufferList->next->bufferType == BUFFER_TYPE_SPS);
|
||||||
LC_ASSERT(decodeUnit->bufferList->next->next != NULL);
|
LC_ASSERT_VT(decodeUnit->bufferList->next->next != NULL);
|
||||||
LC_ASSERT(decodeUnit->bufferList->next->next->bufferType == BUFFER_TYPE_PPS);
|
LC_ASSERT_VT(decodeUnit->bufferList->next->next->bufferType == BUFFER_TYPE_PPS);
|
||||||
LC_ASSERT(decodeUnit->bufferList->next->next->next != NULL);
|
LC_ASSERT_VT(decodeUnit->bufferList->next->next->next != NULL);
|
||||||
|
|
||||||
// We get 2 sets of VPS, SPS, and PPS NALUs in HDR mode.
|
// We get 2 sets of VPS, SPS, and PPS NALUs in HDR mode.
|
||||||
// FIXME: Should we normalize this or something for clients?
|
// FIXME: Should we normalize this or something for clients?
|
||||||
}
|
}
|
||||||
else if (NegotiatedVideoFormat & VIDEO_FORMAT_MASK_AV1) {
|
else if (NegotiatedVideoFormat & VIDEO_FORMAT_MASK_AV1) {
|
||||||
// We don't parse the AV1 bitstream
|
// We don't parse the AV1 bitstream
|
||||||
LC_ASSERT(decodeUnit->bufferList->bufferType == BUFFER_TYPE_PICDATA);
|
LC_ASSERT_VT(decodeUnit->bufferList->bufferType == BUFFER_TYPE_PICDATA);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
LC_ASSERT(false);
|
LC_ASSERT(false);
|
||||||
|
|
@ -697,7 +697,7 @@ static void processAvcHevcRtpPayloadSlow(PBUFFER_DESC currentPos, PLENTRY_INTERN
|
||||||
while (currentPos->length != 0) {
|
while (currentPos->length != 0) {
|
||||||
// Any NALUs we encounter on the way to the end of the packet must be
|
// Any NALUs we encounter on the way to the end of the packet must be
|
||||||
// reference frame slices or filler data.
|
// reference frame slices or filler data.
|
||||||
LC_ASSERT(isSeqReferenceFrameStart(currentPos) || isFillerDataNal(currentPos));
|
LC_ASSERT_VT(isSeqReferenceFrameStart(currentPos) || isFillerDataNal(currentPos));
|
||||||
skipToNextNalOrEnd(currentPos);
|
skipToNextNalOrEnd(currentPos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -765,7 +765,7 @@ static void processRtpPayload(PNV_VIDEO_PACKET videoPacket, int length,
|
||||||
firstPacket = isFirstPacket(flags, fecCurrentBlockNumber);
|
firstPacket = isFirstPacket(flags, fecCurrentBlockNumber);
|
||||||
lastPacket = (flags & FLAG_EOF) && fecCurrentBlockNumber == fecLastBlockNumber;
|
lastPacket = (flags & FLAG_EOF) && fecCurrentBlockNumber == fecLastBlockNumber;
|
||||||
|
|
||||||
LC_ASSERT((flags & ~(FLAG_SOF | FLAG_EOF | FLAG_CONTAINS_PIC_DATA)) == 0);
|
LC_ASSERT_VT((flags & ~(FLAG_SOF | FLAG_EOF | FLAG_CONTAINS_PIC_DATA)) == 0);
|
||||||
|
|
||||||
streamPacketIndex = videoPacket->streamPacketIndex;
|
streamPacketIndex = videoPacket->streamPacketIndex;
|
||||||
|
|
||||||
|
|
@ -843,10 +843,10 @@ static void processRtpPayload(PNV_VIDEO_PACKET videoPacket, int length,
|
||||||
|
|
||||||
// If this is the first packet, skip the frame header (if one exists)
|
// If this is the first packet, skip the frame header (if one exists)
|
||||||
uint32_t frameHeaderSize;
|
uint32_t frameHeaderSize;
|
||||||
LC_ASSERT(currentPos.length > 0);
|
LC_ASSERT_VT(currentPos.length > 0);
|
||||||
if (firstPacket && currentPos.length > 0) {
|
if (firstPacket && currentPos.length > 0) {
|
||||||
// Parse the frame type from the header
|
// Parse the frame type from the header
|
||||||
LC_ASSERT(currentPos.length >= 4);
|
LC_ASSERT_VT(currentPos.length >= 4);
|
||||||
if (APP_VERSION_AT_LEAST(7, 1, 350) && currentPos.length >= 4) {
|
if (APP_VERSION_AT_LEAST(7, 1, 350) && currentPos.length >= 4) {
|
||||||
switch (currentPos.data[currentPos.offset + 3]) {
|
switch (currentPos.data[currentPos.offset + 3]) {
|
||||||
case 1: // Normal P-frame
|
case 1: // Normal P-frame
|
||||||
|
|
@ -874,7 +874,7 @@ static void processRtpPayload(PNV_VIDEO_PACKET videoPacket, int length,
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
Limelog("Unrecognized frame type: %d", currentPos.data[currentPos.offset + 3]);
|
Limelog("Unrecognized frame type: %d", currentPos.data[currentPos.offset + 3]);
|
||||||
LC_ASSERT(false);
|
LC_ASSERT_VT(false);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -888,7 +888,7 @@ static void processRtpPayload(PNV_VIDEO_PACKET videoPacket, int length,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sunshine can provide host processing latency of the frame
|
// Sunshine can provide host processing latency of the frame
|
||||||
LC_ASSERT(currentPos.length >= 3);
|
LC_ASSERT_VT(currentPos.length >= 3);
|
||||||
if (IS_SUNSHINE() && currentPos.length >= 3) {
|
if (IS_SUNSHINE() && currentPos.length >= 3) {
|
||||||
BYTE_BUFFER bb;
|
BYTE_BUFFER bb;
|
||||||
BbInitializeWrappedBuffer(&bb, currentPos.data, currentPos.offset + 1, 2, BYTE_ORDER_LITTLE);
|
BbInitializeWrappedBuffer(&bb, currentPos.data, currentPos.offset + 1, 2, BYTE_ORDER_LITTLE);
|
||||||
|
|
@ -897,7 +897,7 @@ static void processRtpPayload(PNV_VIDEO_PACKET videoPacket, int length,
|
||||||
|
|
||||||
// Codecs like H.264 and HEVC handle the FEC trailing zero padding just fine, but other
|
// Codecs like H.264 and HEVC handle the FEC trailing zero padding just fine, but other
|
||||||
// codecs need the exact length encoded separately.
|
// codecs need the exact length encoded separately.
|
||||||
LC_ASSERT(currentPos.length >= 6);
|
LC_ASSERT_VT(currentPos.length >= 6);
|
||||||
if (!(NegotiatedVideoFormat & (VIDEO_FORMAT_MASK_H264 | VIDEO_FORMAT_MASK_H265)) && currentPos.length >= 6) {
|
if (!(NegotiatedVideoFormat & (VIDEO_FORMAT_MASK_H264 | VIDEO_FORMAT_MASK_H265)) && currentPos.length >= 6) {
|
||||||
BYTE_BUFFER bb;
|
BYTE_BUFFER bb;
|
||||||
BbInitializeWrappedBuffer(&bb, currentPos.data, currentPos.offset + 4, 2, BYTE_ORDER_LITTLE);
|
BbInitializeWrappedBuffer(&bb, currentPos.data, currentPos.offset + 4, 2, BYTE_ORDER_LITTLE);
|
||||||
|
|
@ -912,7 +912,7 @@ static void processRtpPayload(PNV_VIDEO_PACKET videoPacket, int length,
|
||||||
frameHeaderSize = 8;
|
frameHeaderSize = 8;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
LC_ASSERT(currentPos.data[0] == (char)0x81);
|
LC_ASSERT_VT(currentPos.data[0] == (char)0x81);
|
||||||
frameHeaderSize = 44;
|
frameHeaderSize = 44;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -924,7 +924,7 @@ static void processRtpPayload(PNV_VIDEO_PACKET videoPacket, int length,
|
||||||
frameHeaderSize = 8;
|
frameHeaderSize = 8;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
LC_ASSERT(currentPos.data[0] == (char)0x81);
|
LC_ASSERT_VT(currentPos.data[0] == (char)0x81);
|
||||||
frameHeaderSize = 41;
|
frameHeaderSize = 41;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -936,7 +936,7 @@ static void processRtpPayload(PNV_VIDEO_PACKET videoPacket, int length,
|
||||||
frameHeaderSize = 8;
|
frameHeaderSize = 8;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
LC_ASSERT(currentPos.data[0] == (char)0x81);
|
LC_ASSERT_VT(currentPos.data[0] == (char)0x81);
|
||||||
frameHeaderSize = 24;
|
frameHeaderSize = 24;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -957,7 +957,7 @@ static void processRtpPayload(PNV_VIDEO_PACKET videoPacket, int length,
|
||||||
frameHeaderSize = 0;
|
frameHeaderSize = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
LC_ASSERT(currentPos.length >= frameHeaderSize);
|
LC_ASSERT_VT(currentPos.length >= frameHeaderSize);
|
||||||
if (currentPos.length >= frameHeaderSize) {
|
if (currentPos.length >= frameHeaderSize) {
|
||||||
// Skip past the frame header
|
// Skip past the frame header
|
||||||
currentPos.offset += frameHeaderSize;
|
currentPos.offset += frameHeaderSize;
|
||||||
|
|
@ -969,7 +969,7 @@ static void processRtpPayload(PNV_VIDEO_PACKET videoPacket, int length,
|
||||||
// The Annex B NALU start prefix must be next
|
// The Annex B NALU start prefix must be next
|
||||||
if (!getAnnexBStartSequence(¤tPos, NULL)) {
|
if (!getAnnexBStartSequence(¤tPos, NULL)) {
|
||||||
// If we aren't starting on a start prefix, something went wrong.
|
// If we aren't starting on a start prefix, something went wrong.
|
||||||
LC_ASSERT(false);
|
LC_ASSERT_VT(false);
|
||||||
|
|
||||||
// For release builds, we will try to recover by searching for one.
|
// For release builds, we will try to recover by searching for one.
|
||||||
// This mimics the way most decoders handle this situation.
|
// This mimics the way most decoders handle this situation.
|
||||||
|
|
@ -1022,11 +1022,11 @@ static void processRtpPayload(PNV_VIDEO_PACKET videoPacket, int length,
|
||||||
// of trailing zero padding like H.264/HEVC Annex B bitstream parsers are.
|
// of trailing zero padding like H.264/HEVC Annex B bitstream parsers are.
|
||||||
if (lastPacket) {
|
if (lastPacket) {
|
||||||
// The payload length includes the frame header, so it cannot be smaller than that
|
// The payload length includes the frame header, so it cannot be smaller than that
|
||||||
LC_ASSERT(lastPacketPayloadLength > frameHeaderSize);
|
LC_ASSERT_VT(lastPacketPayloadLength > frameHeaderSize);
|
||||||
|
|
||||||
// The payload length cannot be smaller than the actual received payload
|
// The payload length cannot be smaller than the actual received payload
|
||||||
// NB: currentPos.length is already adjusted to exclude the frameHeaderSize from above
|
// NB: currentPos.length is already adjusted to exclude the frameHeaderSize from above
|
||||||
LC_ASSERT(lastPacketPayloadLength - frameHeaderSize <= currentPos.length);
|
LC_ASSERT_VT(lastPacketPayloadLength - frameHeaderSize <= currentPos.length);
|
||||||
|
|
||||||
// If the payload length is valid, truncate the packet. If not, discard this frame.
|
// If the payload length is valid, truncate the packet. If not, discard this frame.
|
||||||
if (lastPacketPayloadLength > frameHeaderSize && lastPacketPayloadLength - frameHeaderSize <= currentPos.length) {
|
if (lastPacketPayloadLength > frameHeaderSize && lastPacketPayloadLength - frameHeaderSize <= currentPos.length) {
|
||||||
|
|
|
||||||
|
|
@ -135,6 +135,7 @@ static void VideoReceiveThreadProc(void* context) {
|
||||||
firstDataTimeMs = PltGetMillis();
|
firstDataTimeMs = PltGetMillis();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef LC_FUZZING
|
||||||
if (!receivedFullFrame) {
|
if (!receivedFullFrame) {
|
||||||
uint64_t now = PltGetMillis();
|
uint64_t now = PltGetMillis();
|
||||||
|
|
||||||
|
|
@ -144,6 +145,7 @@ static void VideoReceiveThreadProc(void* context) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (err < (int)sizeof(RTP_PACKET)) {
|
if (err < (int)sizeof(RTP_PACKET)) {
|
||||||
// Runt packet
|
// Runt packet
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue