mirror of
https://github.com/moonlight-stream/moonlight-android.git
synced 2025-07-20 19:42:45 +00:00
Fix sequencing errors that lead to drops in audio or video for potentially long periods under the right conditions
This commit is contained in:
parent
33ffbe151f
commit
cc92f3829e
@ -45,7 +45,7 @@ public class RtpReorderQueue {
|
|||||||
|
|
||||||
if (nextRtpSequenceNumber != Short.MAX_VALUE) {
|
if (nextRtpSequenceNumber != Short.MAX_VALUE) {
|
||||||
// Don't queue packets we're already ahead of
|
// Don't queue packets we're already ahead of
|
||||||
if (seq < nextRtpSequenceNumber) {
|
if (SequenceHelper.isBeforeSigned(seq, nextRtpSequenceNumber, false)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,11 +88,15 @@ public class RtpReorderQueue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private RtpQueueEntry getEntryByLowestSeq() {
|
private RtpQueueEntry getEntryByLowestSeq() {
|
||||||
short nextSeq = Short.MAX_VALUE;
|
if (queue.isEmpty()) {
|
||||||
RtpQueueEntry lowestSeqEntry = null;
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
RtpQueueEntry lowestSeqEntry = queue.getFirst();
|
||||||
|
short nextSeq = lowestSeqEntry.sequenceNumber;
|
||||||
|
|
||||||
for (RtpQueueEntry entry : queue) {
|
for (RtpQueueEntry entry : queue) {
|
||||||
if (entry.sequenceNumber < nextSeq) {
|
if (SequenceHelper.isBeforeSigned(entry.sequenceNumber, nextSeq, true)) {
|
||||||
lowestSeqEntry = entry;
|
lowestSeqEntry = entry;
|
||||||
nextSeq = entry.sequenceNumber;
|
nextSeq = entry.sequenceNumber;
|
||||||
}
|
}
|
||||||
@ -140,7 +144,7 @@ public class RtpReorderQueue {
|
|||||||
|
|
||||||
public RtpQueueStatus addPacket(RtpPacketFields packet) {
|
public RtpQueueStatus addPacket(RtpPacketFields packet) {
|
||||||
if (nextRtpSequenceNumber != Short.MAX_VALUE &&
|
if (nextRtpSequenceNumber != Short.MAX_VALUE &&
|
||||||
packet.getRtpSequenceNumber() < nextRtpSequenceNumber) {
|
SequenceHelper.isBeforeSigned(packet.getRtpSequenceNumber(), nextRtpSequenceNumber, false)) {
|
||||||
// Reject packets behind our current sequence number
|
// Reject packets behind our current sequence number
|
||||||
return RtpQueueStatus.REJECTED;
|
return RtpQueueStatus.REJECTED;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,20 @@
|
|||||||
|
package com.limelight.nvstream.av;
|
||||||
|
|
||||||
|
public class SequenceHelper {
|
||||||
|
public static boolean isBeforeSigned(int numA, int numB, boolean ambiguousCase) {
|
||||||
|
// This should be the common case for most callers
|
||||||
|
if (numA == numB) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If numA and numB have the same signs,
|
||||||
|
// we can just do a regular comparison.
|
||||||
|
if ((numA < 0 && numB < 0) || (numA >= 0 && numB >= 0)) {
|
||||||
|
return numA < numB;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// The sign switch is ambiguous
|
||||||
|
return ambiguousCase;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -4,6 +4,7 @@ import com.limelight.LimeLog;
|
|||||||
import com.limelight.nvstream.av.ByteBufferDescriptor;
|
import com.limelight.nvstream.av.ByteBufferDescriptor;
|
||||||
import com.limelight.nvstream.av.PopulatedBufferList;
|
import com.limelight.nvstream.av.PopulatedBufferList;
|
||||||
import com.limelight.nvstream.av.RtpPacket;
|
import com.limelight.nvstream.av.RtpPacket;
|
||||||
|
import com.limelight.nvstream.av.SequenceHelper;
|
||||||
|
|
||||||
public class AudioDepacketizer {
|
public class AudioDepacketizer {
|
||||||
|
|
||||||
@ -88,7 +89,7 @@ public class AudioDepacketizer {
|
|||||||
|
|
||||||
// Only tell the decoder if we got packets ahead of what we expected
|
// Only tell the decoder if we got packets ahead of what we expected
|
||||||
// If the packet is behind the current sequence number, drop it
|
// If the packet is behind the current sequence number, drop it
|
||||||
if (seq > (short)(lastSequenceNumber + 1)) {
|
if (!SequenceHelper.isBeforeSigned(seq, (short)(lastSequenceNumber + 1), false)) {
|
||||||
decodeData(null, 0, 0);
|
decodeData(null, 0, 0);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -7,6 +7,7 @@ import com.limelight.nvstream.av.ByteBufferDescriptor;
|
|||||||
import com.limelight.nvstream.av.DecodeUnit;
|
import com.limelight.nvstream.av.DecodeUnit;
|
||||||
import com.limelight.nvstream.av.ConnectionStatusListener;
|
import com.limelight.nvstream.av.ConnectionStatusListener;
|
||||||
import com.limelight.nvstream.av.PopulatedBufferList;
|
import com.limelight.nvstream.av.PopulatedBufferList;
|
||||||
|
import com.limelight.nvstream.av.SequenceHelper;
|
||||||
|
|
||||||
public class VideoDepacketizer {
|
public class VideoDepacketizer {
|
||||||
|
|
||||||
@ -232,12 +233,12 @@ public class VideoDepacketizer {
|
|||||||
|
|
||||||
// Drop duplicates or re-ordered packets
|
// Drop duplicates or re-ordered packets
|
||||||
int streamPacketIndex = packet.getStreamPacketIndex();
|
int streamPacketIndex = packet.getStreamPacketIndex();
|
||||||
if (streamPacketIndex < (int)(lastPacketInStream + 1)) {
|
if (SequenceHelper.isBeforeSigned((short)streamPacketIndex, (short)(lastPacketInStream + 1), false)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Drop packets from a previously completed frame
|
// Drop packets from a previously completed frame
|
||||||
if (frameIndex < nextFrameNumber) {
|
if (SequenceHelper.isBeforeSigned(frameIndex, nextFrameNumber, false)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -279,7 +280,7 @@ public class VideoDepacketizer {
|
|||||||
// miss one in between
|
// miss one in between
|
||||||
else if (firstPacket) {
|
else if (firstPacket) {
|
||||||
// Make sure this is the next consecutive frame
|
// Make sure this is the next consecutive frame
|
||||||
if (nextFrameNumber < frameIndex) {
|
if (SequenceHelper.isBeforeSigned(nextFrameNumber, frameIndex, true)) {
|
||||||
LimeLog.warning("Network dropped an entire frame");
|
LimeLog.warning("Network dropped an entire frame");
|
||||||
nextFrameNumber = frameIndex;
|
nextFrameNumber = frameIndex;
|
||||||
|
|
||||||
@ -287,7 +288,7 @@ public class VideoDepacketizer {
|
|||||||
waitingForNextSuccessfulFrame = true;
|
waitingForNextSuccessfulFrame = true;
|
||||||
dropAvcFrameState();
|
dropAvcFrameState();
|
||||||
}
|
}
|
||||||
else if (nextFrameNumber > frameIndex){
|
else if (nextFrameNumber != frameIndex) {
|
||||||
// Duplicate packet or FEC dup
|
// Duplicate packet or FEC dup
|
||||||
decodingFrame = false;
|
decodingFrame = false;
|
||||||
return;
|
return;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user