Пример #1
0
        /// <summary>
        /// Removes current <see cref="Head"/> frame from the <see cref="FrameQueue"/> after it has been processed and assigns a new <see cref="Head"/>.
        /// </summary>
        public void Pop()
        {
            // We track latest published ticks - don't want to allow slow moving measurements
            // to inject themselves after a certain publication time frame has passed - this
            // avoids any possible out-of-sequence frame publication...
            m_last = m_head;
            m_head = null;
            long publishedTicks = m_last.Timestamp;

            Thread.VolatileWrite(ref m_publishedTicks, publishedTicks);

            // Assign next node, if any, as quickly as possible. Still have to wait for queue
            // lock - tick-tock, time's-a-wastin' and user function needs a frame to publish.
#if MONO
            lock (m_queueLock)
            {
#else
            bool locked = false;

            try
            {
                m_queueLock.Enter(ref locked);
#endif
                if (m_frameList.Count > 0)
                {
                    LinkedListNode <TrackingFrame> nextNode = m_frameList.First.Next;

                    // If next frame is available, go ahead and assign it...
                    if (nextNode != null)
                    {
                        m_head = nextNode.Value;
                    }

                    // Clean up frame queues
                    m_frameList.RemoveFirst();
                }
            }
#if !MONO
            finally
            {
                if (locked)
                {
                    m_queueLock.Exit();
                }
            }
#endif
            TrackingFrame frame;
            m_frameHash.TryRemove(publishedTicks, out frame);
        }
Пример #2
0
        /// <summary>
        /// Releases the unmanaged resources used by the <see cref="FrameQueue"/> object and optionally releases the managed resources.
        /// </summary>
        /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>
        protected virtual void Dispose(bool disposing)
        {
            if (!m_disposed)
            {
                try
                {
                    if (disposing)
                    {
                        Clear();
                        m_frameList = null;
                        m_frameHash = null;

                        m_createNewFrame = null;
                        m_head           = null;
                        m_last           = null;
                    }
                }
                finally
                {
                    m_disposed = true;  // Prevent duplicate dispose.
                }
            }
        }
Пример #3
0
        /// <summary>
        /// Gets <see cref="TrackingFrame"/> from the queue with the specified timestamp, in ticks.  If no frame exists for
        /// the specified timestamp, one will be created.
        /// </summary>
        /// <param name="ticks">Timestamp, in ticks, for which to get or create <see cref="TrackingFrame"/>.</param>
        /// <remarks>
        /// Ticks can be any point in time so long time requested is greater than time of last published frame; this queue is
        /// used in a real-time scenario with time moving forward.  If a frame is requested for an old timestamp, null will
        /// be returned. Note that frame returned will be "best-fit" for given timestamp based on <see cref="FramesPerSecond"/>.
        /// </remarks>
        /// <returns>An existing or new <see cref="TrackingFrame"/> from the queue for the specified timestamp.</returns>
        public TrackingFrame GetFrame(long ticks)
        {
            // Calculate destination ticks for this frame
            TrackingFrame frame = null;
            bool          locked = false, nodeAdded = false;
            long          baseTicks, ticksBeyondSecond, frameIndex, destinationTicks, nextDestinationTicks;

            // Baseline timestamp to the top of the second
            baseTicks = ticks - ticks % Ticks.PerSecond;

            // Remove the seconds from ticks
            ticksBeyondSecond = ticks - baseTicks;

            // Calculate a frame index between 0 and m_framesPerSecond-1, corresponding to ticks
            // rounded down to the nearest frame
            frameIndex = (long)(ticksBeyondSecond / m_ticksPerFrame);

            // Calculate the timestamp of the nearest frame rounded up
            nextDestinationTicks = (frameIndex + 1) * Ticks.PerSecond / m_framesPerSecond;

            // Determine whether the desired frame is the nearest
            // frame rounded down or the nearest frame rounded up
            if (m_timeResolution <= 1)
            {
                if (nextDestinationTicks <= ticksBeyondSecond)
                {
                    destinationTicks = nextDestinationTicks;
                }
                else
                {
                    destinationTicks = frameIndex * Ticks.PerSecond / m_framesPerSecond;
                }
            }
            else
            {
                // If, after translating nextDestinationTicks to the time resolution, it is less than
                // or equal to ticks, nextDestinationTicks corresponds to the desired frame
                if ((nextDestinationTicks / m_timeResolution) * m_timeResolution <= ticksBeyondSecond)
                {
                    destinationTicks = nextDestinationTicks;
                }
                else
                {
                    destinationTicks = frameIndex * Ticks.PerSecond / m_framesPerSecond;
                }
            }

            // Recover the seconds that were removed
            destinationTicks += baseTicks;

            // Make sure ticks are newer than latest published ticks...
            if (destinationTicks > Thread.VolatileRead(ref m_publishedTicks))
            {
                // See if requested frame is already available (can do this outside lock with concurrent dictionary)
                if (m_frameHash.TryGetValue(destinationTicks, out frame))
                {
                    return(frame);
                }

                // Didn't find frame for this timestamp so we need to add a new one to the queue
                try
                {
                    m_queueLock.Enter(ref locked);

                    // Another thread may have gotten to this task already, so check for this contingency...
                    if (m_frameHash.TryGetValue(destinationTicks, out frame))
                    {
                        return(frame);
                    }

                    // Create a new frame for this timestamp
                    frame = new TrackingFrame(m_createNewFrame(destinationTicks), m_downsamplingMethod);

                    if (m_frameList.Count > 0)
                    {
                        // Insert frame into proper sorted position...
                        LinkedListNode <TrackingFrame> node = m_frameList.Last;

                        do
                        {
                            if (destinationTicks > node.Value.Timestamp)
                            {
                                m_frameList.AddAfter(node, frame);
                                nodeAdded = true;
                                break;
                            }

                            node = node.Previous;
                        }while (node != null);
                    }

                    if (!nodeAdded)
                    {
                        m_frameList.AddFirst(frame);
                        m_head = frame;
                    }

                    // Since we'll be requesting this frame over and over, we'll use
                    // a hash table for quick frame lookups by timestamp
                    m_frameHash[destinationTicks] = frame;
                }
                finally
                {
                    if (locked)
                    {
                        m_queueLock.Exit();
                    }
                }
            }

            return(frame);
        }
Пример #4
0
        /// <summary>
        /// Gets <see cref="TrackingFrame"/> from the queue with the specified timestamp, in ticks.  If no frame exists for
        /// the specified timestamp, one will be created.
        /// </summary>
        /// <param name="ticks">Timestamp, in ticks, for which to get or create <see cref="TrackingFrame"/>.</param>
        /// <remarks>
        /// Ticks can be any point in time so long time requested is greater than time of last published frame; this queue is
        /// used in a real-time scenario with time moving forward.  If a frame is requested for an old timestamp, null will
        /// be returned. Note that frame returned will be "best-fit" for given timestamp based on <see cref="FramesPerSecond"/>.
        /// </remarks>
        /// <returns>An existing or new <see cref="TrackingFrame"/> from the queue for the specified timestamp.</returns>
        public TrackingFrame GetFrame(long ticks)
        {
            TrackingFrame frame = null;
            bool nodeAdded = false;
            long destinationTicks;

            // Calculate destination ticks for this frame
            destinationTicks = Ticks.AlignToSubsecondDistribution(ticks, m_framesPerSecond, m_timeResolution);

            // Make sure ticks are newer than latest published ticks...
            if (destinationTicks > Thread.VolatileRead(ref m_publishedTicks))
            {
                // See if requested frame is already available (can do this outside lock with concurrent dictionary)
                if (m_frameHash.TryGetValue(destinationTicks, out frame))
                    return frame;

                // Didn't find frame for this timestamp so we need to add a new one to the queue
#if MONO
                lock (m_queueLock)
                {
#else
                bool locked = false;

                try
                {
                    m_queueLock.Enter(ref locked);
#endif
                    // Another thread may have gotten to this task already, so check for this contingency...
                    if (m_frameHash.TryGetValue(destinationTicks, out frame))
                        return frame;

                    // TODO: Add a flag to add frames to publish even if no data arrives for them as an alternate mode
                    // TODO: of operation. In this mode pre-populate frame queue with at least one second of data from
                    // TODO: given start time (was thinking up next even second). This mode is useful for generically
                    // TODO: using concentrator to create a set of frame data from a data set with possible missing
                    // TODO: data (e.g., a historian) to create an evenly timestamped export

                    // Create a new frame for this timestamp
                    frame = new TrackingFrame(m_createNewFrame(destinationTicks), m_downsamplingMethod);

                    if (m_frameList.Count > 0)
                    {
                        // Insert frame into proper sorted position...
                        LinkedListNode<TrackingFrame> node = m_frameList.Last;

                        do
                        {
                            if (destinationTicks > node.Value.Timestamp)
                            {
                                m_frameList.AddAfter(node, frame);
                                nodeAdded = true;
                                break;
                            }

                            node = node.Previous;
                        }
                        while (node != null);
                    }

                    if (!nodeAdded)
                    {
                        m_frameList.AddFirst(frame);
                        m_head = frame;
                    }

                    // Since we'll be requesting this frame over and over, we'll use
                    // a hash table for quick frame lookups by timestamp
                    m_frameHash[destinationTicks] = frame;
                }
#if !MONO
                finally
                {
                    if (locked)
                        m_queueLock.Exit();
                }
#endif
            }

            return frame;
        }

        #region [ GetFrame Testing Algorithm ]

        // Copy this code into a console application and reference GSF.Core.dll to test.

        //using System;
        //using System.Collections.Generic;
        //using System.Linq;
        //using System.Text;
        //using GSF;

        //namespace FrameTimestampTest
        //{
        //    public class Program
        //    {
        //        private static long s_timeResolution;
        //        private static long s_framesPerSecond;
        //        private static double s_ticksPerFrame;
        //        private static double s_millisecondsPerFrame;

        //        public static void Main(string[] args)
        //        {
        //            s_framesPerSecond = 30;
        //            s_ticksPerFrame = Ticks.PerSecond / (double)s_framesPerSecond;
        //            s_timeResolution = Ticks.PerMillisecond;
        //            s_millisecondsPerFrame = 1000.0 / s_framesPerSecond;

        //            // Test BPA PDCstream style milliseconds
        //            DateTime currentTime = DateTime.Now;
        //            int[] bpaMilliseconds = new int[] { 000, 033, 066, 100, 133, 166, 200, 233, 266, 300, 333, 366, 400, 433, 466, 500, 533, 566, 599, 633, 666, 699, 733, 766, 800, 833, 866, 900, 933, 966 };

        //            s_timeResolution = Ticks.PerMillisecond * 33;
        //            Console.WriteLine("BPA millisecond sorting test, TimeResolution = {0}", s_timeResolution);

        //            for (int i = 0; i < bpaMilliseconds.Length; i++)
        //            {
        //                long longTicks = (new DateTime(currentTime.Year, currentTime.Month, currentTime.Day, currentTime.Hour, currentTime.Minute, currentTime.Second, bpaMilliseconds[i])).Ticks;
        //                long destination = GetFrame(longTicks);
        //                Console.WriteLine(string.Format("{0:000} ms : {1:000} ms", bpaMilliseconds[i], (new DateTime(destination)).Millisecond));
        //            }

        //            s_timeResolution = Ticks.PerMillisecond;
        //            Ticks sourceTime = ((Ticks)DateTime.Now).BaselinedTimestamp(BaselineTimeInterval.Second);

        //            for (int i = 0; i < s_framesPerSecond; i++)
        //            {
        //                int milliseconds = (int)(s_millisecondsPerFrame * i);
        //                long longTicks = ((new DateTime(sourceTime)).AddMilliseconds((double)milliseconds)).Ticks;
        //                long destination = GetFrame(longTicks);
        //                Console.WriteLine(string.Format("{0} - {1:000} ms : {2} - {3:000} ms", longTicks, milliseconds, destination, (new DateTime(destination)).Millisecond));
        //            }
        //            Console.WriteLine();

        //            double ticks = Ticks.PerSecond;

        //            // Test truncated timestamps
        //            for (int i = 0; i < s_framesPerSecond; i++)
        //            {
        //                long longTicks = (long)(ticks / s_timeResolution) * s_timeResolution;
        //                Console.WriteLine(string.Format("{0} : {1}", longTicks, GetFrame(longTicks)));
        //                ticks += s_ticksPerFrame;
        //            }
        //            Console.WriteLine();

        //            ticks = 2 * Ticks.PerSecond;

        //            // Test rounded timestamps
        //            for (int i = 0; i < s_framesPerSecond; i++)
        //            {
        //                long longTicks = (long)Math.Round(ticks / s_timeResolution) * s_timeResolution;
        //                Console.WriteLine(string.Format("{0} : {1}", longTicks, GetFrame(longTicks)));
        //                ticks += s_ticksPerFrame;
        //            }
        //            Console.WriteLine();

        //            ticks = 3 * Ticks.PerSecond;

        //            // Test upper range limits
        //            for (int i = 0; i < s_framesPerSecond; i++)
        //            {
        //                ticks += s_ticksPerFrame;
        //                long longTicks = (long)(ticks / s_timeResolution) * s_timeResolution;
        //                longTicks -= s_timeResolution;
        //                Console.WriteLine(string.Format("{0} : {1}", longTicks, GetFrame(longTicks)));
        //            }
        //            Console.ReadLine();
        //        }

        //        public static long GetFrame(long ticks)
        //        {
        //            long baseTicks, ticksBeyondSecond, frameIndex, destinationTicks, nextDestinationTicks;

        //            // Baseline timestamp to the top of the second
        //            baseTicks = ticks - ticks % Ticks.PerSecond;

        //            // Remove the seconds from ticks
        //            ticksBeyondSecond = ticks - baseTicks;

        //            // Calculate a frame index between 0 and s_framesPerSecond-1, corresponding to ticks
        //            // rounded down to the nearest frame
        //            frameIndex = (long)(ticksBeyondSecond / s_ticksPerFrame);

        //            // Calculate the timestamp of the nearest frame rounded up
        //            nextDestinationTicks = (frameIndex + 1) * Ticks.PerSecond / s_framesPerSecond;

        //            // Determine whether the desired frame is the nearest
        //            // frame rounded down or the nearest frame rounded up
        //            if (s_timeResolution <= 1)
        //            {
        //                if (nextDestinationTicks <= ticksBeyondSecond)
        //                    destinationTicks = nextDestinationTicks;
        //                else
        //                    destinationTicks = frameIndex * Ticks.PerSecond / s_framesPerSecond;
        //            }
        //            else
        //            {
        //                // If, after translating nextDestinationTicks to the time resolution, it is less than
        //                // or equal to ticks, nextDestinationTicks corresponds to the desired frame
        //                if ((nextDestinationTicks / s_timeResolution) * s_timeResolution <= ticksBeyondSecond)
        //                    destinationTicks = nextDestinationTicks;
        //                else
        //                    destinationTicks = frameIndex * Ticks.PerSecond / s_framesPerSecond;
        //            }

        //            // Recover the seconds that were removed
        //            destinationTicks += baseTicks;

        //            return destinationTicks;
        //        }
        //    }
        //}

        #endregion

        #endregion
    }
Пример #5
0
        /// <summary>
        /// Removes current <see cref="Head"/> frame from the <see cref="FrameQueue"/> after it has been processed and assigns a new <see cref="Head"/>.
        /// </summary>
        public void Pop()
        {
            // We track latest published ticks - don't want to allow slow moving measurements
            // to inject themselves after a certain publication time frame has passed - this
            // avoids any possible out-of-sequence frame publication...
            m_last = m_head;
            m_head = null;
            long publishedTicks = m_last.Timestamp;
            Thread.VolatileWrite(ref m_publishedTicks, publishedTicks);

            // Assign next node, if any, as quickly as possible. Still have to wait for queue
            // lock - tick-tock, time's-a-wastin' and user function needs a frame to publish.
#if MONO
            lock (m_queueLock)
            {
#else
            bool locked = false;

            try
            {
                m_queueLock.Enter(ref locked);
#endif
                if (m_frameList.Count > 0)
                {
                    LinkedListNode<TrackingFrame> nextNode = m_frameList.First.Next;

                    // If next frame is available, go ahead and assign it...
                    if (nextNode != null)
                        m_head = nextNode.Value;

                    // Clean up frame queues
                    m_frameList.RemoveFirst();
                }
            }
#if !MONO
            finally
            {
                if (locked)
                    m_queueLock.Exit();
            }
#endif
            TrackingFrame frame;
            m_frameHash.TryRemove(publishedTicks, out frame);
        }
Пример #6
0
        /// <summary>
        /// Releases the unmanaged resources used by the <see cref="FrameQueue"/> object and optionally releases the managed resources.
        /// </summary>
        /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>
        protected virtual void Dispose(bool disposing)
        {
            if (!m_disposed)
            {
                try
                {
                    if (disposing)
                    {
                        Clear();
                        m_frameList = null;
                        m_frameHash = null;

                        m_createNewFrame = null;
                        m_head = null;
                        m_last = null;
                    }
                }
                finally
                {
                    m_disposed = true;  // Prevent duplicate dispose.
                }
            }
        }
Пример #7
0
        /// <summary>
        /// Gets <see cref="TrackingFrame"/> from the queue with the specified timestamp, in ticks.  If no frame exists for
        /// the specified timestamp, one will be created.
        /// </summary>
        /// <param name="ticks">Timestamp, in ticks, for which to get or create <see cref="TrackingFrame"/>.</param>
        /// <remarks>
        /// Ticks can be any point in time so long time requested is greater than time of last published frame; this queue is
        /// used in a real-time scenario with time moving forward.  If a frame is requested for an old timestamp, null will
        /// be returned. Note that frame returned will be "best-fit" for given timestamp based on <see cref="FramesPerSecond"/>.
        /// </remarks>
        /// <returns>An existing or new <see cref="TrackingFrame"/> from the queue for the specified timestamp.</returns>
        public TrackingFrame GetFrame(long ticks)
        {
            TrackingFrame frame     = null;
            bool          nodeAdded = false;
            long          destinationTicks;

            // Calculate destination ticks for this frame
            destinationTicks = m_roundToNearestTimestamp ? Ticks.RoundToSubsecondDistribution(ticks, m_framesPerSecond) : Ticks.AlignToSubsecondDistribution(ticks, m_framesPerSecond, m_timeResolution);

            // Make sure ticks are newer than latest published ticks...
            if (destinationTicks > Thread.VolatileRead(ref m_publishedTicks))
            {
                // See if requested frame is already available (can do this outside lock with concurrent dictionary)
                if (m_frameHash.TryGetValue(destinationTicks, out frame))
                {
                    return(frame);
                }

                // Didn't find frame for this timestamp so we need to add a new one to the queue
#if MONO
                lock (m_queueLock)
                {
#else
                bool locked = false;

                try
                {
                    m_queueLock.Enter(ref locked);
#endif
                    // Another thread may have gotten to this task already, so check for this contingency...
                    if (m_frameHash.TryGetValue(destinationTicks, out frame))
                    {
                        return(frame);
                    }

                    // TODO: Add a flag to add frames to publish even if no data arrives for them as an alternate mode
                    // TODO: of operation. In this mode pre-populate frame queue with at least one second of data from
                    // TODO: given start time (was thinking up next even second). This mode is useful for generically
                    // TODO: using concentrator to create a set of frame data from a data set with possible missing
                    // TODO: data (e.g., a historian) to create an evenly timestamped export

                    // Create a new frame for this timestamp
                    frame = new TrackingFrame(m_createNewFrame(destinationTicks), m_downsamplingMethod);

                    if (m_frameList.Count > 0)
                    {
                        // Insert frame into proper sorted position...
                        LinkedListNode <TrackingFrame> node = m_frameList.Last;

                        do
                        {
                            if (destinationTicks > node.Value.Timestamp)
                            {
                                m_frameList.AddAfter(node, frame);
                                nodeAdded = true;
                                break;
                            }

                            node = node.Previous;
                        }while (node != null);
                    }

                    if (!nodeAdded)
                    {
                        m_frameList.AddFirst(frame);
                        m_head = frame;
                    }

                    // Since we'll be requesting this frame over and over, we'll use
                    // a hash table for quick frame lookups by timestamp
                    m_frameHash[destinationTicks] = frame;
                }
#if !MONO
                finally
                {
                    if (locked)
                    {
                        m_queueLock.Exit();
                    }
                }
#endif
            }

            return(frame);
        }

        #region [ GetFrame Testing Algorithm ]

        // Copy this code into a console application and reference GSF.Core.dll to test.

        //using System;
        //using System.Collections.Generic;
        //using System.Linq;
        //using System.Text;
        //using GSF;

        //namespace FrameTimestampTest
        //{
        //    public class Program
        //    {
        //        private static long s_timeResolution;
        //        private static long s_framesPerSecond;
        //        private static double s_ticksPerFrame;
        //        private static double s_millisecondsPerFrame;

        //        public static void Main(string[] args)
        //        {
        //            s_framesPerSecond = 30;
        //            s_ticksPerFrame = Ticks.PerSecond / (double)s_framesPerSecond;
        //            s_timeResolution = Ticks.PerMillisecond;
        //            s_millisecondsPerFrame = 1000.0 / s_framesPerSecond;

        //            // Test BPA PDCstream style milliseconds
        //            DateTime currentTime = DateTime.Now;
        //            int[] bpaMilliseconds = new int[] { 000, 033, 066, 100, 133, 166, 200, 233, 266, 300, 333, 366, 400, 433, 466, 500, 533, 566, 599, 633, 666, 699, 733, 766, 800, 833, 866, 900, 933, 966 };

        //            s_timeResolution = Ticks.PerMillisecond * 33;
        //            Console.WriteLine("BPA millisecond sorting test, TimeResolution = {0}", s_timeResolution);

        //            for (int i = 0; i < bpaMilliseconds.Length; i++)
        //            {
        //                long longTicks = (new DateTime(currentTime.Year, currentTime.Month, currentTime.Day, currentTime.Hour, currentTime.Minute, currentTime.Second, bpaMilliseconds[i])).Ticks;
        //                long destination = GetFrame(longTicks);
        //                Console.WriteLine(string.Format("{0:000} ms : {1:000} ms", bpaMilliseconds[i], (new DateTime(destination)).Millisecond));
        //            }

        //            s_timeResolution = Ticks.PerMillisecond;
        //            Ticks sourceTime = ((Ticks)DateTime.Now).BaselinedTimestamp(BaselineTimeInterval.Second);

        //            for (int i = 0; i < s_framesPerSecond; i++)
        //            {
        //                int milliseconds = (int)(s_millisecondsPerFrame * i);
        //                long longTicks = ((new DateTime(sourceTime)).AddMilliseconds((double)milliseconds)).Ticks;
        //                long destination = GetFrame(longTicks);
        //                Console.WriteLine(string.Format("{0} - {1:000} ms : {2} - {3:000} ms", longTicks, milliseconds, destination, (new DateTime(destination)).Millisecond));
        //            }
        //            Console.WriteLine();

        //            double ticks = Ticks.PerSecond;

        //            // Test truncated timestamps
        //            for (int i = 0; i < s_framesPerSecond; i++)
        //            {
        //                long longTicks = (long)(ticks / s_timeResolution) * s_timeResolution;
        //                Console.WriteLine(string.Format("{0} : {1}", longTicks, GetFrame(longTicks)));
        //                ticks += s_ticksPerFrame;
        //            }
        //            Console.WriteLine();

        //            ticks = 2 * Ticks.PerSecond;

        //            // Test rounded timestamps
        //            for (int i = 0; i < s_framesPerSecond; i++)
        //            {
        //                long longTicks = (long)Math.Round(ticks / s_timeResolution) * s_timeResolution;
        //                Console.WriteLine(string.Format("{0} : {1}", longTicks, GetFrame(longTicks)));
        //                ticks += s_ticksPerFrame;
        //            }
        //            Console.WriteLine();

        //            ticks = 3 * Ticks.PerSecond;

        //            // Test upper range limits
        //            for (int i = 0; i < s_framesPerSecond; i++)
        //            {
        //                ticks += s_ticksPerFrame;
        //                long longTicks = (long)(ticks / s_timeResolution) * s_timeResolution;
        //                longTicks -= s_timeResolution;
        //                Console.WriteLine(string.Format("{0} : {1}", longTicks, GetFrame(longTicks)));
        //            }
        //            Console.ReadLine();
        //        }

        //        public static long GetFrame(long ticks)
        //        {
        //            long baseTicks, ticksBeyondSecond, frameIndex, destinationTicks, nextDestinationTicks;

        //            // Baseline timestamp to the top of the second
        //            baseTicks = ticks - ticks % Ticks.PerSecond;

        //            // Remove the seconds from ticks
        //            ticksBeyondSecond = ticks - baseTicks;

        //            // Calculate a frame index between 0 and s_framesPerSecond-1, corresponding to ticks
        //            // rounded down to the nearest frame
        //            frameIndex = (long)(ticksBeyondSecond / s_ticksPerFrame);

        //            // Calculate the timestamp of the nearest frame rounded up
        //            nextDestinationTicks = (frameIndex + 1) * Ticks.PerSecond / s_framesPerSecond;

        //            // Determine whether the desired frame is the nearest
        //            // frame rounded down or the nearest frame rounded up
        //            if (s_timeResolution <= 1)
        //            {
        //                if (nextDestinationTicks <= ticksBeyondSecond)
        //                    destinationTicks = nextDestinationTicks;
        //                else
        //                    destinationTicks = frameIndex * Ticks.PerSecond / s_framesPerSecond;
        //            }
        //            else
        //            {
        //                // If, after translating nextDestinationTicks to the time resolution, it is less than
        //                // or equal to ticks, nextDestinationTicks corresponds to the desired frame
        //                if ((nextDestinationTicks / s_timeResolution) * s_timeResolution <= ticksBeyondSecond)
        //                    destinationTicks = nextDestinationTicks;
        //                else
        //                    destinationTicks = frameIndex * Ticks.PerSecond / s_framesPerSecond;
        //            }

        //            // Recover the seconds that were removed
        //            destinationTicks += baseTicks;

        //            return destinationTicks;
        //        }
        //    }
        //}

        #endregion

        #endregion
    }
Пример #8
0
        /// <summary>
        /// Gets <see cref="TrackingFrame"/> from the queue with the specified timestamp, in ticks.  If no frame exists for
        /// the specified timestamp, one will be created.
        /// </summary>
        /// <param name="ticks">Timestamp, in ticks, for which to get or create <see cref="TrackingFrame"/>.</param>
        /// <remarks>
        /// Ticks can be any point in time so long time requested is greater than time of last published frame; this queue is
        /// used in a real-time scenario with time moving forward.  If a frame is requested for an old timestamp, null will
        /// be returned. Note that frame returned will be "best-fit" for given timestamp based on <see cref="FramesPerSecond"/>.
        /// </remarks>
        /// <returns>An existing or new <see cref="TrackingFrame"/> from the queue for the specified timestamp.</returns>
        public TrackingFrame GetFrame(long ticks)
        {
            // Calculate destination ticks for this frame
            TrackingFrame frame = null;
            bool locked = false, nodeAdded = false;
            long baseTicks, ticksBeyondSecond, frameIndex, destinationTicks, nextDestinationTicks;

            // Baseline timestamp to the top of the second
            baseTicks = ticks - ticks % Ticks.PerSecond;

            // Remove the seconds from ticks
            ticksBeyondSecond = ticks - baseTicks;

            // Calculate a frame index between 0 and m_framesPerSecond-1, corresponding to ticks
            // rounded down to the nearest frame
            frameIndex = (long)(ticksBeyondSecond / m_ticksPerFrame);

            // Calculate the timestamp of the nearest frame rounded up
            nextDestinationTicks = (frameIndex + 1) * Ticks.PerSecond / m_framesPerSecond;

            // Determine whether the desired frame is the nearest
            // frame rounded down or the nearest frame rounded up
            if (m_timeResolution <= 1)
            {
                if (nextDestinationTicks <= ticksBeyondSecond)
                    destinationTicks = nextDestinationTicks;
                else
                    destinationTicks = frameIndex * Ticks.PerSecond / m_framesPerSecond;
            }
            else
            {
                // If, after translating nextDestinationTicks to the time resolution, it is less than
                // or equal to ticks, nextDestinationTicks corresponds to the desired frame
                if ((nextDestinationTicks / m_timeResolution) * m_timeResolution <= ticksBeyondSecond)
                    destinationTicks = nextDestinationTicks;
                else
                    destinationTicks = frameIndex * Ticks.PerSecond / m_framesPerSecond;
            }

            // Recover the seconds that were removed
            destinationTicks += baseTicks;

            // Make sure ticks are newer than latest published ticks...
            if (destinationTicks > Thread.VolatileRead(ref m_publishedTicks))
            {
                // See if requested frame is already available (can do this outside lock with concurrent dictionary)
                if (m_frameHash.TryGetValue(destinationTicks, out frame))
                    return frame;

                // Didn't find frame for this timestamp so we need to add a new one to the queue
                try
                {
                    m_queueLock.Enter(ref locked);

                    // Another thread may have gotten to this task already, so check for this contingency...
                    if (m_frameHash.TryGetValue(destinationTicks, out frame))
                        return frame;

                    // Create a new frame for this timestamp
                    frame = new TrackingFrame(m_createNewFrame(destinationTicks), m_downsamplingMethod);

                    if (m_frameList.Count > 0)
                    {
                        // Insert frame into proper sorted position...
                        LinkedListNode<TrackingFrame> node = m_frameList.Last;

                        do
                        {
                            if (destinationTicks > node.Value.Timestamp)
                            {
                                m_frameList.AddAfter(node, frame);
                                nodeAdded = true;
                                break;
                            }

                            node = node.Previous;
                        }
                        while (node != null);
                    }

                    if (!nodeAdded)
                    {
                        m_frameList.AddFirst(frame);
                        m_head = frame;
                    }

                    // Since we'll be requesting this frame over and over, we'll use
                    // a hash table for quick frame lookups by timestamp
                    m_frameHash[destinationTicks] = frame;
                }
                finally
                {
                    if (locked)
                        m_queueLock.Exit();
                }
            }

            return frame;
        }