Setting a callback in a Jack Client causes Unity to crash

73 Views Asked by At

i am writing a Unity script which serves as a JACK client. For this, I need to register a callback function, in which the audio signal gets processed. Since I use managed C# code, I create a delegate and retrieve the function pointer from it, which I pass to the jack_set_process_callback function. Since I found out, that the delegate will be garbage collected after some time, which would cause a access violation and a crash after some time, I now keep a reference as field. However, the application still crashes when I stop the Unity player. Here is the code:

using System;
using UnityEngine;
using System.Runtime.InteropServices;

public class SimpleJackClient : MonoBehaviour
{

    [DllImport("libjack64.dll")]
    private static extern IntPtr jack_client_open(string clientName, int options, out int status);

    [DllImport("libjack64.dll")]
    private static extern IntPtr jack_client_close(IntPtr jackClient);

    [DllImport("libjack64.dll")]
    private static extern int jack_activate(IntPtr client);

    [DllImport("libjack64.dll")]
    private static extern int jack_deactivate(IntPtr client);

    [DllImport("libjack64.dll")]
    private static extern int jack_set_process_callback(IntPtr client, IntPtr callback, IntPtr arg);

    public delegate int CallbackDelegate(int samplesPerFrame, IntPtr arg);

    // Hold a reference to the process callback to avoid it to be garbage collected
    private CallbackDelegate callbackDelegate;

    public string clientName = "UnityClient";

    private IntPtr jackClientPtr;

    private void Start()
    {
        int status;
        jackClientPtr = jack_client_open(clientName, 0, out status);

        callbackDelegate = new CallbackDelegate(Process);
        IntPtr processCallbackPtr = Marshal.GetFunctionPointerForDelegate(callbackDelegate);
        jack_set_process_callback(jackClientPtr, processCallbackPtr, IntPtr.Zero);

        jack_activate(jackClientPtr);
    }

    public int Process(int samplesPerFrame, IntPtr arg)
    {            
        return 0;
    }

    private void OnDestroy()
    {   
        if (jackClientPtr != IntPtr.Zero)
        {
            jack_deactivate(jackClientPtr);
            jack_client_close(jackClientPtr);
        }
 
    }

}

I get an error message: "Fatal error in GC: Suspend thread loop failed."

This is the crash stack trace:

0x00007FFAB3884F2F (mono-2.0-bdwgc) [C:\build\output\Unity-Technologies\mono\external\bdwgc\win32_threads.c:1248] GC_suspend 
0x00007FFAB388466B (mono-2.0-bdwgc) [C:\build\output\Unity-Technologies\mono\external\bdwgc\win32_threads.c:1324] GC_stop_world 
0x00007FFAB38849EB (mono-2.0-bdwgc) [C:\build\output\Unity-Technologies\mono\external\bdwgc\alloc.c:782] GC_stopped_mark 
0x00007FFAB3885558 (mono-2.0-bdwgc) [C:\build\output\Unity-Technologies\mono\external\bdwgc\alloc.c:580] GC_try_to_collect_inner 
0x00007FFAB38763E5 (mono-2.0-bdwgc) [C:\build\output\Unity-Technologies\mono\external\bdwgc\alloc.c:1224] GC_gcollect 
0x00007FF6C2D68B5D (Unity) CleanupAfterLoad
0x00007FF6C2DBC50C (Unity) LoadSceneOperation::CompletePreloadManagerLoadSceneEditor
0x00007FF6C2DBD09B (Unity) LoadSceneOperation::IntegrateMainThread
0x00007FF6C2DC0C91 (Unity) PreloadManager::UpdatePreloadingSingleStep
0x00007FF6C2DC126F (Unity) PreloadManager::WaitForAllAsyncOperationsToComplete
0x00007FF6C3FD106C (Unity) EditorSceneManager::RestoreSceneBackups
0x00007FF6C3CD8FED (Unity) PlayerLoopController::ExitPlayMode
0x00007FF6C3CE8AE1 (Unity) PlayerLoopController::SetIsPlaying
0x00007FF6C3CEBF4B (Unity) Application::TickTimer
0x00007FF6C4140FBA (Unity) MainMessageLoop
0x00007FF6C414588B (Unity) WinMain
0x00007FF6C552315E (Unity) __scrt_common_main_seh
0x00007FFB5A4A26AD (KERNEL32) BaseThreadInitThunk
0x00007FFB5AEAA9F8 (ntdll) RtlUserThreadStart

When I set a breakpoint in OnDestroy(), and then continue, the crash doesn't occur anymore. Do you have an idea how this crash is caused? Is the delegate perhaps still destroyed too early?

0

There are 0 best solutions below