Viewing is open to everyone. Downloading and starring need a GitHub sign-in. Sign in with GitHub

CKeyScanSession.cs

v0.1.0-build.85 Latest Commit ede38f5

Size
4.4 KB
Lines
105
Language
csharp
SHA-256
7fadaa6c616e…
View on GitHub

Sign in with GitHub to download. Each download is recorded with your GitHub username.

1using System;
2using System.Diagnostics;
3using System.Threading;
4using OpenCKey.Interop;
5
6namespace OpenCKey
7{
8 /// <summary>
9 /// A continuous scanning session (for example while a camera view is
10 /// visible). It decodes frames with <see cref="CKeyDecoder"/> and drives the
11 /// telemetry session defined in docs/adoption-and-telemetry.md: it starts
12 /// when the session is created, succeeds at the first decode, and fails when
13 /// it is disposed (or restarted) without one, or after 30 s without a decode.
14 /// Frames and their processing times are counted. Nothing about the payload
15 /// is recorded. With telemetry off (mode 0) it is a plain decoder loop.
16 /// </summary>
17 /// <example>
18 /// <code>
19 /// using var session = new CKeyScanSession();
20 /// foreach (var frame in camera.Frames)
21 /// {
22 /// CKeyResult? result = session.ProcessFrame(frame.Gray, frame.Width, frame.Height, frame.Stride);
23 /// if (result != null) { Show(result.Text, result.Action); break; }
24 /// }
25 /// </code>
26 /// </example>
27 public sealed class CKeyScanSession : IDisposable
28 {
29 private int _decoded;
30 private int _disposed;
31
32 /// <summary>Starts a session.</summary>
33 public CKeyScanSession()
34 {
35 Begin();
36 }
37
38 /// <summary>True once a frame of this session has decoded.</summary>
39 public bool HasDecoded => Volatile.Read(ref _decoded) != 0;
40
41 /// <summary>
42 /// Decodes one grayscale frame and counts it. Returns the result, or null
43 /// when nothing decodes. Later decodes in the same session are still
44 /// returned but are not counted again.
45 /// </summary>
46 public CKeyResult? ProcessFrame(ReadOnlySpan<byte> gray, int width, int height, int stride)
47 {
48 if (Volatile.Read(ref _disposed) != 0) throw new ObjectDisposedException(nameof(CKeyScanSession));
49 long started = Stopwatch.GetTimestamp();
50 CKeyResult? result = CKeyDecoder.Decode(gray, width, height, stride);
51 long elapsedTicks = Stopwatch.GetTimestamp() - started;
52 RecordFrame(TimeSpan.FromSeconds(elapsedTicks / (double)Stopwatch.Frequency));
53 if (result != null) RecordSuccess(result);
54 return result;
55 }
56
57 /// <summary>
58 /// Counts a frame processed by the host's own pipeline (when it does not
59 /// call <see cref="ProcessFrame"/>).
60 /// </summary>
61 public void RecordFrame(TimeSpan processingTime)
62 {
63 if (!CKeyTelemetry.IsAvailable) return;
64 double ms = Math.Round(Math.Max(0, processingTime.TotalMilliseconds));
65 uint processing = ms >= uint.MaxValue ? uint.MaxValue : (uint)ms;
66 NativeTelemetry.ckey_telemetry_frame(MonotonicClock.NowMs, processing);
67 }
68
69 /// <summary>Records the session's first valid decode (later calls are ignored).</summary>
70 public void RecordSuccess(CKeyResult result)
71 {
72 if (result == null) throw new ArgumentNullException(nameof(result));
73 if (Interlocked.Exchange(ref _decoded, 1) != 0) return;
74 if (!CKeyTelemetry.IsAvailable) return;
75 NativeTelemetry.ckey_telemetry_session_success(MonotonicClock.NowMs, result.TelemetryProfileCode);
76 }
77
78 /// <summary>
79 /// "Scan again": ends the current session (failed if it had no decode)
80 /// and starts a new one.
81 /// </summary>
82 public void Restart()
83 {
84 if (Volatile.Read(ref _disposed) != 0) throw new ObjectDisposedException(nameof(CKeyScanSession));
85 Interlocked.Exchange(ref _decoded, 0);
86 Begin(); // the core ends an open session as failed first
87 }
88
89 /// <summary>Ends the session (failed if it had no decode).</summary>
90 public void Dispose()
91 {
92 if (Interlocked.Exchange(ref _disposed, 1) != 0) return;
93 if (!CKeyTelemetry.IsAvailable) return;
94 NativeTelemetry.ckey_telemetry_session_end(MonotonicClock.NowMs);
95 }
96
97 private static void Begin()
98 {
99 if (!CKeyTelemetry.IsAvailable) return;
100 CKeyTelemetry.EnsureClient();
101 NativeTelemetry.ckey_telemetry_session_begin(MonotonicClock.NowMs);
102 if (NativeTelemetry.ckey_telemetry_get_mode() == CKey.TelemetryOn) TelemetrySender.EnsureStarted();
103 }
104 }
105}