private void streamLoop_inner(object objArgs)
        {
            Stopwatch frameTimer = new Stopwatch();

            frameTimer.Start();
            long             nextFrameStart = 0;
            StreamThreadArgs args           = (StreamThreadArgs)objArgs;

            while (!args.abortFlag.abort)
            {
                try
                {
                    int sleepTime = (int)(nextFrameStart - frameTimer.ElapsedMilliseconds);
                    while (sleepTime > 0 || (Interlocked.Read(ref args.numSentFrames) >= Interlocked.Read(ref args.numAcknowledgedFrames) + maxUnacknowledgedFrames))
                    {
                        if (args.abortFlag.abort)
                        {
                            return;
                        }
                        Thread.Sleep(BPMath.Clamp(sleepTime, 1, 10));
                        sleepTime = (int)(nextFrameStart - frameTimer.ElapsedMilliseconds);
                    }
                    if (args.abortFlag.abort)
                    {
                        return;
                    }

                    nextFrameStart = frameTimer.ElapsedMilliseconds + (1000 / maxFPS);

                    if (streamerController == null)
                    {
                        return;
                    }
                    FragmentedImage fragmentedImage = streamerController.GetRawDesktopCapture(imgFlags, jpegQuality, args.abortFlag);
                    if (args.abortFlag.abort)
                    {
                        return;
                    }
                    if (fragmentedImage == null)
                    {
                        fragmentedImage = new FragmentedImage();
                    }
                    fragmentedImage.streamId = (byte)args.myStreamNumber;
                    using (MemoryDataStream mds = new MemoryDataStream(fragmentedImage.GetMaximumRequiredBufferSize()))
                    {
                        byte[] compressionBuffer = null;
                        fragmentedImage.WriteToDataStream(mds, ref compressionBuffer);
                        Interlocked.Increment(ref args.numSentFrames);
                        socket.Send(mds.ToArray());
                    }
                }
                catch (ThreadAbortException) { throw; }
                catch (Exception ex)
                {
                    Logger.Debug(ex);
                }
            }
        }
        private void StartStreaming(byte[] buf)
        {
            streamThreadArgs            = new StreamThreadArgs(Interlocked.Read(ref activeStreamNumber));
            streamThreadArgs.streamType = (StreamType)buf[1]; // TODO: Use streamType
            streamThreadArgs.displayIdx = buf[2];             // TODO: Use displayIdx

            streamingThread              = new Thread(streamLoop);
            streamingThread.Name         = "WebSocket Streaming";
            streamingThread.IsBackground = true;
            streamingThread.Start(streamThreadArgs);
        }