diff --git a/K4AdotNet.Samples.Wpf.BackgroundRemover/App.cs b/K4AdotNet.Samples.Wpf.BackgroundRemover/App.cs
index 91bd530..2b88c84 100644
--- a/K4AdotNet.Samples.Wpf.BackgroundRemover/App.cs
+++ b/K4AdotNet.Samples.Wpf.BackgroundRemover/App.cs
@@ -7,7 +7,15 @@ internal class App : AppBase
{
[STAThread]
public static void Main()
- => new App().Run();
+ {
+#if DEBUG
+ Sdk.TraceLevel = System.Diagnostics.TraceLevel.Info;
+#else
+ Sdk.TraceLevel = System.Diagnostics.TraceLevel.Warning;
+#endif
+
+ new App().Run();
+ }
protected override Window CreateMainWindow(StartupEventArgs e)
{
diff --git a/K4AdotNet.Samples.Wpf.BodyTracker/App.cs b/K4AdotNet.Samples.Wpf.BodyTracker/App.cs
index 350328e..57ab72c 100644
--- a/K4AdotNet.Samples.Wpf.BodyTracker/App.cs
+++ b/K4AdotNet.Samples.Wpf.BodyTracker/App.cs
@@ -7,7 +7,15 @@ internal sealed class App : AppBase
{
[STAThread]
public static void Main()
- => new App().Run();
+ {
+#if DEBUG
+ Sdk.TraceLevel = System.Diagnostics.TraceLevel.Info;
+#else
+ Sdk.TraceLevel = System.Diagnostics.TraceLevel.Warning;
+#endif
+
+ new App().Run();
+ }
protected override Window CreateMainWindow(StartupEventArgs e)
{
diff --git a/K4AdotNet.Samples.Wpf.Viewer/App.cs b/K4AdotNet.Samples.Wpf.Viewer/App.cs
index aaad541..244e827 100644
--- a/K4AdotNet.Samples.Wpf.Viewer/App.cs
+++ b/K4AdotNet.Samples.Wpf.Viewer/App.cs
@@ -7,7 +7,15 @@ internal sealed class App : AppBase
{
[STAThread]
public static void Main()
- => new App().Run();
+ {
+#if DEBUG
+ Sdk.TraceLevel = System.Diagnostics.TraceLevel.Info;
+#else
+ Sdk.TraceLevel = System.Diagnostics.TraceLevel.Warning;
+#endif
+
+ new App().Run();
+ }
protected override Window CreateMainWindow(StartupEventArgs e)
=> new MainWindow(new MainModel(this));
diff --git a/K4AdotNet/K4AdotNet.xml b/K4AdotNet/K4AdotNet.xml
index e6a7e69..d3a7509 100644
--- a/K4AdotNet/K4AdotNet.xml
+++ b/K4AdotNet/K4AdotNet.xml
@@ -1258,6 +1258,79 @@
This method cannot be called for disposed objects.
+
+
+ Internal helper class which implements logging-related logic.
+
+
+
+ Verbosity levels of debug messaging.
+
+
+ The most severe level of debug messaging.
+
+
+ The second most severe level of debug messaging.
+
+
+ The third most severe level of debug messaging.
+
+
+ The second least severe level of debug messaging.
+
+
+ The lest severe level of debug messaging. This is the most verbose messaging possible.
+
+
+ No logging is performed.
+
+
+ DLL imports from k4a.h header file for native functions that are connected with logging.
+
+
+ Callback function for debug messages being generated by the Azure Kinect SDK.
+ The context of the callback function. This is the context that was supplied by the caller to .
+ The level of the message that has been created.
+ The file name of the source file that generated the message.
+ The line number of the source file that generated the message.
+ The messaged generated by the Azure Kinect SDK.
+
+ The callback is called asynchronously when the Azure Kinext SDK generates a message at a that is equal to
+ or more critical than the level specified when calling to register the callback.
+
+ This callback can occur from any thread and blocks the calling thread.This callback user
+ must protect it's logging resources from concurrent calls. All care should be made to minimize the amount of time
+ locks are held.
+
+
+
+ Sets and clears the callback function to receive debug messages from the Azure Kinect device.
+ The callback function to receive messages from. Set to to unregister the callback function.
+ The callback functions context.
+ The least critical error the user wants to be notified about.
+
+ if the callback function was set or cleared successfully.
+ if an error is encountered or the callback function has already been set.
+
+
+ Call this function to set or clear the callback function that is used to deliver debug messages to the caller. This
+ callback may be called concurrently, it is up to the implementation of the callback function to ensure the
+ parallelization is handled.
+
+ Clearing the callback function will block until all pending calls to the callback function have completed.
+
+ To update , this method can be called with the same value and by
+ specifying a new .
+
+ Logging provided via this API is independent of the logging controlled by the environmental variable controls
+ K4A_ENABLE_LOG_TO_STDOUT, K4A_ENABLE_LOG_TO_A_FILE, and K4A_LOG_LEVEL. However there is a slight change in
+ default behavior when using this function.By default, when \p k4a_set_debug_message_handler() has not been used to
+ register a message callback, the default for environmental variable controls is to send debug messages as if
+ K4A_ENABLE_LOG_TO_STDOUT= 1 were set. If this method registers a callback function before
+ is called, then the default for environmental controls
+ is as if K4A_ENABLE_LOG_TO_STDOUT= 0 was specified. Physically specifying the environmental control will override the default.
+
+
32-bit time value in microseconds. Used for timestamps and delays.
@@ -4144,6 +4217,13 @@
Extension of Dynamic Link Libraries (DLL) under Windows.
+
+
+ The K4A.Net can log data to a regular .Net Trace.
+ Use this property to choose the level of such logging, or set it to to turn it off.
+ Default value is .
+
+
The Sensor SDK can log data to the console, files, or to a custom handler.
Level of logging.
@@ -7691,149 +7771,3 @@
-System.Diagnostics.CodeAnalysis.AllowNullAttribute">
-
- Specifies that is allowed as an input even if the
- corresponding type disallows it.
-
-
-
-
- Initializes a new instance of the class.
-
-
-
-
- Specifies that is disallowed as an input even if the
- corresponding type allows it.
-
-
-
-
- Initializes a new instance of the class.
-
-
-
-
- Specifies that a method that will never return under any circumstance.
-
-
-
-
- Initializes a new instance of the class.
-
-
-
-
-
- Specifies that the method will not return if the associated
- parameter is passed the specified value.
-
-
-
-
- Gets the condition parameter value.
- Code after the method is considered unreachable by diagnostics if the argument
- to the associated parameter matches this value.
-
-
-
-
- Initializes a new instance of the
- class with the specified parameter value.
-
-
- The condition parameter value.
- Code after the method is considered unreachable by diagnostics if the argument
- to the associated parameter matches this value.
-
-
-
-
- Specifies that an output may be even if the
- corresponding type disallows it.
-
-
-
-
- Initializes a new instance of the class.
-
-
-
-
- Specifies that when a method returns ,
- the parameter may be even if the corresponding type disallows it.
-
-
-
-
- Gets the return value condition.
- If the method returns this value, the associated parameter may be .
-
-
-
-
- Initializes the attribute with the specified return value condition.
-
-
- The return value condition.
- If the method returns this value, the associated parameter may be .
-
-
-
-
- Specifies that an output is not even if the
- corresponding type allows it.
-
-
-
-
- Initializes a new instance of the class.
-
-
-
-
- Specifies that the output will be non- if the
- named parameter is non-.
-
-
-
-
- Gets the associated parameter name.
- The output will be non- if the argument to the
- parameter specified is non-.
-
-
-
-
- Initializes the attribute with the associated parameter name.
-
-
- The associated parameter name.
- The output will be non- if the argument to the
- parameter specified is non-.
-
-
-
-
- Specifies that when a method returns ,
- the parameter will not be even if the corresponding type allows it.
-
-
-
-
- Gets the return value condition.
- If the method returns this value, the associated parameter will not be .
-
-
-
-
- Initializes the attribute with the specified return value condition.
-
-
- The return value condition.
- If the method returns this value, the associated parameter will not be .
-
-
-
-
diff --git a/K4AdotNet/Logging/LogImpl.cs b/K4AdotNet/Logging/LogImpl.cs
new file mode 100644
index 0000000..44dece8
--- /dev/null
+++ b/K4AdotNet/Logging/LogImpl.cs
@@ -0,0 +1,116 @@
+using System;
+using System.Diagnostics;
+
+namespace K4AdotNet.Logging
+{
+ ///
+ /// Internal helper class which implements logging-related logic.
+ ///
+ internal static class LogImpl
+ {
+ private static readonly NativeApi.LoggingMessageCallback debugMessageHandler = OnDebugMessage;
+ private static TraceLevel traceLevel = TraceLevel.Off;
+ private static readonly object traceLevelSync = new object();
+
+ public static TraceLevel TraceLevel
+ {
+ get
+ {
+ lock (traceLevelSync) return traceLevel;
+ }
+
+ set
+ {
+ lock (traceLevelSync)
+ {
+ if (value == traceLevel)
+ return;
+
+ if (traceLevel != TraceLevel.Off)
+ {
+ var res = NativeApi.SetDebugMessageHandler(null, IntPtr.Zero, traceLevel.ToLogLevel());
+ if (res != NativeCallResults.Result.Succeeded)
+ throw new InvalidOperationException("Failed to clear the debug message handler.");
+ }
+
+ if (value != TraceLevel.Off)
+ {
+ var res = NativeApi.SetDebugMessageHandler(debugMessageHandler, IntPtr.Zero, value.ToLogLevel());
+ if (res != NativeCallResults.Result.Succeeded)
+ throw new InvalidOperationException("Failed to set the debug message handler.");
+ if (traceLevel == TraceLevel.Off)
+ {
+ AppDomain.CurrentDomain.ProcessExit += CurrentDomain_Exit;
+ AppDomain.CurrentDomain.DomainUnload += CurrentDomain_Exit;
+ }
+ }
+ else
+ {
+ AppDomain.CurrentDomain.ProcessExit -= CurrentDomain_Exit;
+ AppDomain.CurrentDomain.DomainUnload -= CurrentDomain_Exit;
+ }
+
+ traceLevel = value;
+ }
+ }
+ }
+
+ private static void OnDebugMessage(IntPtr _, LogLevel level, string file, int line, string message)
+ {
+ var text = $"#K4A [{System.IO.Path.GetFileName(file)}:{line}] {message}";
+
+ switch (level)
+ {
+ case LogLevel.Critical:
+ case LogLevel.Error:
+ Trace.TraceError(text);
+ break;
+ case LogLevel.Warning:
+ Trace.TraceWarning(text);
+ break;
+ case LogLevel.Information:
+ Trace.TraceInformation(text);
+ break;
+ default:
+ Trace.WriteLine(text);
+ break;
+ }
+ }
+
+ private static void CurrentDomain_Exit(object sender, EventArgs e)
+ {
+ var res = NativeApi.SetDebugMessageHandler(null, IntPtr.Zero, traceLevel.ToLogLevel());
+ if (res != NativeCallResults.Result.Succeeded)
+ Trace.TraceWarning("Failed to clear the debug message handler");
+ }
+
+ private static LogLevel ToLogLevel(this TraceLevel level)
+ => level switch
+ {
+ TraceLevel.Off => LogLevel.Off,
+ TraceLevel.Error => LogLevel.Error,
+ TraceLevel.Warning => LogLevel.Warning,
+ TraceLevel.Info => LogLevel.Information,
+ TraceLevel.Verbose => LogLevel.Trace,
+ _ => throw new ArgumentOutOfRangeException(nameof(level)),
+ };
+
+ public static void ConfigureLogging(string variableNamePrefix, TraceLevel level, bool logToStdout, string? logToFile)
+ {
+ Environment.SetEnvironmentVariable(variableNamePrefix + "LOG_LEVEL", level.ToSdkLogLevelLetter(), EnvironmentVariableTarget.Process);
+ Environment.SetEnvironmentVariable(variableNamePrefix + "ENABLE_LOG_TO_STDOUT", logToStdout ? "1" : "0", EnvironmentVariableTarget.Process);
+ Environment.SetEnvironmentVariable(variableNamePrefix + "ENABLE_LOG_TO_A_FILE", string.IsNullOrWhiteSpace(logToFile) ? "0" : logToFile, EnvironmentVariableTarget.Process);
+ }
+
+ private static string ToSdkLogLevelLetter(this TraceLevel level)
+ => level switch
+ {
+ TraceLevel.Off => "c",
+ TraceLevel.Error => "e",
+ TraceLevel.Warning => "w",
+ TraceLevel.Info => "i",
+ TraceLevel.Verbose => "t",
+ _ => throw new ArgumentOutOfRangeException(nameof(level)),
+ };
+ }
+}
diff --git a/K4AdotNet/Logging/LogLevel.cs b/K4AdotNet/Logging/LogLevel.cs
new file mode 100644
index 0000000..c6eb931
--- /dev/null
+++ b/K4AdotNet/Logging/LogLevel.cs
@@ -0,0 +1,31 @@
+namespace K4AdotNet.Logging
+{
+ // k4a_log_level_t
+ /// Verbosity levels of debug messaging.
+ internal enum LogLevel
+ {
+ // K4A_LOG_LEVEL_CRITICAL
+ /// The most severe level of debug messaging.
+ Critical = 0,
+
+ // K4A_LOG_LEVEL_ERROR
+ /// The second most severe level of debug messaging.
+ Error,
+
+ // K4A_LOG_LEVEL_WARNING
+ /// The third most severe level of debug messaging.
+ Warning,
+
+ // K4A_LOG_LEVEL_INFO
+ /// The second least severe level of debug messaging.
+ Information,
+
+ // K4A_LOG_LEVEL_TRACE
+ /// The lest severe level of debug messaging. This is the most verbose messaging possible.
+ Trace,
+
+ // K4A_LOG_LEVEL_OFF
+ /// No logging is performed.
+ Off,
+ }
+}
diff --git a/K4AdotNet/Logging/NativeApi.cs b/K4AdotNet/Logging/NativeApi.cs
new file mode 100644
index 0000000..aa393d8
--- /dev/null
+++ b/K4AdotNet/Logging/NativeApi.cs
@@ -0,0 +1,71 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace K4AdotNet.Logging
+{
+ /// DLL imports from k4a.h header file for native functions that are connected with logging.
+ internal static class NativeApi
+ {
+ // typedef void (k4a_logging_message_cb_t) (void* context,
+ // k4a_log_level_t level,
+ // const char* file,
+ // const int line,
+ // const char* message);
+ /// Callback function for debug messages being generated by the Azure Kinect SDK.
+ /// The context of the callback function. This is the context that was supplied by the caller to .
+ /// The level of the message that has been created.
+ /// The file name of the source file that generated the message.
+ /// The line number of the source file that generated the message.
+ /// The messaged generated by the Azure Kinect SDK.
+ ///
+ /// The callback is called asynchronously when the Azure Kinext SDK generates a message at a that is equal to
+ /// or more critical than the level specified when calling to register the callback.
+ ///
+ /// This callback can occur from any thread and blocks the calling thread.This callback user
+ /// must protect it's logging resources from concurrent calls. All care should be made to minimize the amount of time
+ /// locks are held.
+ ///
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ public delegate void LoggingMessageCallback(
+ IntPtr context,
+ LogLevel level,
+ [MarshalAs(UnmanagedType.LPStr)] string file,
+ int line,
+ [MarshalAs(UnmanagedType.LPStr)] string message);
+
+ // K4A_EXPORT k4a_result_t k4a_set_debug_message_handler(k4a_logging_message_cb_t* message_cb,
+ // void* message_cb_context,
+ // k4a_log_level_t min_level);
+ /// Sets and clears the callback function to receive debug messages from the Azure Kinect device.
+ /// The callback function to receive messages from. Set to to unregister the callback function.
+ /// The callback functions context.
+ /// The least critical error the user wants to be notified about.
+ ///
+ /// if the callback function was set or cleared successfully.
+ /// if an error is encountered or the callback function has already been set.
+ ///
+ ///
+ /// Call this function to set or clear the callback function that is used to deliver debug messages to the caller. This
+ /// callback may be called concurrently, it is up to the implementation of the callback function to ensure the
+ /// parallelization is handled.
+ ///
+ /// Clearing the callback function will block until all pending calls to the callback function have completed.
+ ///
+ /// To update , this method can be called with the same value and by
+ /// specifying a new .
+ ///
+ /// Logging provided via this API is independent of the logging controlled by the environmental variable controls
+ /// K4A_ENABLE_LOG_TO_STDOUT, K4A_ENABLE_LOG_TO_A_FILE, and K4A_LOG_LEVEL. However there is a slight change in
+ /// default behavior when using this function.By default, when \p k4a_set_debug_message_handler() has not been used to
+ /// register a message callback, the default for environmental variable controls is to send debug messages as if
+ /// K4A_ENABLE_LOG_TO_STDOUT= 1 were set. If this method registers a callback function before
+ /// is called, then the default for environmental controls
+ /// is as if K4A_ENABLE_LOG_TO_STDOUT= 0 was specified. Physically specifying the environmental control will override the default.
+ ///
+ [DllImport(Sdk.SENSOR_DLL_NAME, EntryPoint = "k4a_set_debug_message_handler", CallingConvention = CallingConvention.Cdecl)]
+ public static extern NativeCallResults.Result SetDebugMessageHandler(
+ LoggingMessageCallback? messageCallback,
+ IntPtr messageCallbackContext,
+ LogLevel minLevel);
+ }
+}
diff --git a/K4AdotNet/Sdk.cs b/K4AdotNet/Sdk.cs
index 34ccf8f..a6f1238 100644
--- a/K4AdotNet/Sdk.cs
+++ b/K4AdotNet/Sdk.cs
@@ -71,6 +71,17 @@ public static class Sdk
#region Logging
+ ///
+ /// The K4A.Net can log data to a regular .Net Trace.
+ /// Use this property to choose the level of such logging, or set it to to turn it off.
+ /// Default value is .
+ ///
+ public static TraceLevel TraceLevel
+ {
+ get => Logging.LogImpl.TraceLevel;
+ set => Logging.LogImpl.TraceLevel = value;
+ }
+
/// The Sensor SDK can log data to the console, files, or to a custom handler.
/// Level of logging.
/// Log messages to STDOUT?
@@ -88,7 +99,7 @@ public static class Sdk
public static void ConfigureLogging(TraceLevel level, bool logToStdout = false, string? logToFile = null)
{
const string PREFIX = "K4A_";
- ConfigureLogging(PREFIX, level, logToStdout, logToFile);
+ Logging.LogImpl.ConfigureLogging(PREFIX, level, logToStdout, logToFile);
}
/// Record part of Sensor SDK can log data to the console, files, or to a custom handler.
@@ -108,7 +119,7 @@ public static void ConfigureLogging(TraceLevel level, bool logToStdout = false,
public static void ConfigureRecordLogging(TraceLevel level, bool logToStdout = false, string? logToFile = null)
{
const string PREFIX = "K4A_RECORD_";
- ConfigureLogging(PREFIX, level, logToStdout, logToFile);
+ Logging.LogImpl.ConfigureLogging(PREFIX, level, logToStdout, logToFile);
}
/// The Body Tracking SDK can log data to the console, files, or to a custom handler.
@@ -128,27 +139,7 @@ public static void ConfigureRecordLogging(TraceLevel level, bool logToStdout = f
public static void ConfigureBodyTrackingLogging(TraceLevel level, bool logToStdout = false, string? logToFile = null)
{
const string PREFIX = "K4ABT_";
- ConfigureLogging(PREFIX, level, logToStdout, logToFile);
- }
-
- private static void ConfigureLogging(string variableNamePrefix, TraceLevel level, bool logToStdout, string? logToFile)
- {
- Environment.SetEnvironmentVariable(variableNamePrefix + "LOG_LEVEL", level.ToSdkLogLevelLetter(), EnvironmentVariableTarget.Process);
- Environment.SetEnvironmentVariable(variableNamePrefix + "ENABLE_LOG_TO_STDOUT", logToStdout ? "1" : "0", EnvironmentVariableTarget.Process);
- Environment.SetEnvironmentVariable(variableNamePrefix + "ENABLE_LOG_TO_A_FILE", string.IsNullOrWhiteSpace(logToFile) ? "0" : logToFile, EnvironmentVariableTarget.Process);
- }
-
- private static string ToSdkLogLevelLetter(this TraceLevel level)
- {
- switch (level)
- {
- case TraceLevel.Off: return "c";
- case TraceLevel.Error: return "e";
- case TraceLevel.Warning: return "w";
- case TraceLevel.Info: return "i";
- case TraceLevel.Verbose: return "t";
- default: throw new ArgumentOutOfRangeException(nameof(level));
- }
+ Logging.LogImpl.ConfigureLogging(PREFIX, level, logToStdout, logToFile);
}
#endregion