diff --git a/Common/Classes/Disposables/BaseDisposable.cs b/Common/Classes/Disposables/BaseDisposable.cs index 37d9c2f2..3bc0ddd8 100644 --- a/Common/Classes/Disposables/BaseDisposable.cs +++ b/Common/Classes/Disposables/BaseDisposable.cs @@ -81,7 +81,7 @@ public abstract class BaseDisposable : IDisposed, IAsyncDisposable /// /// [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] - internal static long RetrieveState(BaseDisposable bd) { return bd.State; } + internal static int RetrieveState(BaseDisposable bd) { return bd.State; } /// /// Indicates the @@ -89,7 +89,7 @@ public abstract class BaseDisposable : IDisposed, IAsyncDisposable /// /// [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] - internal static bool IsDestructing(BaseDisposable bd, ref long state) { return (state = RetrieveState(bd)) > Disposed; } + internal static bool IsDestructing(BaseDisposable bd, ref int state) { return (state = RetrieveState(bd)) > Disposed; } /// /// If the sender is of the type then will be called to dispose the instance immediately. @@ -133,7 +133,7 @@ public static void SetShouldDispose(BaseDisposable toDispose, bool value, bool c /// The sign bit of the integer value is the only 'confusing' part about this and it must be understood because the Interlocked methods are CLS Compliant and do not expose unsigned counterparts. /// See the remarks section above for more clarity. /// - private long State; // = Undisposed; (Todo, internal protected and can remove Statics.. or new private protected and...) + private int State; // = Undisposed; (Todo, internal protected and can remove Statics.. or new private protected and...) #endregion @@ -188,9 +188,7 @@ protected internal bool IsUndisposed [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] get { - //return System.Threading.Thread.VolatileRead(ref State) == Undisposed; - //return (System.Threading.Interlocked.Read(ref State) & int.MaxValue).Equals(Undisposed); - return System.Threading.Interlocked.Read(ref State).Equals(Undisposed); + return System.Threading.Volatile.Read(ref State) == Undisposed; } } @@ -202,9 +200,7 @@ internal bool IsFinalized [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] get { - //return System.Threading.Thread.VolatileRead(ref State) == Finalized; - //return (System.Threading.Interlocked.Read(ref State) & int.MaxValue).Equals(Finalized); - return System.Threading.Interlocked.Read(ref State).Equals(Finalized); + return System.Threading.Volatile.Read(ref State) == Finalized; } } diff --git a/Common/Classes/Disposables/SuppressedFinalizerDisposable.cs b/Common/Classes/Disposables/SuppressedFinalizerDisposable.cs index 4a5c6d12..96fa21cb 100644 --- a/Common/Classes/Disposables/SuppressedFinalizerDisposable.cs +++ b/Common/Classes/Disposables/SuppressedFinalizerDisposable.cs @@ -55,7 +55,7 @@ public SuppressedFinalizerDisposable(bool shouldDispose) internal void Resurrect(ref int managedThreadId) { //Need to retrieve the state from this instance. - long state = 0; + int state = 0; //Not already disposed or destructing? if (IsUndisposed is false | BaseDisposable.IsDestructing(this, ref state) is false) return; diff --git a/Common/Collections/Generic/ConcurrentLinkedQueueSlim.cs b/Common/Collections/Generic/ConcurrentLinkedQueueSlim.cs index 3ac8f766..edd4c3eb 100644 --- a/Common/Collections/Generic/ConcurrentLinkedQueueSlim.cs +++ b/Common/Collections/Generic/ConcurrentLinkedQueueSlim.cs @@ -41,6 +41,7 @@ The above copyright notice and this permission notice shall be included in all c using System; using System.Collections.Generic; using System.Linq; +using System.Threading; #endregion @@ -217,7 +218,7 @@ public long Count public bool IsEmpty { [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] - get { return Count is Common.Binary.LongZero; } + get { return Volatile.Read(ref First) is null; } } #endregion @@ -324,8 +325,7 @@ public bool TryPeek(ref T t) [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] public void Enqueue(T t) { - bool added = false; - + bool added; do added = TryEnqueue(ref t); while (added is false); } diff --git a/Common/Extensions/SocketExtensions.cs b/Common/Extensions/SocketExtensions.cs index cf41380a..67eba78b 100644 --- a/Common/Extensions/SocketExtensions.cs +++ b/Common/Extensions/SocketExtensions.cs @@ -963,15 +963,9 @@ public static void DisableAddressReuse(System.Net.Sockets.Socket socket, bool ex #region UnicastPortReuse - //Notes 4.6 has ReuseUnicastPort - - private const int ReuseUnicastPort = 0x3007; // 12295 - - private static readonly System.Net.Sockets.SocketOptionName ReuseUnicastPortOption = (System.Net.Sockets.SocketOptionName)ReuseUnicastPort; - public static void SetUnicastPortReuse(System.Net.Sockets.Socket socket, int value) { - socket.SetSocketOption(System.Net.Sockets.SocketOptionLevel.Socket, ReuseUnicastPortOption, value); + socket.SetSocketOption(System.Net.Sockets.SocketOptionLevel.Socket, System.Net.Sockets.SocketOptionName.ReuseUnicastPort, value); } public static void DisableUnicastPortReuse(System.Net.Sockets.Socket socket) diff --git a/Http/HttpClient.cs b/Http/HttpClient.cs index 758b2502..159c77ef 100644 --- a/Http/HttpClient.cs +++ b/Http/HttpClient.cs @@ -1299,6 +1299,7 @@ m_LastTransmitted is not null && message is not null && catch (Exception ex) { Common.ILoggingExtensions.Log(Logger, ToString() + "@SendHttpMessage: " + ex.Message); + Common.ILoggingExtensions.LogException(Logger, ex); } finally { diff --git a/Rtp/RtpClient.Fields.cs b/Rtp/RtpClient.Fields.cs index 74a49022..050973b5 100644 --- a/Rtp/RtpClient.Fields.cs +++ b/Rtp/RtpClient.Fields.cs @@ -56,13 +56,16 @@ public partial class RtpClient internal bool m_StopRequested, m_ThreadEvents, //on or off right now, int could allow levels of threading.. m_IListSockets; //Indicates if to use the IList send overloads. + // How much time to wait between event queue checks. + private System.TimeSpan m_WaitIntervalBetweenEvents = Media.Common.Extensions.TimeSpan.TimeSpanExtensions.OneMillisecond; + //Collection to handle the dispatch of events. //Notes that Collections.Concurrent.Queue may be better suited for this in production until the ConcurrentLinkedQueue has been thoroughly engineered and tested. //The context, the item, final, recieved private readonly Media.Common.Collections.Generic.ConcurrentLinkedQueueSlim<(RtpClient.TransportContext Context, Common.BaseDisposable Packet, bool Final, bool Received)> m_EventData = new(); //Todo, LinkedQueue and Clock. - private readonly System.Threading.ManualResetEventSlim m_EventReady = new(false, 100); //should be caluclated based on memory and speed. SpinWait uses 10 as a default. + private readonly System.Threading.ManualResetEventSlim m_EventReady = new(false, spinCount: 20); //should be caluclated based on memory and speed. SpinWait uses 10 as a default. //Outgoing Packets, Not a Queue because you cant re-order a Queue (in place) and you can't take a range from the Queue (in a single operation) //Those things aside, ordering is not performed here and only single packets are iterated and would eliminate the need for removing after the operation. diff --git a/Rtp/RtpClient.Methods.cs b/Rtp/RtpClient.Methods.cs index 5b7a4a05..10132f88 100644 --- a/Rtp/RtpClient.Methods.cs +++ b/Rtp/RtpClient.Methods.cs @@ -2256,7 +2256,7 @@ private void HandleEvents() m_EventReady.Reset(); while (IsActive && m_EventData.IsEmpty) - m_EventReady.Wait(Common.Extensions.TimeSpan.TimeSpanExtensions.OneMicrosecond); + m_EventReady.Wait(WaitIntervalBetweenEvents); } else if (IsActive is false) break; @@ -2267,7 +2267,13 @@ private void HandleEvents() HandleEvent(); } } - catch (System.Exception ex) { Media.Common.ILoggingExtensions.Log(Logger, ToString() + "@HandleEvents: " + ex.Message); goto Begin; } + catch (System.Exception ex) + { + Media.Common.ILoggingExtensions.Log(Logger, ToString() + "@HandleEvents: " + ex.Message); + Media.Common.ILoggingExtensions.LogException(Logger, ex); + + goto Begin; + } } } @@ -2777,6 +2783,7 @@ private void SendReceieve() catch (System.Exception ex) { Media.Common.ILoggingExtensions.Log(Logger, ToString() + "@SendRecieve: " + ex.Message); + Media.Common.ILoggingExtensions.LogException(Logger, ex); if (critical) System.Threading.Thread.EndCriticalRegion(); diff --git a/Rtp/RtpClient.cs b/Rtp/RtpClient.cs index a7c90757..5d457d5c 100644 --- a/Rtp/RtpClient.cs +++ b/Rtp/RtpClient.cs @@ -3912,6 +3912,19 @@ public bool IListSockets } } + /// + /// How much time to wait between event queue checks. + /// High values reduce event handling speed / FPS, but also reduce CPU consumption. + /// + public TimeSpan WaitIntervalBetweenEvents + { + [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.Synchronized | System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] + get => m_WaitIntervalBetweenEvents; + + [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.Synchronized | System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] + set => m_WaitIntervalBetweenEvents = value; + } + /// /// Gets or sets a value which indicates if events will be threaded or not. /// If threading is enabled the call will block until the event thread has started. diff --git a/Rtsp/RtspClient.cs b/Rtsp/RtspClient.cs index e803f2b7..078ba3b8 100644 --- a/Rtsp/RtspClient.cs +++ b/Rtsp/RtspClient.cs @@ -1019,6 +1019,7 @@ public bool IsPlaying catch (Exception ex) { Media.Common.ILoggingExtensions.Log(Logger, ToString() + "@IsPlaying - " + ex.Message); + Media.Common.ILoggingExtensions.LogException(Logger, ex); } } @@ -3083,7 +3084,7 @@ public void StopPlaying(IEnumerable mediaDescriptions, bool fo public void StopPlaying(bool disconnectSocket = true) { try { Disconnect(disconnectSocket); } - catch (Exception ex) { Media.Common.ILoggingExtensions.Log(Logger, ex.Message); } + catch (Exception ex) { Media.Common.ILoggingExtensions.LogException(Logger, ex); } } [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.Synchronized)] @@ -3318,7 +3319,7 @@ message header. } catch (Exception ex) { - Common.ILoggingExtensions.Log(Logger, ex.Message); + Common.ILoggingExtensions.LogException(Logger, ex); throw; } @@ -4623,6 +4624,7 @@ SharesSocket is false && catch (Exception ex) { Common.ILoggingExtensions.Log(Logger, ToString() + "@SendRtspMessage: " + ex.Message); + Common.ILoggingExtensions.LogException(Logger, ex); } finally { @@ -5967,7 +5969,11 @@ InUse is false && DisableKeepAliveRequest = keepAlives; } } - catch (Exception ex) { Common.ILoggingExtensions.Log(Logger, ToString() + "@MonitorProtocol: " + ex.Message); } + catch (Exception ex) + { + Common.ILoggingExtensions.Log(Logger, ToString() + "@MonitorProtocol: " + ex.Message); + Common.ILoggingExtensions.LogException(Logger, ex); + } //If not disposed AND IsConnected and if protocol switch is still allowed AND IsPlaying and not already TCP if (Common.IDisposedExtensions.IsNullOrDisposed(this) is false && @@ -6047,6 +6053,7 @@ tc.TotalPacketsSent is Common.Binary.LongZero && catch (Exception ex) { Common.ILoggingExtensions.Log(Logger, ToString() + "@MonitorProtocol: " + ex.Message); + Common.ILoggingExtensions.LogException(Logger, ex); } } } @@ -6070,8 +6077,19 @@ tc.TotalPacketsSent is Common.Binary.LongZero && //If there is still a timer change it based on the last messages round trip time, should be relative to all messages... if (Common.IDisposedExtensions.IsNullOrDisposed(this) is false && m_ProtocolMonitor is not null) - try { m_ProtocolMonitor.Change(m_ConnectionTime.Add(LastMessageRoundTripTime), Media.Common.Extensions.TimeSpan.TimeSpanExtensions.InfiniteTimeSpan); } - catch (Exception ex) { Common.ILoggingExtensions.Log(Logger, ToString() + "@MonitorProtocol: " + ex.Message); } + try + { + m_ProtocolMonitor.Change + ( + m_ConnectionTime.Add(LastMessageRoundTripTime), + Media.Common.Extensions.TimeSpan.TimeSpanExtensions.InfiniteTimeSpan + ); + } + catch (Exception ex) + { + Common.ILoggingExtensions.Log(Logger, ToString() + "@MonitorProtocol: " + ex.Message); + Common.ILoggingExtensions.LogException(Logger, ex); + } } public RtspMessage SendPlay(MediaDescription mediaDescription, TimeSpan? startTime = null, TimeSpan? endTime = null, string rangeType = "npt") @@ -6514,7 +6532,11 @@ context.Goodbye is null || } } - catch (Exception ex) { Common.ILoggingExtensions.Log(Logger, ToString() + "@SendKeepAlive: " + ex.Message); } + catch (Exception ex) + { + Common.ILoggingExtensions.Log(Logger, ToString() + "@SendKeepAlive: " + ex.Message); + Common.ILoggingExtensions.LogException(Logger, ex); + } //Raise the stopping event if not playing anymore //if (true == wasPlaying && false == IsPlaying) OnStopping(); diff --git a/Rtsp/RtspSession.cs b/Rtsp/RtspSession.cs index 91d1d3ee..38694696 100644 --- a/Rtsp/RtspSession.cs +++ b/Rtsp/RtspSession.cs @@ -752,6 +752,7 @@ public bool IsPlaying catch (Exception ex) { Media.Common.ILoggingExtensions.Log(Logger, ToString() + "@IsPlaying - " + ex.Message); + Media.Common.ILoggingExtensions.LogException(Logger, ex); } } @@ -1702,6 +1703,7 @@ SharesSocket is false && catch (Exception ex) { Common.ILoggingExtensions.Log(Logger, ToString() + "@SendRtspMessage: " + ex.Message); + Common.ILoggingExtensions.LogException(Logger, ex); } finally { @@ -2399,7 +2401,7 @@ message header. } catch (Exception ex) { - Common.ILoggingExtensions.Log(Logger, ex.Message); + Common.ILoggingExtensions.LogException(Logger, ex); throw; } diff --git a/RtspServer/MediaTypes/RFC2435Media.cs b/RtspServer/MediaTypes/RFC2435Media.cs index bc4f8fa4..d23706c8 100644 --- a/RtspServer/MediaTypes/RFC2435Media.cs +++ b/RtspServer/MediaTypes/RFC2435Media.cs @@ -2527,7 +2527,7 @@ internal override void SendPackets() { try { - if (Frames.Count is 0 && State == StreamState.Started) + if (Frames.IsEmpty && State == StreamState.Started) { if (RtpClient.IsActive) RtpClient.m_WorkerThread.Priority = System.Threading.ThreadPriority.Lowest; diff --git a/RtspServer/MediaTypes/RtpAudioSink.cs b/RtspServer/MediaTypes/RtpAudioSink.cs index 247e4e7f..a98ffb22 100644 --- a/RtspServer/MediaTypes/RtpAudioSink.cs +++ b/RtspServer/MediaTypes/RtpAudioSink.cs @@ -68,7 +68,7 @@ internal override void SendPackets() { try { - if (Frames.Count is 0 && State == StreamState.Started) + if (Frames.IsEmpty && State == StreamState.Started) { if (RtpClient.IsActive) RtpClient.m_WorkerThread.Priority = System.Threading.ThreadPriority.Lowest; diff --git a/RtspServer/MediaTypes/RtpSink.cs b/RtspServer/MediaTypes/RtpSink.cs index cb9c31b9..54c3fa0b 100644 --- a/RtspServer/MediaTypes/RtpSink.cs +++ b/RtspServer/MediaTypes/RtpSink.cs @@ -155,7 +155,7 @@ internal virtual void SendPackets() { try { - if (Packets.Count is 0) + if (Packets.IsEmpty) { System.Threading.Thread.Sleep(0); diff --git a/RtspServer/MediaTypes/RtpVideoSink.cs b/RtspServer/MediaTypes/RtpVideoSink.cs index d5c1c45a..bb27e6d2 100644 --- a/RtspServer/MediaTypes/RtpVideoSink.cs +++ b/RtspServer/MediaTypes/RtpVideoSink.cs @@ -188,7 +188,7 @@ internal override void SendPackets() { try { - if (Frames.Count is 0 && State is StreamState.Started) + if (Frames.IsEmpty && State is StreamState.Started) { if (RtpClient.IsActive) RtpClient.m_WorkerThread.Priority = ThreadPriority.Lowest; diff --git a/RtspServer/RtspServer.cs b/RtspServer/RtspServer.cs index fd70f659..f4dc970e 100644 --- a/RtspServer/RtspServer.cs +++ b/RtspServer/RtspServer.cs @@ -65,6 +65,12 @@ public class RtspServer : Common.BaseDisposable, Common.ISocketReference, Common //Milliseconds internal const int DefaultSendTimeout = 500; + // Minimum timout to use for RTSP clients. + private readonly TimeSpan MinimumRtspClientInactivityTimeout = TimeSpan.FromSeconds(1); + + // Default timout to use for RTSP clients. + private readonly TimeSpan DefaultRtspClientInactivityTimeout = TimeSpan.FromSeconds(60); + internal static void ConfigureRtspServerThread(Thread thread) { thread.TrySetApartmentState(ApartmentState.MTA); @@ -255,17 +261,35 @@ internal static void ConfigureRtspServerSocket(Socket socket, out int interFrame private Thread m_ServerThread; /// - /// Indicates to the ServerThread a stop has been requested + /// Indicates to the ServerThread a stop has been requested. /// - private bool m_StopRequested, m_Maintaining; + private int m_StopRequested, m_Maintaining; //Handles the Restarting of streams which needs to be and disconnects clients which are inactive. - internal Timer m_Maintainer; + internal volatile Timer m_Maintainer; #endregion #region Propeties + /// + /// Is stop requested? Thread-safe as required. + /// + private bool IsStopRequested + { + get => Volatile.Read(ref m_StopRequested) == 1; + set => Interlocked.Exchange(ref m_StopRequested, value ? 1 : 0); + } + + /// + /// Is maintaining server? Thread-safe as required. + /// + private bool IsMaintaining + { + get => Volatile.Read(ref m_Maintaining) == 1; + set => Interlocked.Exchange(ref m_Maintaining, value ? 1 : 0); + } + public Media.Rtsp.Server.RtspStreamArchiver Archiver { [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] @@ -427,7 +451,7 @@ public bool IsRunning get { return IsDisposed is false && - m_StopRequested is false && + IsStopRequested is false && m_Started.HasValue && m_ServerThread is not null; } @@ -646,16 +670,18 @@ public void RemoveRequestHandler(RtspMethod method) //Todo //Allow for joining of server instances to support multiple end points. - public RtspServer(AddressFamily addressFamily = AddressFamily.InterNetwork, int listenPort = DefaultPort, bool shouldDispose = true) - : this(new IPEndPoint(Media.Common.Extensions.Socket.SocketExtensions.GetFirstUnicastIPAddress(addressFamily), listenPort), shouldDispose) { } + public RtspServer(AddressFamily addressFamily, int listenPort, TimeSpan? inactivityTimeout = null, bool shouldDispose = true) + : this(new IPEndPoint(Media.Common.Extensions.Socket.SocketExtensions.GetFirstUnicastIPAddress(addressFamily), listenPort), inactivityTimeout, shouldDispose) { } - public RtspServer(IPAddress listenAddress, int listenPort, bool shouldDispose = true) - : this(new IPEndPoint(listenAddress, listenPort), shouldDispose) { } + public RtspServer(IPAddress listenAddress, int listenPort, TimeSpan? inactivityTimeout = null, bool shouldDispose = true) + : this(new IPEndPoint(listenAddress, listenPort), inactivityTimeout, shouldDispose) { } - public RtspServer(IPEndPoint listenEndPoint, bool shouldDispose = true) + public RtspServer(IPEndPoint listenEndPoint, TimeSpan? inactivityTimeout = null, bool shouldDispose = true) : base(shouldDispose) { - RtspClientInactivityTimeout = TimeSpan.FromSeconds(60); + RtspClientInactivityTimeout = inactivityTimeout.HasValue + ? Media.Common.Extensions.TimeSpan.TimeSpanExtensions.Max(inactivityTimeout.Value, MinimumRtspClientInactivityTimeout) + : DefaultRtspClientInactivityTimeout; //Check syntax of Server header to ensure allowed format... ServerName = "ASTI Media Server RTSP\\" + Version.ToString(RtspMessage.VersionFormat, System.Globalization.CultureInfo.InvariantCulture); @@ -1210,7 +1236,7 @@ public virtual async Task StartAsync(bool allowAddressReuse = false, bool allowP if (IsRunning) return; //Allowed to run - m_Maintaining = m_StopRequested = false; + IsMaintaining = IsStopRequested = false; //Indicate start was called Common.ILoggingExtensions.Log(Logger, "Server Started @ " + DateTime.UtcNow); @@ -1262,10 +1288,10 @@ public virtual async Task StartAsync(bool allowAddressReuse = false, bool allowP //Start it m_ServerThread.Start(); - //Timer for maintaince ( one quarter of the ticks) + //Timer for maintaince (one quarter of the ticks) m_Maintainer = new Timer(MaintainServer, null, - TimeSpan.FromTicks(RtspClientInactivityTimeout.Ticks >> 2), + TimeSpan.FromTicks(Math.Max(RtspClientInactivityTimeout.Ticks >> 4, MinimumRtspClientInactivityTimeout.Ticks)), Media.Common.Extensions.TimeSpan.TimeSpanExtensions.InfiniteTimeSpan); if (m_UdpPort >= 0) EnableUnreliableTransport(m_UdpPort); @@ -1290,11 +1316,11 @@ public virtual async Task StartAsync(bool allowAddressReuse = false, bool allowP /// Reserved internal virtual void MaintainServer(object state = null) { - if (m_Maintaining || IsDisposed || m_StopRequested) return; + if (IsMaintaining || IsDisposed || IsStopRequested) return; - if (IsRunning && m_Maintaining is false) + if (IsRunning && IsMaintaining is false) { - m_Maintaining = true; + IsMaintaining = true; try { @@ -1315,7 +1341,7 @@ internal virtual void MaintainServer(object state = null) MediaStreams.AsParallel().ForAll(s => s.TrySetLogger(Logger)); - m_Maintaining = false; + IsMaintaining = false; if (IsRunning && m_Maintainer is not null) { @@ -1336,7 +1362,7 @@ internal virtual void MaintainServer(object state = null) { Common.ILoggingExtensions.LogException(Logger, ex); - m_Maintaining = m_Maintainer is not null; + IsMaintaining = m_Maintainer is not null; } } } @@ -1353,7 +1379,7 @@ public virtual async Task StopAsync(bool leaveOpen = false) if (IsRunning is false) return; //Stop listening for new clients - m_StopRequested = true; + IsStopRequested = true; Common.ILoggingExtensions.Log(Logger, "@Stop - StopRequested"); Common.ILoggingExtensions.Log(Logger, "Connected Clients:" + ActiveConnections); @@ -1415,7 +1441,7 @@ internal virtual async Task StartStreamsAsync() foreach (Media.Rtsp.Server.IMedia stream in MediaStreams) { - if (m_StopRequested) return; + if (IsStopRequested) return; streamTasks.Add(StartStreamAsync(stream)); } @@ -1509,9 +1535,10 @@ internal void AcceptLoop() //While running while (IsRunning) { - if (m_StopRequested) + if (IsStopRequested) break; - else if (m_Sessions.Count < m_MaximumSessions) + + if (m_Sessions.Count < m_MaximumSessions) { //If not already accepting if (lastAccept is null) @@ -1560,7 +1587,7 @@ internal void AcceptLoop() { Common.ILoggingExtensions.LogException(Logger, ex); - if (m_StopRequested) return; + if (IsStopRequested) return; goto Begin; } @@ -2245,7 +2272,7 @@ generated URLs. //Then it would also be easier to make /audio only passwords etc. //When stopping only handle teardown and keep alives - if (m_StopRequested && + if (IsStopRequested && (request.ContainsHeader(RtspHeaders.Connection) is false || (request.RtspMethod != RtspMethod.TEARDOWN && request.RtspMethod != RtspMethod.GET_PARAMETER && request.RtspMethod != RtspMethod.OPTIONS))) { diff --git a/UnitTests/Program.cs b/UnitTests/Program.cs index de172a6c..9b92861d 100644 --- a/UnitTests/Program.cs +++ b/UnitTests/Program.cs @@ -144,15 +144,15 @@ public class Program public static async Task Main(string[] args) { //Run the main tests - foreach (Action test in LogicTests) RunTest(test); + //foreach (Action test in LogicTests) RunTest(test); - Console.WriteLine("Logic Tests Complete! Press Q to Exit or any other key to perform the live tests."); + //Console.WriteLine("Logic Tests Complete! Press Q to Exit or any other key to perform the live tests."); - if (Console.ReadKey(true).Key == ConsoleKey.Q) return; + //if (Console.ReadKey(true).Key == ConsoleKey.Q) return; - RunTest(HttpClientTests); + //RunTest(HttpClientTests); - RunTest(RtspClientTests); + //RunTest(RtspClientTests); await RunTestAsync(TestServerAsync, nameof(TestServerAsync)).ConfigureAwait(false); } @@ -2471,10 +2471,6 @@ private static async Task TestServerAsync() { server.Logger.LogException(ex); - gfxScreenshot.Dispose(); - - bmpScreenshot.Dispose(); - if (server is not null && server.IsRunning) goto Start; } }