diff --git a/examples/webrtccmdline/Program.cs b/examples/webrtccmdline/Program.cs index 5685e9117..87bab0979 100755 --- a/examples/webrtccmdline/Program.cs +++ b/examples/webrtccmdline/Program.cs @@ -51,11 +51,11 @@ public class Options public bool UseSecureWebSocket { get; set; } [Option("wsport", Required = false, - HelpText = "The port to use for the web socket server. If not set defualt of 8081 will be used. Format \"--wsport 18081\".")] + HelpText = "The port to use for the web socket server. If not set default of 8081 will be used. Format \"--wsport 18081\".")] public int WebSocketServerPort { get; set; } - [Option("wsserver", Required = false, - HelpText = "The address of a web socket server to connect to establish a WebRTC connection. Format \"--wsserver=ws://127.0.0.1:8081\".")] + [Option("wsclient", Required = false, + HelpText = "The address of a web socket server to connect to establish a WebRTC connection. Format \"--wsclient ws://127.0.0.1:8081\".")] public string WebSocketServer { get; set; } [Option("offer", Required = false, @@ -309,32 +309,55 @@ private static async Task RunCommand(Options options, bool noOptions) } else if (options.EchoServerUrl != null) { + ManualResetEvent gatheringComplete = new ManualResetEvent(false); + // Create offer and send to echo server. var pc = await Createpc(null, _stunServer, _relayOnly, _noAudioTrack, _noDataChannel, _useRsa, _rtpPort); - var signaler = new HttpClient(); + pc.onicegatheringstatechange += (iceGatheringState) => + { + logger.LogDebug($"ICE gathering state changed to {iceGatheringState}."); - var offer = pc.createOffer(null); - await pc.setLocalDescription(offer); + if (iceGatheringState == RTCIceGatheringState.complete) + { + gatheringComplete.Set(); + } + }; - var content = new StringContent(offer.toJSON(), Encoding.UTF8, "application/json"); - var response = await signaler.PostAsync($"{options.EchoServerUrl}", content); - var answerStr = await response.Content.ReadAsStringAsync(); + logger.LogDebug("Waiting for ICE gaterhing to complete."); - if (RTCSessionDescriptionInit.TryParse(answerStr, out var answerInit)) + if (!gatheringComplete.WaitOne(TimeSpan.FromSeconds(10))) { - var setAnswerResult = pc.setRemoteDescription(answerInit); - if (setAnswerResult != SetDescriptionResultEnum.OK) - { - Console.WriteLine($"Set remote description failed {setAnswerResult}."); - } + logger.LogWarning($"Gave up after 10s waiting for ICE gathering to complete."); } else { - Console.WriteLine("Failed to parse SDP answer from echo server."); + logger.LogDebug($"Attempting to send offer to echo server at {options.EchoServerUrl}."); + + var signaler = new HttpClient(); + + var offer = pc.createOffer(null); + await pc.setLocalDescription(offer); + + var content = new StringContent(offer.toJSON(), Encoding.UTF8, "application/json"); + var response = await signaler.PostAsync($"{options.EchoServerUrl}", content); + var answerStr = await response.Content.ReadAsStringAsync(); + + if (RTCSessionDescriptionInit.TryParse(answerStr, out var answerInit)) + { + var setAnswerResult = pc.setRemoteDescription(answerInit); + if (setAnswerResult != SetDescriptionResultEnum.OK) + { + Console.WriteLine($"Set remote description failed {setAnswerResult}."); + } + } + else + { + Console.WriteLine("Failed to parse SDP answer from echo server."); + } } } - else if(options.ActAsEchoServer) + else if (options.ActAsEchoServer) { var echoServer = new EchoServer(); echoServer.Start(); @@ -492,7 +515,7 @@ private async static Task ProcessInput(CancellationTokenSource cts) { byte dtmfByte = 0x03; - if(x.Length >= 6) + if (x.Length >= 6) { dtmfByte = (byte)x.Substring(5).ToCharArray()[0]; } @@ -704,7 +727,7 @@ private async static Task Createpc(WebSocketContext context, _peerConnection.OnRtpEvent += (ep, ev, hdr) => { - if(_rtpEventSsrc == 0) + if (_rtpEventSsrc == 0) { if (ev.EndOfEvent && hdr.MarkerBit == 1) { diff --git a/src/net/DtlsSrtp/DtlsSrtpTransport.cs b/src/net/DtlsSrtp/DtlsSrtpTransport.cs index d3266c82d..3a72203d4 100755 --- a/src/net/DtlsSrtp/DtlsSrtpTransport.cs +++ b/src/net/DtlsSrtp/DtlsSrtpTransport.cs @@ -17,9 +17,7 @@ //----------------------------------------------------------------------------- using System; -using System.Buffers; using System.Collections.Concurrent; -using System.Linq; using Microsoft.Extensions.Logging; using Org.BouncyCastle.Crypto.Tls; using Org.BouncyCastle.Security; @@ -400,51 +398,27 @@ public int UnprotectRTP(byte[] payload, int length, out int outLength) } public byte[] ProtectRTP(byte[] packet, int offset, int length) - { - var buffer=ArrayPool.Shared.Rent(packet.Length * 2); - try - { - var resultLength = ProtectRTP(packet, offset, length, buffer, packet.Length * 2); - var segment=new ArraySegment(buffer, 0, resultLength); - return segment.ToArray(); - } - finally - { - ArrayPool.Shared.Return(buffer); - } - - } - public int ProtectRTP(byte[] packet, int offset, int length,byte[] buffer,int bufferLength) { lock (this.srtpEncoder) { - return this.srtpEncoder.Transform(packet, offset, length,buffer,bufferLength); + return this.srtpEncoder.Transform(packet, offset, length); } } public int ProtectRTP(byte[] payload, int length, out int outLength) { - var resultBuf=ArrayPool.Shared.Rent(length * 2); - try - { - var resultSize = ProtectRTP(payload, 0, length,resultBuf,length * 2); - - if (resultSize <1) - { - outLength = 0; - return -1; - } - - System.Buffer.BlockCopy(resultBuf, 0, payload, 0, resultSize); - outLength = resultSize; + var result = ProtectRTP(payload, 0, length); - return 0; //No Errors - } - finally + if (result == null) { - ArrayPool.Shared.Return(resultBuf); + outLength = 0; + return -1; } - + + System.Buffer.BlockCopy(result, 0, payload, 0, result.Length); + outLength = result.Length; + + return 0; //No Errors } public byte[] UnprotectRTCP(byte[] packet, int offset, int length) @@ -471,49 +445,26 @@ public int UnprotectRTCP(byte[] payload, int length, out int outLength) } public byte[] ProtectRTCP(byte[] packet, int offset, int length) - { - var buffer=ArrayPool.Shared.Rent(packet.Length * 2); - try - { - var resultLength = ProtectRTCP(packet, offset, length, buffer, packet.Length * 2); - var segment=new ArraySegment(buffer, 0, resultLength); - return segment.ToArray(); - } - finally - { - ArrayPool.Shared.Return(buffer); - } - } - public int ProtectRTCP(byte[] packet, int offset, int length,byte[] buffer,int bufferLength) { lock (this.srtcpEncoder) { - return this.srtcpEncoder.Transform(packet, offset, length,buffer,bufferLength); + return this.srtcpEncoder.Transform(packet, offset, length); } } public int ProtectRTCP(byte[] payload, int length, out int outLength) { - var buff=ArrayPool.Shared.Rent(length * 2); - try + var result = ProtectRTCP(payload, 0, length); + if (result == null) { - var resultSize = ProtectRTCP(payload, 0, length,buff,length * 2); - if (resultSize<0) - { - outLength = 0; - return -1; - } + outLength = 0; + return -1; + } - System.Buffer.BlockCopy(buff, 0, payload, 0, resultSize); - outLength = resultSize; + System.Buffer.BlockCopy(result, 0, payload, 0, result.Length); + outLength = result.Length; - return 0; //No Errors - } - finally - { - ArrayPool.Shared.Return(buff); - } - + return 0; //No Errors } /// diff --git a/src/net/DtlsSrtp/SrtpHandler.cs b/src/net/DtlsSrtp/SrtpHandler.cs index 324a4e4df..2fed6ecf6 100644 --- a/src/net/DtlsSrtp/SrtpHandler.cs +++ b/src/net/DtlsSrtp/SrtpHandler.cs @@ -14,7 +14,6 @@ //----------------------------------------------------------------------------- using System; -using System.Buffers; using System.Collections.Generic; using System.Linq; using Microsoft.Extensions.Logging; @@ -190,53 +189,29 @@ public int UnprotectRTP(byte[] payload, int length, out int outLength) return 0; //No Errors } - + public byte[] ProtectRTP(byte[] packet, int offset, int length) { - var buffer=ArrayPool.Shared.Rent(packet.Length * 2); - try - { - var resultLength = ProtectRTP(packet, offset, length, buffer, packet.Length * 2); - var segment=new ArraySegment(buffer, 0, resultLength); - return segment.ToArray(); - } - finally + lock (SrtpEncoder) { - ArrayPool.Shared.Return(buffer); - } - } - - public int ProtectRTP(byte[] packet, int offset, int length,byte[] buffer,int bufferLength) - { - lock (this.SrtpEncoder) - { - return this.SrtpEncoder.Transform(packet, offset, length,buffer,bufferLength); + return SrtpEncoder.Transform(packet, offset, length); } } public int ProtectRTP(byte[] payload, int length, out int outLength) { - var resultBuf=ArrayPool.Shared.Rent(length * 2); - try - { - var resultSize = ProtectRTP(payload, 0, length,resultBuf,length * 2); - - if (resultSize <1) - { - outLength = 0; - return -1; - } + var result = ProtectRTP(payload, 0, length); - System.Buffer.BlockCopy(resultBuf, 0, payload, 0, resultSize); - outLength = resultSize; - - return 0; //No Errors - } - finally + if (result == null) { - ArrayPool.Shared.Return(resultBuf); + outLength = 0; + return -1; } + System.Buffer.BlockCopy(result, 0, payload, 0, result.Length); + outLength = result.Length; + + return 0; //No Errors } public byte[] UnprotectRTCP(byte[] packet, int offset, int length) @@ -263,51 +238,26 @@ public int UnprotectRTCP(byte[] payload, int length, out int outLength) } public byte[] ProtectRTCP(byte[] packet, int offset, int length) - { - var buffer=ArrayPool.Shared.Rent(packet.Length * 2); - try - { - var resultLength = ProtectRTCP(packet, offset, length, buffer, packet.Length * 2); - var segment=new ArraySegment(buffer, 0, resultLength); - return segment.ToArray(); - } - finally - { - ArrayPool.Shared.Return(buffer); - } - } - public int ProtectRTCP(byte[] packet, int offset, int length, byte[] buffer,int bufferLength) { lock (SrtcpEncoder) { - return SrtcpEncoder.Transform(packet, offset, length,buffer,bufferLength); + return SrtcpEncoder.Transform(packet, offset, length); } } public int ProtectRTCP(byte[] payload, int length, out int outLength) { - var resultBuf=ArrayPool.Shared.Rent(length * 2); - try + var result = ProtectRTCP(payload, 0, length); + if (result == null) { - var resultSize = ProtectRTCP(payload, 0, length,resultBuf,length * 2); - - if (resultSize <1) - { - outLength = 0; - return -1; - } + outLength = 0; + return -1; + } - System.Buffer.BlockCopy(resultBuf, 0, payload, 0, resultSize); - outLength = resultSize; + System.Buffer.BlockCopy(result, 0, payload, 0, result.Length); + outLength = result.Length; - return 0; //No Errors - } - finally - { - ArrayPool.Shared.Return(resultBuf); - } - - + return 0; //No Errors } } } \ No newline at end of file diff --git a/src/net/DtlsSrtp/Transform/IPackerTransformer.cs b/src/net/DtlsSrtp/Transform/IPackerTransformer.cs index 9d7253368..4f570f782 100644 --- a/src/net/DtlsSrtp/Transform/IPackerTransformer.cs +++ b/src/net/DtlsSrtp/Transform/IPackerTransformer.cs @@ -1,23 +1,23 @@ -//----------------------------------------------------------------------------- -// Filename: IPacketTransformer.cs -// +//----------------------------------------------------------------------------- +// Filename: IPacketTransformer.cs +// // Description: Encapsulate the concept of packet transformation. Given a packet, // PacketTransformer can either transform it or reverse the -// transformation. -// -// Derived From: -// https://github.com/RestComm/media-core/blob/master/rtp/src/main/java/org/restcomm/media/core/rtp/crypto/PacketTransformer.java -// -// Author(s): -// Rafael Soares (raf.csoares@kyubinteractive.com) -// -// History: -// 01 Jul 2020 Rafael Soares Created. -// -// License: -// BSD 3-Clause "New" or "Revised" License, see included LICENSE.md file. -// Original Source: AGPL-3.0 License -//----------------------------------------------------------------------------- +// transformation. +// +// Derived From: +// https://github.com/RestComm/media-core/blob/master/rtp/src/main/java/org/restcomm/media/core/rtp/crypto/PacketTransformer.java +// +// Author(s): +// Rafael Soares (raf.csoares@kyubinteractive.com) +// +// History: +// 01 Jul 2020 Rafael Soares Created. +// +// License: +// BSD 3-Clause "New" or "Revised" License, see included LICENSE.md file. +// Original Source: AGPL-3.0 License +//----------------------------------------------------------------------------- namespace SIPSorcery.Net { @@ -31,7 +31,6 @@ public interface IPacketTransformer * @return The transformed packet. Returns null if the packet cannot be transformed. */ byte[] Transform(byte[] pkt); - int Transform(byte[] pkt,byte[] resultBuffer,int resultBufferLength); /** * Transforms a specific non-secure packet. @@ -45,9 +44,7 @@ public interface IPacketTransformer * @return The transformed packet. Returns null if the packet cannot be * transformed. */ - byte[] Transform(byte[] pkt, int offset, int length); - int Transform(byte[] pkt, int offset, int length,byte[] resultBuffer,int resultBufferLength); /** * Reverse-transforms a specific packet (i.e. transforms a transformed diff --git a/src/net/DtlsSrtp/Transform/RawPacket.cs b/src/net/DtlsSrtp/Transform/RawPacket.cs index 2c94696cb..7da6fb3a7 100644 --- a/src/net/DtlsSrtp/Transform/RawPacket.cs +++ b/src/net/DtlsSrtp/Transform/RawPacket.cs @@ -1,25 +1,25 @@ -//----------------------------------------------------------------------------- -// Filename: RawPacket.cs -// -// TODO: This class should be replaced by the existing RTP packet implementation -// in src/net/RTP. -// -// Description: See below. -// -// Derived From: -// https://github.com/RestComm/media-core/blob/master/rtp/src/main/java/org/restcomm/media/core/rtp/crypto/RawPacket.java -// -// Author(s): -// Rafael Soares (raf.csoares@kyubinteractive.com) -// -// History: -// 01 Jul 2020 Rafael Soares Created. -// -// License: -// BSD 3-Clause "New" or "Revised" License, see included LICENSE.md file. -// Original Source: AGPL-3.0 License -//----------------------------------------------------------------------------- - +//----------------------------------------------------------------------------- +// Filename: RawPacket.cs +// +// TODO: This class should be replaced by the existing RTP packet implementation +// in src/net/RTP. +// +// Description: See below. +// +// Derived From: +// https://github.com/RestComm/media-core/blob/master/rtp/src/main/java/org/restcomm/media/core/rtp/crypto/RawPacket.java +// +// Author(s): +// Rafael Soares (raf.csoares@kyubinteractive.com) +// +// History: +// 01 Jul 2020 Rafael Soares Created. +// +// License: +// BSD 3-Clause "New" or "Revised" License, see included LICENSE.md file. +// Original Source: AGPL-3.0 License +//----------------------------------------------------------------------------- + /** * When using TransformConnector, a RTP/RTCP packet is represented using * RawPacket. RawPacket stores the buffer holding the RTP/RTCP packet, as well @@ -38,7 +38,7 @@ * @author Boris Grozev * @author Lyubomir Marinov * -*/ +*/ using System.IO; @@ -95,33 +95,13 @@ public void Wrap(byte[] data, int offset, int length) this.buffer.SetLength(length - offset); this.buffer.Position = 0; } - public int GetDataIntoBuffer(byte[] resultBuffer,int bufferLength) - { - - if (bufferLength < this.buffer.Length) - { - throw new InvalidDataException("Buffer is too small"); - } - this.buffer.Position = 0; - - this.buffer.Read(resultBuffer, 0, (int)this.buffer.Length); - return (int)this.buffer.Length; - } - public byte[] GetData(byte[] resultBuffer=null) - { - if (resultBuffer == null) - { - resultBuffer= new byte[this.buffer.Length]; - } - if (resultBuffer.Length < this.buffer.Length) - { - throw new InvalidDataException("Buffer is too small"); - } + public byte[] GetData() + { this.buffer.Position = 0; - - this.buffer.Read(resultBuffer, 0, (int)this.buffer.Length); - return resultBuffer; + byte[] data = new byte[this.buffer.Length]; + this.buffer.Read(data, 0, data.Length); + return data; } /** diff --git a/src/net/DtlsSrtp/Transform/SrtcpTransformer.cs b/src/net/DtlsSrtp/Transform/SrtcpTransformer.cs index de87b3d1c..734f9b120 100644 --- a/src/net/DtlsSrtp/Transform/SrtcpTransformer.cs +++ b/src/net/DtlsSrtp/Transform/SrtcpTransformer.cs @@ -64,12 +64,6 @@ public byte[] Transform(byte[] pkt) return Transform(pkt, 0, pkt.Length); } - - public int Transform(byte[] pkt,byte[] resultBuffer,int resultBufferLength) - { - return Transform(pkt, 0, pkt.Length, resultBuffer, resultBufferLength); - } - public byte[] Transform(byte[] pkt, int offset, int length) { var isLocked = Interlocked.CompareExchange(ref _isLocked, 1, 0) != 0; @@ -93,42 +87,9 @@ public byte[] Transform(byte[] pkt, int offset, int length) // Secure packet into SRTCP format context.TransformPacket(packet); - return packet.GetData(); - - } - finally - { - //Unlock - if (!isLocked) - Interlocked.CompareExchange(ref _isLocked, 0, 1); - } - } - - public int Transform(byte[] pkt, int offset, int length,byte[] resultBuffer,int resultBufferLength) - { - var isLocked = Interlocked.CompareExchange(ref _isLocked, 1, 0) != 0; - try - { - // Wrap the data into raw packet for readable format - var packet = !isLocked ? this.packet : new RawPacket(); - packet.Wrap(pkt, offset, length); + byte[] result = packet.GetData(); - // Associate the packet with its encryption context - long ssrc = packet.GetRTCPSSRC(); - SrtcpCryptoContext context = null; - contexts.TryGetValue(ssrc, out context); - - if (context == null) - { - context = forwardEngine.GetDefaultContextControl().DeriveContext(ssrc); - context.DeriveSrtcpKeys(); - contexts.AddOrUpdate(ssrc, context, (a, b) => context); - } - - // Secure packet into SRTCP format - context.TransformPacket(packet); - return packet.GetDataIntoBuffer(resultBuffer,resultBufferLength); - + return result; } finally { diff --git a/src/net/DtlsSrtp/Transform/SrtpTransformer.cs b/src/net/DtlsSrtp/Transform/SrtpTransformer.cs index 994ec47d8..e72816c98 100644 --- a/src/net/DtlsSrtp/Transform/SrtpTransformer.cs +++ b/src/net/DtlsSrtp/Transform/SrtpTransformer.cs @@ -1,24 +1,24 @@ -//----------------------------------------------------------------------------- -// Filename: SrtpTransformer.cs -// -// Description: SRTPTransformer implements PacketTransformer and provides -// implementations for RTP packet to SRTP packet transformation and SRTP -// packet to RTP packet transformation logic. -// -// Derived From: -// https://github.com/RestComm/media-core/blob/master/rtp/src/main/java/org/restcomm/media/core/rtp/crypto/SRTPTransformer.java -// -// Author(s): -// Rafael Soares (raf.csoares@kyubinteractive.com) -// -// History: -// 01 Jul 2020 Rafael Soares Created. -// -// License: -// BSD 3-Clause "New" or "Revised" License, see included LICENSE.md file. -// Original Source: AGPL-3.0 License -//----------------------------------------------------------------------------- - +//----------------------------------------------------------------------------- +// Filename: SrtpTransformer.cs +// +// Description: SRTPTransformer implements PacketTransformer and provides +// implementations for RTP packet to SRTP packet transformation and SRTP +// packet to RTP packet transformation logic. +// +// Derived From: +// https://github.com/RestComm/media-core/blob/master/rtp/src/main/java/org/restcomm/media/core/rtp/crypto/SRTPTransformer.java +// +// Author(s): +// Rafael Soares (raf.csoares@kyubinteractive.com) +// +// History: +// 01 Jul 2020 Rafael Soares Created. +// +// License: +// BSD 3-Clause "New" or "Revised" License, see included LICENSE.md file. +// Original Source: AGPL-3.0 License +//----------------------------------------------------------------------------- + /** * * Code derived and adapted from the Jitsi client side SRTP framework. @@ -37,19 +37,19 @@ * @author Bing SU (nova.su@gmail.com) * @author Rafael Soares (raf.csoares@kyubinteractive.com) * -*/ - -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Threading; - +*/ + +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Threading; + namespace SIPSorcery.Net { public class SrtpTransformer : IPacketTransformer { private int _isLocked = 0; - private RawPacket rawPacket; - + private RawPacket rawPacket; + private SrtpTransformEngine forwardEngine; private SrtpTransformEngine reverseEngine; @@ -69,82 +69,45 @@ public SrtpTransformer(SrtpTransformEngine forwardEngine, SrtpTransformEngine re this.contexts = new ConcurrentDictionary(); this.rawPacket = new RawPacket(); } + public byte[] Transform(byte[] pkt) { return Transform(pkt, 0, pkt.Length); } - public int Transform(byte[] pkt,byte[] outputBuffer,int outputBufferSize) - { - return Transform(pkt, 0, pkt.Length,outputBuffer,outputBufferSize); - } - - public byte[] Transform(byte[] pkt, int offset, int length) - { - var isLocked = Interlocked.CompareExchange(ref _isLocked, 1, 0) != 0; - - try - { - // Updates the contents of raw packet with new incoming packet - var rawPacket = !isLocked ? this.rawPacket : new RawPacket(); - rawPacket.Wrap(pkt, offset, length); - - // Associate packet to a crypto context - long ssrc = rawPacket.GetSSRC(); - SrtpCryptoContext context = null; - contexts.TryGetValue(ssrc, out context); - - if (context == null) - { - context = forwardEngine.GetDefaultContext().deriveContext(ssrc, 0, 0); - context.DeriveSrtpKeys(0); - contexts.AddOrUpdate(ssrc, context, (a, b) => context); - } - - // Transform RTP packet into SRTP - context.TransformPacket(rawPacket); - return rawPacket.GetData(); - - } - finally - { - //Unlock - if (!isLocked) - Interlocked.CompareExchange(ref _isLocked, 0, 1); - } - } - public int Transform(byte[] pkt, int offset, int length,byte[] outputBuffer,int outputBufferSize) + public byte[] Transform(byte[] pkt, int offset, int length) { var isLocked = Interlocked.CompareExchange(ref _isLocked, 1, 0) != 0; - try - { - // Updates the contents of raw packet with new incoming packet - var rawPacket = !isLocked ? this.rawPacket : new RawPacket(); - rawPacket.Wrap(pkt, offset, length); - - // Associate packet to a crypto context - long ssrc = rawPacket.GetSSRC(); - SrtpCryptoContext context = null; - contexts.TryGetValue(ssrc, out context); - - if (context == null) - { - context = forwardEngine.GetDefaultContext().deriveContext(ssrc, 0, 0); - context.DeriveSrtpKeys(0); - contexts.AddOrUpdate(ssrc, context, (a, b) => context); - } - - // Transform RTP packet into SRTP - context.TransformPacket(rawPacket); - return rawPacket.GetDataIntoBuffer(outputBuffer,outputBufferSize); - + try + { + // Updates the contents of raw packet with new incoming packet + var rawPacket = !isLocked ? this.rawPacket : new RawPacket(); + rawPacket.Wrap(pkt, offset, length); + + // Associate packet to a crypto context + long ssrc = rawPacket.GetSSRC(); + SrtpCryptoContext context = null; + contexts.TryGetValue(ssrc, out context); + + if (context == null) + { + context = forwardEngine.GetDefaultContext().deriveContext(ssrc, 0, 0); + context.DeriveSrtpKeys(0); + contexts.AddOrUpdate(ssrc, context, (a, b) => context); + } + + // Transform RTP packet into SRTP + context.TransformPacket(rawPacket); + byte[] result = rawPacket.GetData(); + + return result; } finally - { - //Unlock - if (!isLocked) - Interlocked.CompareExchange(ref _isLocked, 0, 1); + { + //Unlock + if (!isLocked) + Interlocked.CompareExchange(ref _isLocked, 0, 1); } } @@ -164,37 +127,37 @@ public byte[] ReverseTransform(byte[] pkt) public byte[] ReverseTransform(byte[] pkt, int offset, int length) { var isLocked = Interlocked.CompareExchange(ref _isLocked, 1, 0) != 0; - try - { - // Wrap data into the raw packet for readable format - var rawPacket = !isLocked ? this.rawPacket : new RawPacket(); - rawPacket.Wrap(pkt, offset, length); - - // Associate packet to a crypto context - long ssrc = rawPacket.GetSSRC(); - SrtpCryptoContext context = null; - this.contexts.TryGetValue(ssrc, out context); - if (context == null) - { - context = this.reverseEngine.GetDefaultContext().deriveContext(ssrc, 0, 0); - context.DeriveSrtpKeys(rawPacket.GetSequenceNumber()); - contexts.AddOrUpdate(ssrc, context, (a, b) => context); - } - - byte[] result = null; - bool reversed = context.ReverseTransformPacket(rawPacket); - if (reversed) - { - result = rawPacket.GetData(); - } - - return result; + try + { + // Wrap data into the raw packet for readable format + var rawPacket = !isLocked ? this.rawPacket : new RawPacket(); + rawPacket.Wrap(pkt, offset, length); + + // Associate packet to a crypto context + long ssrc = rawPacket.GetSSRC(); + SrtpCryptoContext context = null; + this.contexts.TryGetValue(ssrc, out context); + if (context == null) + { + context = this.reverseEngine.GetDefaultContext().deriveContext(ssrc, 0, 0); + context.DeriveSrtpKeys(rawPacket.GetSequenceNumber()); + contexts.AddOrUpdate(ssrc, context, (a, b) => context); + } + + byte[] result = null; + bool reversed = context.ReverseTransformPacket(rawPacket); + if (reversed) + { + result = rawPacket.GetData(); + } + + return result; } finally - { - //Unlock - if (!isLocked) - Interlocked.CompareExchange(ref _isLocked, 0, 1); + { + //Unlock + if (!isLocked) + Interlocked.CompareExchange(ref _isLocked, 0, 1); } } @@ -207,9 +170,9 @@ public byte[] ReverseTransform(byte[] pkt, int offset, int length) public void Close() { forwardEngine.Close(); - if (forwardEngine != reverseEngine) - { - reverseEngine.Close(); + if (forwardEngine != reverseEngine) + { + reverseEngine.Close(); } var keys = new List(contexts.Keys); @@ -217,9 +180,9 @@ public void Close() { SrtpCryptoContext context; contexts.TryRemove(ssrc, out context); - if (context != null) - { - context.Close(); + if (context != null) + { + context.Close(); } } } diff --git a/src/net/ICE/IceChecklistEntry.cs b/src/net/ICE/IceChecklistEntry.cs index 8317a96eb..1e6eb98a7 100644 --- a/src/net/ICE/IceChecklistEntry.cs +++ b/src/net/ICE/IceChecklistEntry.cs @@ -288,9 +288,16 @@ internal void GotStunResponse(STUNMessage stunResponse, IPEndPoint remoteEndPoin if (errCodeAttribute.ErrorCode == IceServer.STUN_UNAUTHORISED_ERROR_CODE || errCodeAttribute.ErrorCode == IceServer.STUN_STALE_NONCE_ERROR_CODE) { - LocalCandidate.IceServer.SetAuthenticationFields(stunResponse); - LocalCandidate.IceServer.GenerateNewTransactionID(); - retry = true; + if (LocalCandidate.IceServer == null) + { + logger.LogWarning($"A STUN error response was received on an ICE candidate without a corresponding ICE server, ignoring."); + } + else + { + LocalCandidate.IceServer.SetAuthenticationFields(stunResponse); + LocalCandidate.IceServer.GenerateNewTransactionID(); + retry = true; + } } } diff --git a/src/net/ICE/RtpIceChannel.cs b/src/net/ICE/RtpIceChannel.cs index a2576e4b0..7ce2d40f2 100755 --- a/src/net/ICE/RtpIceChannel.cs +++ b/src/net/ICE/RtpIceChannel.cs @@ -582,6 +582,7 @@ internal int RTO /// If both are null system DNS resolver will be used. /// public Func> MdnsResolve; + /// /// An optional callback function to resolve remote ICE candidates with MDNS hostnames. /// @@ -597,7 +598,6 @@ internal int RTO private bool m_tcpRtpReceiverStarted = false; - /// /// Creates a new instance of an RTP ICE channel to provide RTP channel functions /// with ICE connectivity checks. @@ -661,7 +661,7 @@ public RtpIceChannel( // Create TCP Socket to implement TURN Control // Take a note that TURN Control will only use TCP for CreatePermissions/Allocate/BindRequests/Data - // Ice Candidates returned by relay will always be UDP Based + // Ice Candidates returned by relay will always be UDP based. var tcpIceServers = _iceServers != null ? _iceServers.FindAll(a => a != null && @@ -671,7 +671,7 @@ public RtpIceChannel( var supportTcp = tcpIceServers != null && tcpIceServers.Count > 0; if (supportTcp) { - // Init one TCP Socket per IceServer as we need to connect to proper use a TcpSocket (unfortunally) + // Init one TCP Socket per IceServer as we need to connect to properly use a TcpSocket (unfortunately). RtpTcpSocketByUri = new Dictionary(); foreach (var tcpIceServer in tcpIceServers) { @@ -760,6 +760,7 @@ public void StartGathering() _connectivityChecksTimer = new Timer(DoConnectivityCheck, null, 0, Ta); } } + protected void StartTcpRtpReceiver() { if (!m_tcpRtpReceiverStarted && RtpTcpSocketByUri != null && RtpTcpSocketByUri.Count > 0) @@ -2633,16 +2634,11 @@ protected override void OnRTPPacketReceived(UdpReceiver receiver, int localPort, /// The data to send to the peer. /// The TURN server end point to send the relayed request to. /// - private SocketError SendRelay(ProtocolType protocol, IPEndPoint dstEndPoint, byte[] buffer, IPEndPoint relayEndPoint, IceServer iceServer, int bufferLength = -1) + private SocketError SendRelay(ProtocolType protocol, IPEndPoint dstEndPoint, byte[] buffer, IPEndPoint relayEndPoint, IceServer iceServer) { - if (bufferLength < 0) - { - bufferLength = buffer.Length; - } - STUNMessage sendReq = new STUNMessage(STUNMessageTypesEnum.SendIndication); sendReq.AddXORPeerAddressAttribute(dstEndPoint.Address, dstEndPoint.Port); - sendReq.Attributes.Add(new STUNAttribute(STUNAttributeTypesEnum.Data, buffer.Take(bufferLength).ToArray())); + sendReq.Attributes.Add(new STUNAttribute(STUNAttributeTypesEnum.Data, buffer)); var request = sendReq.ToByteBuffer(null, false); var sendResult = protocol == ProtocolType.Tcp ? @@ -2715,7 +2711,7 @@ private async Task ResolveMdnsName(RTCIceCandidate candidate) /// The data to send. /// The result of initiating the send. This result does not reflect anything about /// whether the remote party received the packet or not. - public override SocketError Send(RTPChannelSocketsEnum sendOn, IPEndPoint dstEndPoint, byte[] buffer, int bufferLength = -1) + public override SocketError Send(RTPChannelSocketsEnum sendOn, IPEndPoint dstEndPoint, byte[] buffer) { if (NominatedEntry != null && NominatedEntry.LocalCandidate.type == RTCIceCandidateType.relay && NominatedEntry.LocalCandidate.IceServer != null && @@ -2729,7 +2725,7 @@ public override SocketError Send(RTPChannelSocketsEnum sendOn, IPEndPoint dstEnd } else { - return base.Send(sendOn, dstEndPoint, buffer, bufferLength); + return base.Send(sendOn, dstEndPoint, buffer); } } } diff --git a/src/net/RTP/MediaStream.cs b/src/net/RTP/MediaStream.cs index d80f71b9d..40ab12b9e 100644 --- a/src/net/RTP/MediaStream.cs +++ b/src/net/RTP/MediaStream.cs @@ -15,7 +15,6 @@ //----------------------------------------------------------------------------- using System; -using System.Buffers; using System.Collections.Generic; using System.Linq; using System.Net; @@ -398,20 +397,14 @@ private static byte[] Combine(params byte[][] arrays) return rv; } - protected void SendRtpRaw(byte[] data, uint timestamp, int markerBit, int payloadType, Boolean checkDone, ushort? seqNum = null,int dataLength=-1) + protected void SendRtpRaw(byte[] data, uint timestamp, int markerBit, int payloadType, Boolean checkDone, ushort? seqNum = null) { - if (dataLength < 0) - { - dataLength = data.Length; - } - if (checkDone || CheckIfCanSendRtpRaw()) { ProtectRtpPacket protectRtpPacket = SecureContext?.ProtectRtpPacket; int srtpProtectionLength = (protectRtpPacket != null) ? RTPSession.SRTP_MAX_PREFIX_LENGTH : 0; - var packetPayloadBuffer=ArrayPool.Shared.Rent(dataLength + srtpProtectionLength); - RTPPacket rtpPacket = new RTPPacket(packetPayloadBuffer,dataLength + srtpProtectionLength); + RTPPacket rtpPacket = new RTPPacket(data.Length + srtpProtectionLength); rtpPacket.Header.SyncSource = LocalTrack.Ssrc; rtpPacket.Header.SequenceNumber = seqNum ?? LocalTrack.GetNextSeqNum(); rtpPacket.Header.Timestamp = timestamp; @@ -437,8 +430,7 @@ 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 */ if (LocalTrack?.HeaderExtensions?.Values.Count > 0) { - int payloadLength = 0; - byte[] payload = ArrayPool.Shared.Rent(1024*1024); + byte[] payload = null; foreach (var ext in LocalTrack.HeaderExtensions.Values) { // We support up to 14 extensions .... Not clear at all how to manage more ... @@ -449,9 +441,6 @@ 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 // Get extension payload and combine it to global payload var extPayLoad = ext.Marshal(); - extPayLoad.CopyTo(payload,0); - payloadLength += extPayLoad.Length; - /* if (payload == null) { payload = extPayLoad; @@ -459,28 +448,23 @@ 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 else { payload = Combine(payload, extPayLoad); - }*/ + } } - if(payloadLength > 0) + if(payload?.Length > 0) { // Need to round to 4 bytes boundaries - var roundedExtSize = payloadLength % 4; + var roundedExtSize = payload.Length % 4; if(roundedExtSize > 0) { - for (int i = 1; i <= roundedExtSize; i++) - { - payload[i] = 0; - } - - payloadLength += roundedExtSize; + var padding = Enumerable.Repeat((byte)0, 4 - roundedExtSize).ToArray(); + payload = Combine(payload, padding); } rtpPacket.Header.HeaderExtensionFlag = 1; // We have at least one extension rtpPacket.Header.ExtensionLength = (ushort) (payload.Length / 4); // payload length / 4 rtpPacket.Header.ExtensionProfile = RTPHeader.ONE_BYTE_EXTENSION_PROFILE; // We support up to 14 extensions .... Not clear at all how to manage more ... - rtpPacket.Header.ExtensionPayload = payload.Take(payloadLength).ToArray(); - ArrayPool.Shared.Return(payload); + rtpPacket.Header.ExtensionPayload = payload; } } else @@ -488,11 +472,9 @@ 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 rtpPacket.Header.HeaderExtensionFlag = 0; } - Buffer.BlockCopy(data, 0, rtpPacket.Payload, 0, dataLength); + Buffer.BlockCopy(data, 0, rtpPacket.Payload, 0, data.Length); - var rtpBuffer=ArrayPool.Shared.Rent(rtpPacket.CalculatedSize()); - var bufferSize=rtpPacket.GetBytes(rtpBuffer); - //var rtpBuffer = rtpPacket.GetBytes(); + var rtpBuffer = rtpPacket.GetBytes(); if (protectRtpPacket == null) { @@ -500,21 +482,19 @@ 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 } else { - int rtperr = protectRtpPacket(rtpBuffer, bufferSize - srtpProtectionLength, out int outBufLen); + int rtperr = protectRtpPacket(rtpBuffer, rtpBuffer.Length - srtpProtectionLength, out int outBufLen); if (rtperr != 0) { logger.LogError("SendRTPPacket protection failed, result " + rtperr + "."); } else { - rtpChannel.Send(RTPChannelSocketsEnum.RTP, DestinationEndPoint, rtpBuffer,outBufLen); + rtpChannel.Send(RTPChannelSocketsEnum.RTP, DestinationEndPoint, rtpBuffer.Take(outBufLen).ToArray()); } } m_lastRtpTimestamp = timestamp; RtcpSession?.RecordRtpPacketSend(rtpPacket); - ArrayPool.Shared.Return(rtpBuffer); - ArrayPool.Shared.Return(packetPayloadBuffer); } } diff --git a/src/net/RTP/Packetisation/H264Packetiser.cs b/src/net/RTP/Packetisation/H264Packetiser.cs index 4404c2699..2f9014cdb 100644 --- a/src/net/RTP/Packetisation/H264Packetiser.cs +++ b/src/net/RTP/Packetisation/H264Packetiser.cs @@ -41,33 +41,30 @@ public class H264Packetiser public struct H264Nal { - public readonly int Start; - public readonly int Length; - + public byte[] NAL { get; } public bool IsLast { get; } - public H264Nal(int start, int length, bool isLast) + public H264Nal(byte[] nal, bool isLast) { - Start = start; - Length = length; + NAL = nal; IsLast = isLast; } } - public static IEnumerable ParseNals(byte[] accessUnit, int start, int length) + public static IEnumerable ParseNals(byte[] accessUnit) { int zeroes = 0; // Parse NALs from H264 access unit, encoded as an Annex B bitstream. // NALs are delimited by 0x000001 or 0x00000001. int currPosn = 0; - for (int i = 0; i < length; i++) + for (int i = 0; i < accessUnit.Length; i++) { - if (accessUnit[start+i] == 0x00) + if (accessUnit[i] == 0x00) { zeroes++; } - else if (accessUnit[start+i] == 0x01 && zeroes >= 2) + else if (accessUnit[i] == 0x01 && zeroes >= 2) { // This is a NAL start sequence. int nalStart = i + 1; @@ -77,7 +74,7 @@ public static IEnumerable ParseNals(byte[] accessUnit, int start, int l int nalSize = endPosn - currPosn; bool isLast = currPosn + nalSize == accessUnit.Length; - yield return new H264Nal(start+currPosn, nalSize, isLast); + yield return new H264Nal(accessUnit.Skip(currPosn).Take(nalSize).ToArray(), isLast); } currPosn = nalStart; @@ -88,9 +85,9 @@ public static IEnumerable ParseNals(byte[] accessUnit, int start, int l } } - if (currPosn < length) + if (currPosn < accessUnit.Length) { - yield return new H264Nal(start+currPosn, length - currPosn, true); + yield return new H264Nal(accessUnit.Skip(currPosn).ToArray(), true); } } diff --git a/src/net/RTP/RTPChannel.cs b/src/net/RTP/RTPChannel.cs index adf9fdb8c..6d2a0add2 100644 --- a/src/net/RTP/RTPChannel.cs +++ b/src/net/RTP/RTPChannel.cs @@ -42,10 +42,12 @@ namespace SIPSorcery.Net public class UdpReceiver { /// - /// MTU is 1452 bytes so this should be heaps. - /// TODO: What about fragmented UDP packets that are put back together by the OS? + /// MTU is 1452 bytes so this should be heaps [AC 03 Nov 2024: turns out it's not when considering UDP fragmentation can + /// result in a max UDP payload of 65535 - 8 (header) = 65527 bytes]. + /// An issue was reported with a real World WeBRTC implementation producing UDP packet sizes of 2144 byes #1045. Consequently + /// updated from 2048 to 3000. /// - protected const int RECEIVE_BUFFER_SIZE = 2048; + protected const int RECEIVE_BUFFER_SIZE = 3000; protected static ILogger logger = Log.Logger; @@ -153,7 +155,6 @@ public virtual void BeginReceiveFrom() } } - private int socketLoop = 0; /// /// Handler for end of the begin receive call. /// @@ -210,17 +211,10 @@ protected virtual void EndReceiveFrom(IAsyncResult ar) } } } - socketLoop = 0; - } catch (SocketException resetSockExcp) when (resetSockExcp.SocketErrorCode == SocketError.ConnectionReset) { - // not really safe. creates a loop with stack exhaustion - socketLoop++; - if (socketLoop > 5) - { - Close(resetSockExcp.Message); - } + // Thrown when close is called on a socket from this end. Safe to ignore. } catch (SocketException sockExcp) { @@ -469,13 +463,8 @@ public void Close(string reason) /// The data to send. /// The result of initiating the send. This result does not reflect anything about /// whether the remote party received the packet or not. - public virtual SocketError Send(RTPChannelSocketsEnum sendOn, IPEndPoint dstEndPoint, byte[] buffer,int bufferLength=-1) + public virtual SocketError Send(RTPChannelSocketsEnum sendOn, IPEndPoint dstEndPoint, byte[] buffer) { - if (bufferLength == -1) - { - bufferLength=buffer.Length; - } - if (m_isClosed) { return SocketError.Disconnecting; @@ -484,7 +473,7 @@ public virtual SocketError Send(RTPChannelSocketsEnum sendOn, IPEndPoint dstEndP { throw new ArgumentException("dstEndPoint", "An empty destination was specified to Send in RTPChannel."); } - else if (buffer == null || bufferLength == 0) + else if (buffer == null || buffer.Length == 0) { throw new ArgumentException("buffer", "The buffer must be set and non empty for Send in RTPChannel."); } @@ -527,7 +516,7 @@ public virtual SocketError Send(RTPChannelSocketsEnum sendOn, IPEndPoint dstEndP m_rtpReceiver.BeginReceiveFrom(); } - sendSocket.BeginSendTo(buffer, 0, bufferLength, SocketFlags.None, dstEndPoint, EndSendTo, sendSocket); + sendSocket.BeginSendTo(buffer, 0, buffer.Length, SocketFlags.None, dstEndPoint, EndSendTo, sendSocket); return SocketError.Success; } catch (ObjectDisposedException) // Thrown when socket is closed. Can be safely ignored. diff --git a/src/net/RTP/RTPHeader.cs b/src/net/RTP/RTPHeader.cs index d5500266c..bb56a9d7a 100644 --- a/src/net/RTP/RTPHeader.cs +++ b/src/net/RTP/RTPHeader.cs @@ -15,10 +15,8 @@ //----------------------------------------------------------------------------- using System; -using System.Buffers; using System.Buffers.Binary; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; using SIPSorcery.net.RTP; using SIPSorcery.Sys; @@ -145,114 +143,44 @@ public byte[] GetHeader(UInt16 sequenceNumber, uint timestamp, uint syncSource) return GetBytes(); } - - private void WriteHeaderBytes(byte[] target, int offset, byte[] data,int datalength) - { - if (BitConverter.IsLittleEndian) - { - for (int i = 0; i .Shared.Rent(2); - BitConverter.TryWriteBytes(buff, data); - WriteHeaderBytes(target,offset,buff,2); - ArrayPool.Shared.Return(buff); - #else - var buff=BitConverter.GetBytes(data); - WriteHeaderBytes(target,offset,buff,2); - #endif - } - - private void WriteHeaderBytes(byte[] target,int offset, uint data) + public byte[] GetBytes() { - - -#if NET5_0_OR_GREATER - var buff = ArrayPool.Shared.Rent(4); - BitConverter.TryWriteBytes(buff, data); - WriteHeaderBytes(target,offset,buff,4); - ArrayPool.Shared.Return(buff); -#else - var buff=BitConverter.GetBytes(data); - WriteHeaderBytes(target,offset,buff,4); -#endif - } - - public byte[] GetBytes(byte[] header=null) - { - header ??= new byte[Length]; - + byte[] header = new byte[Length]; UInt16 firstWord = Convert.ToUInt16(Version * 16384 + PaddingFlag * 8192 + HeaderExtensionFlag * 4096 + CSRCCount * 256 + MarkerBit * 128 + PayloadType); - WriteHeaderBytes(header, 0, firstWord); - WriteHeaderBytes(header, 2, SequenceNumber); - WriteHeaderBytes(header, 4, Timestamp); - WriteHeaderBytes(header, 8, SyncSource); - if (HeaderExtensionFlag == 1) - { - WriteHeaderBytes(header, 12 + 4 * CSRCCount, ExtensionProfile); - WriteHeaderBytes(header, 14 + 4 * CSRCCount, ExtensionLength); - } - - - if (ExtensionLength > 0 && ExtensionPayload != null) - { - Buffer.BlockCopy(ExtensionPayload, 0, header, 16 + 4 * CSRCCount, ExtensionLength * 4); - } -/* - var legacyHeader = new byte[Length]; - - if (BitConverter.IsLittleEndian) { - Buffer.BlockCopy(BitConverter.GetBytes(NetConvert.DoReverseEndian(firstWord)), 0, legacyHeader, 0, 2); - Buffer.BlockCopy(BitConverter.GetBytes(NetConvert.DoReverseEndian(SequenceNumber)), 0, legacyHeader, 2, 2); - Buffer.BlockCopy(BitConverter.GetBytes(NetConvert.DoReverseEndian(Timestamp)), 0, legacyHeader, 4, 4); - Buffer.BlockCopy(BitConverter.GetBytes(NetConvert.DoReverseEndian(SyncSource)), 0, legacyHeader, 8, 4); + Buffer.BlockCopy(BitConverter.GetBytes(NetConvert.DoReverseEndian(firstWord)), 0, header, 0, 2); + Buffer.BlockCopy(BitConverter.GetBytes(NetConvert.DoReverseEndian(SequenceNumber)), 0, header, 2, 2); + Buffer.BlockCopy(BitConverter.GetBytes(NetConvert.DoReverseEndian(Timestamp)), 0, header, 4, 4); + Buffer.BlockCopy(BitConverter.GetBytes(NetConvert.DoReverseEndian(SyncSource)), 0, header, 8, 4); if (HeaderExtensionFlag == 1) { - Buffer.BlockCopy(BitConverter.GetBytes(NetConvert.DoReverseEndian(ExtensionProfile)), 0, legacyHeader, 12 + 4 * CSRCCount, 2); - Buffer.BlockCopy(BitConverter.GetBytes(NetConvert.DoReverseEndian(ExtensionLength)), 0, legacyHeader, 14 + 4 * CSRCCount, 2); + Buffer.BlockCopy(BitConverter.GetBytes(NetConvert.DoReverseEndian(ExtensionProfile)), 0, header, 12 + 4 * CSRCCount, 2); + Buffer.BlockCopy(BitConverter.GetBytes(NetConvert.DoReverseEndian(ExtensionLength)), 0, header, 14 + 4 * CSRCCount, 2); } } else { - Buffer.BlockCopy(BitConverter.GetBytes(firstWord), 0, legacyHeader, 0, 2); - Buffer.BlockCopy(BitConverter.GetBytes(SequenceNumber), 0, legacyHeader, 2, 2); - Buffer.BlockCopy(BitConverter.GetBytes(Timestamp), 0, legacyHeader, 4, 4); - Buffer.BlockCopy(BitConverter.GetBytes(SyncSource), 0, legacyHeader, 8, 4); + Buffer.BlockCopy(BitConverter.GetBytes(firstWord), 0, header, 0, 2); + Buffer.BlockCopy(BitConverter.GetBytes(SequenceNumber), 0, header, 2, 2); + Buffer.BlockCopy(BitConverter.GetBytes(Timestamp), 0, header, 4, 4); + Buffer.BlockCopy(BitConverter.GetBytes(SyncSource), 0, header, 8, 4); if (HeaderExtensionFlag == 1) { - Buffer.BlockCopy(BitConverter.GetBytes(ExtensionProfile), 0, legacyHeader, 12 + 4 * CSRCCount, 2); - Buffer.BlockCopy(BitConverter.GetBytes(ExtensionLength), 0, legacyHeader, 14 + 4 * CSRCCount, 2); + Buffer.BlockCopy(BitConverter.GetBytes(ExtensionProfile), 0, header, 12 + 4 * CSRCCount, 2); + Buffer.BlockCopy(BitConverter.GetBytes(ExtensionLength), 0, header, 14 + 4 * CSRCCount, 2); } } if (ExtensionLength > 0 && ExtensionPayload != null) { - Buffer.BlockCopy(ExtensionPayload, 0, legacyHeader, 16 + 4 * CSRCCount, ExtensionLength * 4); + Buffer.BlockCopy(ExtensionPayload, 0, header, 16 + 4 * CSRCCount, ExtensionLength * 4); } - if (!legacyHeader.SequenceEqual(header.Take(Length))) - { - Debugger.Break(); - } -*/ return header; } diff --git a/src/net/RTP/RTPPacket.cs b/src/net/RTP/RTPPacket.cs index faa0c4d09..4da11bf74 100644 --- a/src/net/RTP/RTPPacket.cs +++ b/src/net/RTP/RTPPacket.cs @@ -15,33 +15,23 @@ //----------------------------------------------------------------------------- using System; -using System.IO; namespace SIPSorcery.Net { public class RTPPacket { public RTPHeader Header; - public byte[] Payload { get; private set; } - public int PayloadSize = -1; + public byte[] Payload; + public RTPPacket() { Header = new RTPHeader(); } - public RTPPacket(int payloadSize) { Header = new RTPHeader(); Payload = new byte[payloadSize]; - this.PayloadSize = payloadSize; - } - - public RTPPacket(byte[] payloadBuffer, int payloadSize) - { - Header = new RTPHeader(); - Payload = payloadBuffer; - this.PayloadSize = payloadSize; } public RTPPacket(byte[] packet) @@ -49,33 +39,15 @@ public RTPPacket(byte[] packet) Header = new RTPHeader(packet); Payload = new byte[Header.PayloadSize]; Array.Copy(packet, Header.Length, Payload, 0, Payload.Length); - this.PayloadSize = packet.Length; } - - public int CalculatedSize() - { - return Header.Length + PayloadSize; - } - - public int GetBytes(byte[] buffer) - { - if (buffer.Length < CalculatedSize()) - { - throw new InvalidDataException("buffer is too small"); - } - - Header.GetBytes(buffer); - Array.Copy(Payload, 0, buffer, Header.Length, PayloadSize); - return Header.Length+PayloadSize; - } public byte[] GetBytes() { byte[] header = Header.GetBytes(); byte[] packet = new byte[header.Length + Payload.Length]; Array.Copy(header, packet, header.Length); - Array.Copy(Payload, 0, packet, header.Length, PayloadSize); + Array.Copy(Payload, 0, packet, header.Length, Payload.Length); return packet; } diff --git a/src/net/RTP/VideoStream.cs b/src/net/RTP/VideoStream.cs index 222a701bb..54dd24161 100644 --- a/src/net/RTP/VideoStream.cs +++ b/src/net/RTP/VideoStream.cs @@ -15,7 +15,6 @@ //----------------------------------------------------------------------------- using System; -using System.Buffers; using System.Collections.Generic; using System.Linq; using System.Net; @@ -133,22 +132,13 @@ public void SendJpegFrame(uint duration, int payloadTypeID, byte[] jpegBytes, in /// See Annex B for byte stream specification. /// // The same URL without XML escape sequences: https://www.itu.int/rec/dologin_pub.asp?lang=e&id=T-REC-H.264-201602-S!!PDF-E&type=items - public void SendH264Frame(uint duration, int payloadTypeID, byte[] accessUnit, int index=-1, int length=-1) + public void SendH264Frame(uint duration, int payloadTypeID, byte[] accessUnit) { - if (index < 0) - { - index = 0; - } - - if (length < 0) - { - length = accessUnit.Length; - } if (CheckIfCanSendRtpRaw()) { - foreach (var nal in H264Packetiser.ParseNals(accessUnit,index,length)) + foreach (var nal in H264Packetiser.ParseNals(accessUnit)) { - SendH264Nal(duration, payloadTypeID, accessUnit, nal.IsLast,nal.Start,nal.Length); + SendH264Nal(duration, payloadTypeID, nal.NAL, nal.IsLast); } } } @@ -161,19 +151,19 @@ public void SendH264Frame(uint duration, int payloadTypeID, byte[] accessUnit, i /// The buffer containing the NAL to send. /// Should be set for the last NAL in the H264 access unit. Determines when the markbit gets set /// and the timestamp incremented. - private void SendH264Nal(uint duration, int payloadTypeID, byte[] nal, bool isLastNal,int arrIndex,int length) + private void SendH264Nal(uint duration, int payloadTypeID, byte[] nal, bool isLastNal) { //logger.LogDebug($"Send NAL {nal.Length}, is last {isLastNal}, timestamp {videoTrack.Timestamp}."); //logger.LogDebug($"nri {nalNri:X2}, type {nalType:X2}."); - byte nal0 = nal[arrIndex+0]; + byte nal0 = nal[0]; - if (length <= RTPSession.RTP_MAX_PAYLOAD) + if (nal.Length <= RTPSession.RTP_MAX_PAYLOAD) { // Send as Single-Time Aggregation Packet (STAP-A). - byte[] payload = new byte[length]; + byte[] payload = new byte[nal.Length]; int markerBit = isLastNal ? 1 : 0; // There is only ever one packet in a STAP-A. - Buffer.BlockCopy(nal, arrIndex, payload, 0, length); + Buffer.BlockCopy(nal, 0, payload, 0, nal.Length); SendRtpRaw(payload, LocalTrack.Timestamp, markerBit, payloadTypeID, true); //logger.LogDebug($"send H264 {videoChannel.RTPLocalEndPoint}->{dstEndPoint} timestamp {videoTrack.Timestamp}, payload length {payload.Length}, seqnum {videoTrack.SeqNum}, marker {markerBit}."); @@ -181,29 +171,25 @@ private void SendH264Nal(uint duration, int payloadTypeID, byte[] nal, bool isLa } else { - arrIndex++; - length--; - //nal = nal.Skip(1).ToArray(); + nal = nal.Skip(1).ToArray(); // Send as Fragmentation Unit A (FU-A): - for (int index = 0; index * RTPSession.RTP_MAX_PAYLOAD = length; + bool isFinalPacket = (index + 1) * RTPSession.RTP_MAX_PAYLOAD >= nal.Length; int markerBit = (isLastNal && isFinalPacket) ? 1 : 0; byte[] h264RtpHdr = H264Packetiser.GetH264RtpHeader(nal0, isFirstPacket, isFinalPacket); - byte[] payload = ArrayPool.Shared.Rent(payloadLength + h264RtpHdr.Length); - //byte[] payload = new byte[payloadLength + h264RtpHdr.Length]; + byte[] payload = new byte[payloadLength + h264RtpHdr.Length]; Buffer.BlockCopy(h264RtpHdr, 0, payload, 0, h264RtpHdr.Length); - Buffer.BlockCopy(nal, offset+arrIndex, payload, h264RtpHdr.Length, payloadLength); + Buffer.BlockCopy(nal, offset, payload, h264RtpHdr.Length, payloadLength); - SendRtpRaw(payload, LocalTrack.Timestamp, markerBit, payloadTypeID, true,dataLength:payloadLength + h264RtpHdr.Length); - ArrayPool.Shared.Return(payload); + SendRtpRaw(payload, LocalTrack.Timestamp, markerBit, payloadTypeID, true); //logger.LogDebug($"send H264 {videoChannel.RTPLocalEndPoint}->{dstEndPoint} timestamp {videoTrack.Timestamp}, FU-A {h264RtpHdr.HexStr()}, payload length {payloadLength}, seqnum {videoTrack.SeqNum}, marker {markerBit}."); } } @@ -269,7 +255,7 @@ public void SendVideo(uint durationRtpUnits, byte[] sample) SendVp8Frame(durationRtpUnits, payloadID, sample); break; case "H264": - SendH264Frame(durationRtpUnits, payloadID, sample,0,sample.Length); + SendH264Frame(durationRtpUnits, payloadID, sample); break; default: throw new ApplicationException($"Unsupported video format selected {videoSendingFormat.Name()}."); diff --git a/src/net/WebRTC/RTCPeerConnection.cs b/src/net/WebRTC/RTCPeerConnection.cs index 7c0d4dcb8..dbad165c2 100755 --- a/src/net/WebRTC/RTCPeerConnection.cs +++ b/src/net/WebRTC/RTCPeerConnection.cs @@ -1212,7 +1212,6 @@ private SDP createBaseSdp(List mediaStreamList, bool excludeIceCand string dtlsFingerprint = this.DtlsCertificateFingerprint.ToString(); bool iceCandidatesAdded = false; - // Local function to add ICE candidates to one of the media announcements. void AddIceCandidates(SDPMediaAnnouncement announcement) { diff --git a/src/sys/Crypto/Crypto.cs b/src/sys/Crypto/Crypto.cs index f90132aa0..bd4a64a3e 100644 --- a/src/sys/Crypto/Crypto.cs +++ b/src/sys/Crypto/Crypto.cs @@ -15,7 +15,6 @@ //----------------------------------------------------------------------------- using System; -using System.Buffers; using System.IO; using System.Linq; using System.Security.Cryptography; @@ -219,52 +218,31 @@ public static Int32 GetRandomInt(Int32 minValue, Int32 maxValue) public static UInt16 GetRandomUInt16() { - byte[] uint16Buffer = ArrayPool.Shared.Rent(2); - try - { - m_randomProvider.GetBytes(uint16Buffer); - return BitConverter.ToUInt16(uint16Buffer, 0); - } - finally - { - ArrayPool.Shared.Return(uint16Buffer); - } + byte[] uint16Buffer = new byte[2]; + m_randomProvider.GetBytes(uint16Buffer); + return BitConverter.ToUInt16(uint16Buffer, 0); } public static UInt32 GetRandomUInt(bool noZero = false) { - byte[] uint32Buffer = ArrayPool.Shared.Rent(4); - try - { - m_randomProvider.GetBytes(uint32Buffer); - var randomUint = BitConverter.ToUInt32(uint32Buffer, 0); - - if (noZero && randomUint == 0) - { - m_randomProvider.GetBytes(uint32Buffer); - randomUint = BitConverter.ToUInt32(uint32Buffer, 0); - } + byte[] uint32Buffer = new byte[4]; + m_randomProvider.GetBytes(uint32Buffer); + var randomUint = BitConverter.ToUInt32(uint32Buffer, 0); - return randomUint; - } - finally + if(noZero && randomUint == 0) { - ArrayPool.Shared.Return(uint32Buffer); + m_randomProvider.GetBytes(uint32Buffer); + randomUint = BitConverter.ToUInt32(uint32Buffer, 0); } + + return randomUint; } public static UInt64 GetRandomULong() { - byte[] uint64Buffer = ArrayPool.Shared.Rent(8); - try - { - m_randomProvider.GetBytes(uint64Buffer); - return BitConverter.ToUInt64(uint64Buffer, 0); - } - finally - { - ArrayPool.Shared.Return(uint64Buffer); - } + byte[] uint64Buffer = new byte[8]; + m_randomProvider.GetBytes(uint64Buffer); + return BitConverter.ToUInt64(uint64Buffer, 0); } public static byte[] createRandomSalt(int length) diff --git a/test/unit/net/SDP/SDPMediaAnnouncementUnitTests.cs b/test/unit/net/SDP/SDPMediaAnnouncementUnitTests.cs index a15471dc2..70424ea01 100644 --- a/test/unit/net/SDP/SDPMediaAnnouncementUnitTests.cs +++ b/test/unit/net/SDP/SDPMediaAnnouncementUnitTests.cs @@ -1,10 +1,6 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Net; -using System.Text; using Microsoft.Extensions.Logging; -using SIPSorcery.Sys; -using SIPSorceryMedia.Abstractions; using Xunit; namespace SIPSorcery.Net.UnitTests @@ -18,7 +14,8 @@ public class SDPMediaAnnouncementUnitTests public SDPMediaAnnouncementUnitTests(Xunit.Abstractions.ITestOutputHelper output) { logger = SIPSorcery.UnitTests.TestLogHelper.InitTestLogger(output); - } + } + /// /// Checks that the SDP with Message Media is well formatted. ///