From b871b65cd06e10f906bc9c643ec87461f7a9d814 Mon Sep 17 00:00:00 2001 From: Tomasz Heimowski Date: Mon, 4 Mar 2024 11:59:10 +0100 Subject: [PATCH 1/9] Add abs-send-time to each RTP packet --- src/net/RTP/MediaStream.cs | 28 ++++++++++++++++++++++++++++ src/net/WebRTC/RTCPeerConnection.cs | 8 +++++++- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/src/net/RTP/MediaStream.cs b/src/net/RTP/MediaStream.cs index e23e3ff49..a33e7764a 100644 --- a/src/net/RTP/MediaStream.cs +++ b/src/net/RTP/MediaStream.cs @@ -366,6 +366,12 @@ protected void SendRtpRaw(byte[] data, uint timestamp, int markerBit, int payloa rtpPacket.Header.MarkerBit = markerBit; rtpPacket.Header.PayloadType = payloadType; + // abs-send-time + rtpPacket.Header.HeaderExtensionFlag = 1; + rtpPacket.Header.ExtensionProfile = 0xBEDE; // one byte extension + rtpPacket.Header.ExtensionLength = 1; + rtpPacket.Header.ExtensionPayload = AbsSendTime(); + Buffer.BlockCopy(data, 0, rtpPacket.Payload, 0, data.Length); var rtpBuffer = rtpPacket.GetBytes(); @@ -393,6 +399,28 @@ protected void SendRtpRaw(byte[] data, uint timestamp, int markerBit, int payloa } } + private byte[] AbsSendTime() + { + var t = DateTimeOffset.Now; + ulong u = (ulong)((t - DateTimeOffset.UnixEpoch).Ticks * 100L); + var s = u / (ulong)1e9; + s += 0x83AA7E80UL; + var f = u % (ulong)1e9; + f <<= 32; + f /= (ulong)1e9; + s <<= 32; + var ntp = s | f; + var abs = ntp >> 14; + + return new byte[] + { + 0x22, // ID = 2; L = 2 (3-1) + (byte)((abs & 0xff0000UL) >> 16), + (byte)((abs & 0xff00UL) >> 8), + (byte)(abs & 0xffUL) + }; + } + /// /// Allows additional control for sending raw RTP payloads. No framing or other processing is carried out. /// diff --git a/src/net/WebRTC/RTCPeerConnection.cs b/src/net/WebRTC/RTCPeerConnection.cs index d85ecda9d..e038d118a 100644 --- a/src/net/WebRTC/RTCPeerConnection.cs +++ b/src/net/WebRTC/RTCPeerConnection.cs @@ -1143,7 +1143,13 @@ void AddIceCandidates(SDPMediaAnnouncement announcement) SDPMediaAnnouncement announcement = new SDPMediaAnnouncement( mediaStream.LocalTrack.Kind, SDP.IGNORE_RTP_PORT_NUMBER, - mediaStream.LocalTrack.Capabilities); + mediaStream.LocalTrack.Capabilities) + { + HeaderExtensions = new Dictionary + { + {2, new RTPHeaderExtension(2, "http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time")} + } + }; announcement.Transport = RTP_MEDIA_PROFILE; announcement.Connection = new SDPConnectionInformation(IPAddress.Any); From b202de3ad8571021432a83890c66fb2d5b706e3e Mon Sep 17 00:00:00 2001 From: Tomasz Heimowski Date: Mon, 11 Mar 2024 11:40:52 +0100 Subject: [PATCH 2/9] Add a=rtcp-fb with goog-remb to SDP --- src/net/SDP/SDP.cs | 6 +++--- src/net/SDP/SDPAudioVideoMediaFormat.cs | 8 ++++++++ src/net/SDP/SDPMediaAnnouncement.cs | 14 ++++++++++---- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/src/net/SDP/SDP.cs b/src/net/SDP/SDP.cs index 3d93ff8e1..bd155a750 100644 --- a/src/net/SDP/SDP.cs +++ b/src/net/SDP/SDP.cs @@ -434,13 +434,13 @@ public static SDP ParseSDPDescription(string sdpDescription) } break; - case var l when l.StartsWith(SDPMediaAnnouncement.MEDIA_FORMAT_ATTRIBUE_PREFIX): + case var l when l.StartsWith(SDPMediaAnnouncement.MEDIA_FORMAT_ATTRIBUTE_PREFIX): if (activeAnnouncement != null) { if (activeAnnouncement.Media == SDPMediaTypesEnum.audio || activeAnnouncement.Media == SDPMediaTypesEnum.video) { // Parse the rtpmap attribute for audio/video announcements. - Match formatAttributeMatch = Regex.Match(sdpLineTrimmed, SDPMediaAnnouncement.MEDIA_FORMAT_ATTRIBUE_PREFIX + @"(?\d+)\s+(?.*)$"); + Match formatAttributeMatch = Regex.Match(sdpLineTrimmed, SDPMediaAnnouncement.MEDIA_FORMAT_ATTRIBUTE_PREFIX + @"(?\d+)\s+(?.*)$"); if (formatAttributeMatch.Success) { string formatID = formatAttributeMatch.Result("${id}"); @@ -471,7 +471,7 @@ public static SDP ParseSDPDescription(string sdpDescription) else { // Parse the rtpmap attribute for NON audio/video announcements. - Match formatAttributeMatch = Regex.Match(sdpLineTrimmed, SDPMediaAnnouncement.MEDIA_FORMAT_ATTRIBUE_PREFIX + @"(?\S+)\s+(?.*)$"); + Match formatAttributeMatch = Regex.Match(sdpLineTrimmed, SDPMediaAnnouncement.MEDIA_FORMAT_ATTRIBUTE_PREFIX + @"(?\S+)\s+(?.*)$"); if (formatAttributeMatch.Success) { string formatID = formatAttributeMatch.Result("${id}"); diff --git a/src/net/SDP/SDPAudioVideoMediaFormat.cs b/src/net/SDP/SDPAudioVideoMediaFormat.cs index e01fbee39..f8b7dcdd8 100644 --- a/src/net/SDP/SDPAudioVideoMediaFormat.cs +++ b/src/net/SDP/SDPAudioVideoMediaFormat.cs @@ -96,6 +96,14 @@ public struct SDPAudioVideoMediaFormat /// public string Fmtp { get; } + public IEnumerable SupportedRtcpFeedbackMessages + { + get + { + yield return "goog-remb"; + } + } + /// /// The standard name of the media format. /// diff --git a/src/net/SDP/SDPMediaAnnouncement.cs b/src/net/SDP/SDPMediaAnnouncement.cs index 85150bd87..aab7e2b02 100644 --- a/src/net/SDP/SDPMediaAnnouncement.cs +++ b/src/net/SDP/SDPMediaAnnouncement.cs @@ -70,7 +70,8 @@ public SDPSsrcAttribute(uint ssrc, string cname, string groupID) public class SDPMediaAnnouncement { public const string MEDIA_EXTENSION_MAP_ATTRIBUE_PREFIX = "a=extmap:"; - public const string MEDIA_FORMAT_ATTRIBUE_PREFIX = "a=rtpmap:"; + public const string MEDIA_FORMAT_ATTRIBUTE_PREFIX = "a=rtpmap:"; + public const string MEDIA_FORMAT_FEEDBACK_PREFIX = "a=rtcp-fb:"; public const string MEDIA_FORMAT_PARAMETERS_ATTRIBUE_PREFIX = "a=fmtp:"; public const string MEDIA_FORMAT_SSRC_ATTRIBUE_PREFIX = "a=ssrc:"; public const string MEDIA_FORMAT_SSRC_GROUP_ATTRIBUE_PREFIX = "a=ssrc-group:"; @@ -422,7 +423,7 @@ public string GetFormatListAttributesToString() { if (appFormat.Value.Rtpmap != null) { - sb.Append($"{MEDIA_FORMAT_ATTRIBUE_PREFIX}{appFormat.Key} {appFormat.Value.Rtpmap}{m_CRLF}"); + sb.Append($"{MEDIA_FORMAT_ATTRIBUTE_PREFIX}{appFormat.Key} {appFormat.Value.Rtpmap}{m_CRLF}"); } if (appFormat.Value.Fmtp != null) @@ -474,11 +475,16 @@ public string GetFormatListAttributesToString() { // Well known media formats are not required to add an rtpmap but we do so any way as some SIP // stacks don't work without it. - formatAttributes += MEDIA_FORMAT_ATTRIBUE_PREFIX + mediaFormat.ID + " " + mediaFormat.Name() + "/" + mediaFormat.ClockRate() + m_CRLF; + formatAttributes += MEDIA_FORMAT_ATTRIBUTE_PREFIX + mediaFormat.ID + " " + mediaFormat.Name() + "/" + mediaFormat.ClockRate() + m_CRLF; } else { - formatAttributes += MEDIA_FORMAT_ATTRIBUE_PREFIX + mediaFormat.ID + " " + mediaFormat.Rtpmap + m_CRLF; + formatAttributes += MEDIA_FORMAT_ATTRIBUTE_PREFIX + mediaFormat.ID + " " + mediaFormat.Rtpmap + m_CRLF; + } + + foreach (var rtcpFeedbackMessage in mediaFormat.SupportedRtcpFeedbackMessages) + { + formatAttributes += MEDIA_FORMAT_FEEDBACK_PREFIX + mediaFormat.ID + " " + rtcpFeedbackMessage + m_CRLF; } if (mediaFormat.Fmtp != null) From aae14c3c5a49c223da8d1c0e6d9a31a176f1a541 Mon Sep 17 00:00:00 2001 From: Tomasz Heimowski Date: Mon, 11 Mar 2024 11:48:47 +0100 Subject: [PATCH 3/9] Move Header Extensions declaration to SDPMediaAnnouncement constructor --- src/net/SDP/SDPMediaAnnouncement.cs | 13 +++++++++++++ src/net/WebRTC/RTCPeerConnection.cs | 12 +++--------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/net/SDP/SDPMediaAnnouncement.cs b/src/net/SDP/SDPMediaAnnouncement.cs index aab7e2b02..0868a37a0 100644 --- a/src/net/SDP/SDPMediaAnnouncement.cs +++ b/src/net/SDP/SDPMediaAnnouncement.cs @@ -81,6 +81,9 @@ public class SDPMediaAnnouncement public const string MEDIA_FORMAT_PATH_MSRP_PREFIX = "a=path:msrp:"; public const string MEDIA_FORMAT_PATH_ACCEPT_TYPES_PREFIX = "a=accept-types:"; public const string TIAS_BANDWIDTH_ATTRIBUE_PREFIX = "b=TIAS:"; + private const int RTP_HEADER_EXTENSION_ID_ABS_SEND_TIME = 2; + private const string RTP_HEADER_EXTENSION_URI_ABS_SEND_TIME = "http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time"; + public const MediaStreamStatusEnum DEFAULT_STREAM_STATUS = MediaStreamStatusEnum.SendRecv; public const string m_CRLF = "\r\n"; @@ -207,6 +210,16 @@ public SDPMediaAnnouncement(SDPMediaTypesEnum mediaType, int port, List + { + { + RTP_HEADER_EXTENSION_ID_ABS_SEND_TIME, + new RTPHeaderExtension( + RTP_HEADER_EXTENSION_ID_ABS_SEND_TIME, + RTP_HEADER_EXTENSION_URI_ABS_SEND_TIME) + } + }; } public SDPMediaAnnouncement(SDPMediaTypesEnum mediaType, int port, List appMediaFormats) diff --git a/src/net/WebRTC/RTCPeerConnection.cs b/src/net/WebRTC/RTCPeerConnection.cs index e038d118a..55b025be6 100644 --- a/src/net/WebRTC/RTCPeerConnection.cs +++ b/src/net/WebRTC/RTCPeerConnection.cs @@ -1141,15 +1141,9 @@ void AddIceCandidates(SDPMediaAnnouncement announcement) else { SDPMediaAnnouncement announcement = new SDPMediaAnnouncement( - mediaStream.LocalTrack.Kind, - SDP.IGNORE_RTP_PORT_NUMBER, - mediaStream.LocalTrack.Capabilities) - { - HeaderExtensions = new Dictionary - { - {2, new RTPHeaderExtension(2, "http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time")} - } - }; + mediaStream.LocalTrack.Kind, + SDP.IGNORE_RTP_PORT_NUMBER, + mediaStream.LocalTrack.Capabilities); announcement.Transport = RTP_MEDIA_PROFILE; announcement.Connection = new SDPConnectionInformation(IPAddress.Any); From 317a98e96a445a1ca16666fd4a62bc95b1cf3b0e Mon Sep 17 00:00:00 2001 From: Tomasz Heimowski Date: Mon, 11 Mar 2024 11:56:05 +0100 Subject: [PATCH 4/9] UnixEpoch not available on lower frameworks --- src/net/RTP/MediaStream.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/net/RTP/MediaStream.cs b/src/net/RTP/MediaStream.cs index a33e7764a..4fb9aff8d 100644 --- a/src/net/RTP/MediaStream.cs +++ b/src/net/RTP/MediaStream.cs @@ -399,10 +399,13 @@ protected void SendRtpRaw(byte[] data, uint timestamp, int markerBit, int payloa } } + // DateTimeOffset.UnixEpoch only available in newer target frameworks + private static readonly DateTimeOffset UnixEpoch = new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero); + private byte[] AbsSendTime() { var t = DateTimeOffset.Now; - ulong u = (ulong)((t - DateTimeOffset.UnixEpoch).Ticks * 100L); + ulong u = (ulong)((t - UnixEpoch).Ticks * 100L); var s = u / (ulong)1e9; s += 0x83AA7E80UL; var f = u % (ulong)1e9; From d74894a5212a1c06383175fb64da3719ea149fe1 Mon Sep 17 00:00:00 2001 From: Tomasz Heimowski Date: Mon, 11 Mar 2024 12:07:48 +0100 Subject: [PATCH 5/9] Move AbsSendTime to RTPHeader class --- src/net/RTP/MediaStream.cs | 30 +----------------------------- src/net/RTP/RTPHeader.cs | 36 +++++++++++++++++++++++++++++++++++- 2 files changed, 36 insertions(+), 30 deletions(-) diff --git a/src/net/RTP/MediaStream.cs b/src/net/RTP/MediaStream.cs index 4fb9aff8d..b4dfd39f1 100644 --- a/src/net/RTP/MediaStream.cs +++ b/src/net/RTP/MediaStream.cs @@ -367,10 +367,7 @@ protected void SendRtpRaw(byte[] data, uint timestamp, int markerBit, int payloa rtpPacket.Header.PayloadType = payloadType; // abs-send-time - rtpPacket.Header.HeaderExtensionFlag = 1; - rtpPacket.Header.ExtensionProfile = 0xBEDE; // one byte extension - rtpPacket.Header.ExtensionLength = 1; - rtpPacket.Header.ExtensionPayload = AbsSendTime(); + rtpPacket.Header.AddAbsSendTimeExtension(); Buffer.BlockCopy(data, 0, rtpPacket.Payload, 0, data.Length); @@ -399,31 +396,6 @@ protected void SendRtpRaw(byte[] data, uint timestamp, int markerBit, int payloa } } - // DateTimeOffset.UnixEpoch only available in newer target frameworks - private static readonly DateTimeOffset UnixEpoch = new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero); - - private byte[] AbsSendTime() - { - var t = DateTimeOffset.Now; - ulong u = (ulong)((t - UnixEpoch).Ticks * 100L); - var s = u / (ulong)1e9; - s += 0x83AA7E80UL; - var f = u % (ulong)1e9; - f <<= 32; - f /= (ulong)1e9; - s <<= 32; - var ntp = s | f; - var abs = ntp >> 14; - - return new byte[] - { - 0x22, // ID = 2; L = 2 (3-1) - (byte)((abs & 0xff0000UL) >> 16), - (byte)((abs & 0xff00UL) >> 8), - (byte)(abs & 0xffUL) - }; - } - /// /// Allows additional control for sending raw RTP payloads. No framing or other processing is carried out. /// diff --git a/src/net/RTP/RTPHeader.cs b/src/net/RTP/RTPHeader.cs index 9ac9698ff..21d50f640 100644 --- a/src/net/RTP/RTPHeader.cs +++ b/src/net/RTP/RTPHeader.cs @@ -28,6 +28,7 @@ public class RTPHeader public const int MIN_HEADER_LEN = 12; public const int RTP_VERSION = 2; + private const int ONE_BYTE_EXTENSION_PROFILE = 0xBEDE; public int Version = RTP_VERSION; // 2 bits. public int PaddingFlag = 0; // 1 bit. @@ -253,7 +254,7 @@ public List GetHeaderExtensions() private bool HasOneByteExtension() { - return ExtensionProfile == 0xBEDE; + return ExtensionProfile == ONE_BYTE_EXTENSION_PROFILE; } private bool HasTwoByteExtension() @@ -323,5 +324,38 @@ private bool HasTwoByteExtension() consumed = offset; return header.PayloadSize>=0; } + + // DateTimeOffset.UnixEpoch only available in newer target frameworks + private static readonly DateTimeOffset UnixEpoch = new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero); + + private byte[] AbsSendTime() + { + var t = DateTimeOffset.Now; + ulong u = (ulong)((t - UnixEpoch).Ticks * 100L); + var s = u / (ulong)1e9; + s += 0x83AA7E80UL; + var f = u % (ulong)1e9; + f <<= 32; + f /= (ulong)1e9; + s <<= 32; + var ntp = s | f; + var abs = ntp >> 14; + + return new byte[] + { + 0x22, // ID = 2; L = 2 (3-1) + (byte)((abs & 0xff0000UL) >> 16), + (byte)((abs & 0xff00UL) >> 8), + (byte)(abs & 0xffUL) + }; + } + + public void AddAbsSendTimeExtension() + { + HeaderExtensionFlag = 1; + ExtensionProfile = ONE_BYTE_EXTENSION_PROFILE; + ExtensionLength = 1; // only abs-send-time for now + ExtensionPayload = AbsSendTime(); + } } } From f4056e035f072c80e7d3989777b1f2f0d06da3d5 Mon Sep 17 00:00:00 2001 From: Tomasz Heimowski Date: Mon, 11 Mar 2024 12:27:23 +0100 Subject: [PATCH 6/9] Comments for AbsSendTime --- src/net/RTP/RTPHeader.cs | 39 +++++++++++++++++++++-------- src/net/SDP/SDPMediaAnnouncement.cs | 2 +- 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/src/net/RTP/RTPHeader.cs b/src/net/RTP/RTPHeader.cs index 21d50f640..c35215fab 100644 --- a/src/net/RTP/RTPHeader.cs +++ b/src/net/RTP/RTPHeader.cs @@ -328,28 +328,47 @@ private bool HasTwoByteExtension() // DateTimeOffset.UnixEpoch only available in newer target frameworks private static readonly DateTimeOffset UnixEpoch = new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero); + // inspired by https://github.com/pion/rtp/blob/master/abssendtimeextension.go private byte[] AbsSendTime() { - var t = DateTimeOffset.Now; - ulong u = (ulong)((t - UnixEpoch).Ticks * 100L); - var s = u / (ulong)1e9; - s += 0x83AA7E80UL; - var f = u % (ulong)1e9; + var now = DateTimeOffset.Now; + ulong unixNanoseconds = (ulong)((now - UnixEpoch).Ticks * 100L); + var seconds = unixNanoseconds / (ulong)1e9; + seconds += 0x83AA7E80UL; // offset in seconds between unix epoch and ntp epoch + var f = unixNanoseconds % (ulong)1e9; f <<= 32; f /= (ulong)1e9; - s <<= 32; - var ntp = s | f; + seconds <<= 32; + var ntp = seconds | f; var abs = ntp >> 14; + var length = 2; // extension length (3-1) - return new byte[] + return new[] { - 0x22, // ID = 2; L = 2 (3-1) + (byte)((SDPMediaAnnouncement.RTP_HEADER_EXTENSION_ID_ABS_SEND_TIME << 4) | length), (byte)((abs & 0xff0000UL) >> 16), (byte)((abs & 0xff00UL) >> 8), (byte)(abs & 0xffUL) }; } - + + /* + An example header extension, with three extension elements, some + padding, and including the required RTP fields, follows: + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | 0xBE | 0xDE | length=3 | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | ID | L=0 | data | ID | L=1 | data... | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | ...data | 0 (pad) | 0 (pad) | ID | L=3 | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | data | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + // https://datatracker.ietf.org/doc/html/rfc5285#section-4.2 public void AddAbsSendTimeExtension() { HeaderExtensionFlag = 1; diff --git a/src/net/SDP/SDPMediaAnnouncement.cs b/src/net/SDP/SDPMediaAnnouncement.cs index 0868a37a0..0a7761de6 100644 --- a/src/net/SDP/SDPMediaAnnouncement.cs +++ b/src/net/SDP/SDPMediaAnnouncement.cs @@ -81,7 +81,7 @@ public class SDPMediaAnnouncement public const string MEDIA_FORMAT_PATH_MSRP_PREFIX = "a=path:msrp:"; public const string MEDIA_FORMAT_PATH_ACCEPT_TYPES_PREFIX = "a=accept-types:"; public const string TIAS_BANDWIDTH_ATTRIBUE_PREFIX = "b=TIAS:"; - private const int RTP_HEADER_EXTENSION_ID_ABS_SEND_TIME = 2; + public const int RTP_HEADER_EXTENSION_ID_ABS_SEND_TIME = 2; private const string RTP_HEADER_EXTENSION_URI_ABS_SEND_TIME = "http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time"; public const MediaStreamStatusEnum DEFAULT_STREAM_STATUS = MediaStreamStatusEnum.SendRecv; From dc0108ed644c563197b4b6aa0d0c717d498e3b91 Mon Sep 17 00:00:00 2001 From: Tomasz Heimowski Date: Mon, 11 Mar 2024 13:54:56 +0100 Subject: [PATCH 7/9] Send abs-send-time only if remote track supports it --- src/net/RTP/MediaStream.cs | 7 +++++-- src/net/SDP/SDPMediaAnnouncement.cs | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/net/RTP/MediaStream.cs b/src/net/RTP/MediaStream.cs index b4dfd39f1..575d2a57a 100644 --- a/src/net/RTP/MediaStream.cs +++ b/src/net/RTP/MediaStream.cs @@ -366,8 +366,11 @@ protected void SendRtpRaw(byte[] data, uint timestamp, int markerBit, int payloa rtpPacket.Header.MarkerBit = markerBit; rtpPacket.Header.PayloadType = payloadType; - // abs-send-time - rtpPacket.Header.AddAbsSendTimeExtension(); + if (RemoteTrack.HeaderExtensions.TryGetValue(SDPMediaAnnouncement.RTP_HEADER_EXTENSION_ID_ABS_SEND_TIME, out var ext) && + ext.Uri == SDPMediaAnnouncement.RTP_HEADER_EXTENSION_URI_ABS_SEND_TIME) + { + rtpPacket.Header.AddAbsSendTimeExtension(); + } Buffer.BlockCopy(data, 0, rtpPacket.Payload, 0, data.Length); diff --git a/src/net/SDP/SDPMediaAnnouncement.cs b/src/net/SDP/SDPMediaAnnouncement.cs index 0a7761de6..9ab3f2d7c 100644 --- a/src/net/SDP/SDPMediaAnnouncement.cs +++ b/src/net/SDP/SDPMediaAnnouncement.cs @@ -82,7 +82,7 @@ public class SDPMediaAnnouncement public const string MEDIA_FORMAT_PATH_ACCEPT_TYPES_PREFIX = "a=accept-types:"; public const string TIAS_BANDWIDTH_ATTRIBUE_PREFIX = "b=TIAS:"; public const int RTP_HEADER_EXTENSION_ID_ABS_SEND_TIME = 2; - private const string RTP_HEADER_EXTENSION_URI_ABS_SEND_TIME = "http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time"; + public const string RTP_HEADER_EXTENSION_URI_ABS_SEND_TIME = "http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time"; public const MediaStreamStatusEnum DEFAULT_STREAM_STATUS = MediaStreamStatusEnum.SendRecv; From c6b9c2393ff570e085d6db924f368043fd08f331 Mon Sep 17 00:00:00 2001 From: Tomasz Heimowski Date: Mon, 11 Mar 2024 15:21:50 +0100 Subject: [PATCH 8/9] Add unit test --- src/net/RTP/RTPHeader.cs | 5 ++--- test/unit/net/RTP/RTPHeaderExtensionUnitTest.cs | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/net/RTP/RTPHeader.cs b/src/net/RTP/RTPHeader.cs index c35215fab..11306baae 100644 --- a/src/net/RTP/RTPHeader.cs +++ b/src/net/RTP/RTPHeader.cs @@ -329,9 +329,8 @@ private bool HasTwoByteExtension() private static readonly DateTimeOffset UnixEpoch = new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero); // inspired by https://github.com/pion/rtp/blob/master/abssendtimeextension.go - private byte[] AbsSendTime() + internal static byte[] AbsSendTime(DateTimeOffset now) { - var now = DateTimeOffset.Now; ulong unixNanoseconds = (ulong)((now - UnixEpoch).Ticks * 100L); var seconds = unixNanoseconds / (ulong)1e9; seconds += 0x83AA7E80UL; // offset in seconds between unix epoch and ntp epoch @@ -374,7 +373,7 @@ public void AddAbsSendTimeExtension() HeaderExtensionFlag = 1; ExtensionProfile = ONE_BYTE_EXTENSION_PROFILE; ExtensionLength = 1; // only abs-send-time for now - ExtensionPayload = AbsSendTime(); + ExtensionPayload = AbsSendTime(DateTimeOffset.Now); } } } diff --git a/test/unit/net/RTP/RTPHeaderExtensionUnitTest.cs b/test/unit/net/RTP/RTPHeaderExtensionUnitTest.cs index ffc63f10f..5bfeac436 100644 --- a/test/unit/net/RTP/RTPHeaderExtensionUnitTest.cs +++ b/test/unit/net/RTP/RTPHeaderExtensionUnitTest.cs @@ -67,5 +67,20 @@ public void ReturnsNullTimestamps() Assert.Null(timestamps); } + + [Fact] + public void AbsSendTime() + { + logger.LogDebug("--> " + System.Reflection.MethodBase.GetCurrentMethod().Name); + logger.BeginScope(System.Reflection.MethodBase.GetCurrentMethod().Name); + + var time = new DateTimeOffset(2024, 2, 11, 14, 51, 02, 999, new TimeSpan(-5, 0, 0)); + var bytes = RTPHeader.AbsSendTime(time); + + Assert.Equal(0x22, bytes[0]); // 2 for ID and 2 for Length (3-1) + Assert.Equal(155, bytes[1]); + Assert.Equal(254, bytes[2]); + Assert.Equal(249, bytes[3]); + } } } From 2a38481633e52d58b746c84a52bd5fa63a514129 Mon Sep 17 00:00:00 2001 From: Tomasz Heimowski Date: Mon, 11 Mar 2024 15:27:40 +0100 Subject: [PATCH 9/9] Revert whitespace changes --- src/net/WebRTC/RTCPeerConnection.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/net/WebRTC/RTCPeerConnection.cs b/src/net/WebRTC/RTCPeerConnection.cs index 55b025be6..d85ecda9d 100644 --- a/src/net/WebRTC/RTCPeerConnection.cs +++ b/src/net/WebRTC/RTCPeerConnection.cs @@ -1141,9 +1141,9 @@ void AddIceCandidates(SDPMediaAnnouncement announcement) else { SDPMediaAnnouncement announcement = new SDPMediaAnnouncement( - mediaStream.LocalTrack.Kind, - SDP.IGNORE_RTP_PORT_NUMBER, - mediaStream.LocalTrack.Capabilities); + mediaStream.LocalTrack.Kind, + SDP.IGNORE_RTP_PORT_NUMBER, + mediaStream.LocalTrack.Capabilities); announcement.Transport = RTP_MEDIA_PROFILE; announcement.Connection = new SDPConnectionInformation(IPAddress.Any);