Skip to content

Update RTCPTWCCFeedback.cs#1640

Closed
ispysoftware wants to merge 3 commits into
sipsorcery-org:masterfrom
ispysoftware:patch-4
Closed

Update RTCPTWCCFeedback.cs#1640
ispysoftware wants to merge 3 commits into
sipsorcery-org:masterfrom
ispysoftware:patch-4

Conversation

@ispysoftware

Copy link
Copy Markdown
Contributor

Fix parsing bugs

Fix parsing bugs
@sipsorcery sipsorcery added the rtp label May 29, 2026

@sipsorcery sipsorcery left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The BitsToStatus method is missing.

@ispysoftware

Copy link
Copy Markdown
Contributor Author

Ah yes sorry about that

Comment on lines +151 to +159
private static readonly Dictionary<TWCCPacketStatusType, ushort> StatusToBits = new Dictionary<TWCCPacketStatusType, ushort>
{
{ TWCCPacketStatusType.NotReceived, 0 },
{ TWCCPacketStatusType.ReceivedSmallDelta, 1 },
{ TWCCPacketStatusType.ReceivedLargeDelta, 2 },
{ TWCCPacketStatusType.Reserved, 3 }
};

private static readonly Dictionary<ushort, TWCCPacketStatusType> BitsToStatus = StatusToBits.ToDictionary(kvp => kvp.Value, kvp => kvp.Key);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider using FrozenDictionary<TKey,TValue> for performant unmodifiable dictionaries.

But, for this use case, a switch expression would be the best option.

Comment on lines 329 to 332
int expectedDeltaCount = statusSymbols.Count(s =>
s == TWCCPacketStatusType.ReceivedSmallDelta ||
s == TWCCPacketStatusType.ReceivedLargeDelta);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

expectedDeltaCount doesn't seem to be used.

This adds an unnecessary enumeration of statusSymbols with delegate invocation.


private List<TWCCPacketStatusType> ParseStatusChunks(byte[] packet, ref int offset)
{
var statusSymbols = new List<TWCCPacketStatusType>();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Initialize the list with the know maximum size to avoid allocations and memory copy on growth.

            var statusSymbols = new List<TWCCPacketStatusType>(PacketStatusCount);


private (List<int> deltaValues, int lastOffset) ParseDeltaValues(byte[] packet, int offset, List<TWCCPacketStatusType> statusSymbols)
{
var deltaValues = new List<int>();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Initialize the list with the know maximum size to avoid allocations and memory copy on growth.

            var deltaValues = new List<int>(statusSymbols.Count);

List<TWCCPacketStatusType> symbols = PacketStatuses.Select(ps => ps.Status).ToList();

// Reconstruct packet status chunks.
List<ushort> chunks = new List<ushort>();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Initialize the list with the know maximum size to avoid allocations and memory copy on growth.

// Worst-case chunk count is all 2-bit vector chunks (7 symbols per chunk).
int chunkCapacity = (symbolCount + 6) / 7;
List<ushort> chunks = new List<ushort>(chunkCapacity);

public byte[] GetBytes()
{
// Build a list of TWCCPacketStatusType from PacketStatuses.
List<TWCCPacketStatusType> symbols = PacketStatuses.Select(ps => ps.Status).ToList();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using LINQ erases the optimizations that List<T> have. Also grows a list that is known to have a maximum and uses delegate invocation for that.

int symbolCount = PacketStatuses.Count;
var symbols = new List<TWCCPacketStatusType>(symbolCount);

int deltaBytesCapacity = 0;
foreach (var ps in PacketStatuses)
{
    symbols.Add(ps.Status);

    if (ps.Status == TWCCPacketStatusType.ReceivedSmallDelta)
    {
        deltaBytesCapacity += 1;
    }
    else if (ps.Status == TWCCPacketStatusType.ReceivedLargeDelta)
    {
        deltaBytesCapacity += 2;
    }
}

Comment on lines +214 to +217
if (!BitsToStatus.TryGetValue(statusBits, out TWCCPacketStatusType symbol))
{
throw new ArgumentException($"Invalid status bits in run length chunk: {statusBits}");
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider a switch expression.
Doesn't require dictionary allocation and lookup,

Suggested change
if (!BitsToStatus.TryGetValue(statusBits, out TWCCPacketStatusType symbol))
{
throw new ArgumentException($"Invalid status bits in run length chunk: {statusBits}");
}
TWCCPacketStatusType symbol = statusBits switch
{
0 => TWCCPacketStatusType.NotReceived,
1 => TWCCPacketStatusType.ReceivedSmallDelta,
2 => TWCCPacketStatusType.ReceivedLargeDelta,
3 => TWCCPacketStatusType.Reserved,
_ => throw new ArgumentException($"Invalid status bits in run length chunk: {statusBits}")
};

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants