diff --git a/README.md b/README.md
index d4264455..961b1869 100644
--- a/README.md
+++ b/README.md
@@ -425,6 +425,14 @@ room.RegisterByteStreamHandler("my-topic", (reader, identity) =>
);
```
+## Verbose Logging
+
+To enable verbose logging, define the `LK_VERBOSE` symbol:
+
+1. Navigate to Project Settings → Player
+2. Select your platform tab (e.g., Mac, iOS, Android).
+3. Under Other Settings → Scripting Define Symbols, add `LK_VERBOSE`.
+
| LiveKit Ecosystem |
diff --git a/Runtime/Scripts/Internal/FFIClient.cs b/Runtime/Scripts/Internal/FFIClient.cs
index d037a3bb..8e2aab51 100644
--- a/Runtime/Scripts/Internal/FFIClient.cs
+++ b/Runtime/Scripts/Internal/FFIClient.cs
@@ -139,11 +139,8 @@ private static void InitializeSdk()
return;
#endif
-#if LK_VERBOSE
+ // TODO: gate behind LK_VERBOSE
const bool captureLogs = true;
-#else
- const bool captureLogs = false;
-#endif
NativeMethods.LiveKitInitialize(FFICallback, captureLogs, "unity", ""); // TODO: Get SDK version
@@ -218,7 +215,6 @@ out UIntPtr dataLen
}
}
-
[AOT.MonoPInvokeCallback(typeof(FFICallbackDelegate))]
static unsafe void FFICallback(UIntPtr data, UIntPtr size)
{
@@ -243,6 +239,7 @@ static unsafe void FFICallback(UIntPtr data, UIntPtr size)
switch (r?.MessageCase)
{
case FfiEvent.MessageOneofCase.Logs:
+ Utils.HandleLogBatch(r.Logs);
break;
case FfiEvent.MessageOneofCase.PublishData:
break;
diff --git a/Runtime/Scripts/Internal/Utils.cs b/Runtime/Scripts/Internal/Utils.cs
index b8a60da3..252fb714 100644
--- a/Runtime/Scripts/Internal/Utils.cs
+++ b/Runtime/Scripts/Internal/Utils.cs
@@ -3,11 +3,13 @@
using UnityEngine;
using UnityEngine.Experimental.Rendering;
using UnityEngine.Rendering;
+using LiveKit.Proto;
+using System.Collections.Generic;
namespace LiveKit.Internal
{
///
- /// The class Utils contains internal utilities used for FfiClient
+ /// The class Utils contains internal utilities used for FfiClient
/// The log part is useful to print messages only when "LK_DEBUG" is defined.
///
internal static class Utils
@@ -15,15 +17,88 @@ internal static class Utils
private const string PREFIX = "LiveKit";
private const string LK_DEBUG = "LK_DEBUG";
+ ///
+ /// Log a message at the info level.
+ ///
+ public static void Info(object msg)
+ {
+ UnityEngine.Debug.unityLogger.Log(PREFIX, msg);
+ }
+
+ ///
+ /// Log a message at the error level.
+ ///
+ public static void Error(object msg)
+ {
+ UnityEngine.Debug.unityLogger.LogError(PREFIX, msg);
+ }
+
+ ///
+ /// Log a message at the warning level.
+ ///
+ public static void Warning(object msg)
+ {
+ UnityEngine.Debug.unityLogger.LogWarning(PREFIX, msg);
+ }
+
+ ///
+ /// Log a message at the debug level.
+ ///
[Conditional(LK_DEBUG)]
public static void Debug(object msg)
{
- UnityEngine.Debug.unityLogger.Log(LogType.Log, $"{PREFIX}: {msg}");
+ UnityEngine.Debug.unityLogger.Log(PREFIX, msg);
}
- public static void Error(object msg)
+ //
+ /// Forwards a log batch received over FFI to the Unity logging system.
+ ///
+ internal static void HandleLogBatch(LogBatch batch)
{
- UnityEngine.Debug.unityLogger.Log(LogType.Error, $"{PREFIX}: {msg}");
+ if (batch == null) return;
+ foreach (var record in batch.Records)
+ {
+ if (record == null || !record.HasMessage || string.IsNullOrEmpty(record.Message)) continue;
+ var formatted = FormatLogMessage(record);
+ switch (record.Level)
+ {
+ case LogLevel.LogError:
+ Error(formatted);
+ break;
+ case LogLevel.LogWarn:
+ Warning(formatted);
+ break;
+ case LogLevel.LogInfo:
+ Info(formatted);
+ break;
+ case LogLevel.LogDebug:
+ case LogLevel.LogTrace:
+ Debug(formatted);
+ break;
+ default:
+ Info(formatted);
+ break;
+ }
+ }
+ }
+
+ private static string FormatLogMessage(LogRecord record)
+ {
+ var parts = new List { record.Message };
+ if (record.HasFile && !string.IsNullOrEmpty(record.File))
+ {
+ var location = record.HasLine && record.Line > 0
+ ? $"{record.File}:{record.Line}"
+ : record.File;
+ parts.Add($"Source: {location} (FFI)");
+ }
+ if (record.HasModulePath && !string.IsNullOrEmpty(record.ModulePath))
+ parts.Add($"Module: {record.ModulePath}");
+
+ if (record.HasTarget && !string.IsNullOrEmpty(record.Target))
+ parts.Add($"Target: {record.Target}");
+
+ return string.Join("\n", parts);
}
public static GraphicsFormat GetSupportedGraphicsFormat(GraphicsDeviceType type)