forked from sipsorcery-org/sipsorcery
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathTransportWideCCExtension.cs
More file actions
125 lines (109 loc) · 4.74 KB
/
TransportWideCCExtension.cs
File metadata and controls
125 lines (109 loc) · 4.74 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
/*
* File: TransportWideCCExtension.cs
*
* Description:
* Implements the Transport Wide Congestion Control (TWCC) RTP header extension.
* This extension carries a 16-bit sequence number and adheres to the IETF draft:
* http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
* It provides functionality to marshal and unmarshal the TWCC header extension.
*
* Author: Sean Tearney
* Date: 2025-02-22
*
* License: BSD 3-Clause "New" or "Revised" License, see included LICENSE.md file.
*
* Change Log:
* 2025-02-20 Initial creation.
*/
using System;
using System.Buffers.Binary;
namespace SIPSorcery.Net
{
/// <summary>
/// TransportWideCCExtension implements the Transport Wide Congestion Control (TWCC)
/// RTP header extension as defined in:
/// http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
///
/// This extension carries a 16-bit sequence number (2 bytes of payload).
/// The one-byte header is constructed as (id << 4) | (extensionSize - 1).
/// </summary>
public class TransportWideCCExtension : RTPHeaderExtension
{
//
public const string RTP_HEADER_EXTENSION_URI = "http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01";
public override bool MatchesExtension(string uri)
{
switch (uri.ToLower())
{
case RTP_HEADER_EXTENSION_URI:
case "urn:ietf:params:rtp-hdrext:transport-wide-cc": //official urn registered with IANA
case "http://www.webrtc.org/experiments/rtp-hdrext/transport-wide-cc-02":
return true;
}
return false;
}
internal const int RTP_HEADER_EXTENSION_SIZE = 2; // TWCC payload: 2 bytes for sequence number.
public TransportWideCCExtension(int id, string uri)
: base(id, uri, RTP_HEADER_EXTENSION_SIZE, RTPHeaderExtensionType.OneByte)
{
}
/// <summary>
/// The TWCC sequence number.
/// </summary>
public ushort SequenceNumber { get; private set; }
/// <summary>
/// Constructs a TWCC header extension with the negotiated extension id.
/// </summary>
/// <param name="id">The negotiated header extension id.</param>
public TransportWideCCExtension(int id)
: base(id, RTP_HEADER_EXTENSION_URI, RTP_HEADER_EXTENSION_SIZE, RTPHeaderExtensionType.OneByte)
{
}
/// <summary>
/// Generic setter override. Expects a ushort representing the sequence number.
/// </summary>
/// <param name="value">The TWCC sequence number as an object (ushort).</param>
public override void Set(object value)
{
if (value is ushort seq)
{
SequenceNumber = seq;
}
else
{
throw new ArgumentException("Value must be a ushort representing the TWCC sequence number", nameof(value));
}
}
/// <summary>
/// Marshals the TWCC header extension to a byte array.
/// The first byte is the one-byte header (with id and length) and
/// the following two bytes are the sequence number in network (big-endian) order.
/// </summary>
/// <returns>A byte array containing the marshalled TWCC header extension.</returns>
public override byte[] Marshal()
{
// Construct the one-byte header. (id << 4) | (extensionSize - 1)
byte headerByte = (byte)((Id << 4) | (RTP_HEADER_EXTENSION_SIZE - 1));
// Convert the sequence number to a 2-byte array in big-endian order.
byte[] seqBytes = new byte[2];
BinaryPrimitives.WriteUInt16BigEndian(seqBytes, SequenceNumber);
return new byte[] { headerByte, seqBytes[0], seqBytes[1] };
}
/// <summary>
/// Unmarshals the TWCC header extension from the provided data.
/// </summary>
/// <param name="header">The RTP header (if additional context is needed).</param>
/// <param name="data">The extension payload (should be exactly 2 bytes).</param>
/// <returns>The extracted TWCC sequence number (as a ushort).</returns>
public override object Unmarshal(RTPHeader header, byte[] data)
{
if (data.Length != RTP_HEADER_EXTENSION_SIZE)
{
throw new ArgumentException($"Invalid TWCC extension payload size, expected {RTP_HEADER_EXTENSION_SIZE} but got {data.Length}.");
}
// Combine the two bytes into a ushort (big-endian).
ushort seqNum = (ushort)((data[0] << 8) | data[1]);
return seqNum;
}
}
}