# Callbacks from C# without crackling/popping

**URL:** <https://qa.fmod.com/t/callbacks-from-c-without-crackling-popping/23516>\
**Category:** FMOD Engine\
**Created:** [October 26, 2025, 8:51am UTC](https://qa.fmod.com/t/callbacks-from-c-without-crackling-popping/23516 "2025-10-26T08:51:20Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![katelyngadd](https://yyz2.discourse-cdn.com/flex036/user_avatar/qa.fmod.com/katelyngadd/32/8597_2.png) [@katelyngadd](https://qa.fmod.com/u/katelyngadd)\
**Post date:** [October 26, 2025, 8:51am UTC](https://qa.fmod.com/t/callbacks-from-c-without-crackling-popping/23516/1 "2025-10-26T08:51:20Z")

</div>

I’m using FMOD and FMOD Studio from C# without particular issues, but I ended up needing to add a custom DSP callback.

If the callback is written in C#, as expected, I get occasional pops/crackling (from GC stop-the-world pauses) and audio drops out if I pause to break into the debugger, since it suspends all my managed code, as expected.

I solved this on Windows by porting the DSP callback to C++. I can take the DSP callback and pass it to FMOD like this:

```csharp
// Pin buffer used by DSP callback
hCollectorBuffer = GCHandle.Alloc(_WaveformSamples, GCHandleType.Pinned);
// Get function pointer to DSP callback from C++, in 'callback' local
Collector_Init(hCollectorBuffer.AddrOfPinnedObject(), _WaveformSamples.Length, out var callback);
// Create delegate for the C++ DSP callback to pass to FMOD via marshaling
CallbackDelegate = Marshal.GetDelegateForFunctionPointer<DSP_READ_CALLBACK>(callback);
// Maintain a handle to the delegate so it's not collected
hCallbackDelegate = GCHandle.Alloc(CallbackDelegate);

// Populate DSP description
var nameBytes = new byte[32];
var name = "Collector\0";
Encoding.UTF8.GetBytes(name, 0, name.Length, nameBytes, 0);
var dspDesc = new DSP_DESCRIPTION {
    name = nameBytes,
    // This part sucks. We're round-tripping the C++ DSP callback through a Delegate wrapper.
    read = CallbackDelegate,
    numinputbuffers = 1,
    numoutputbuffers = 0
};
// Create DSP from description
AssertOk(FMod.System.createDSP(ref dspDesc, out FMod.CollectorDsp));

```

However, when running under Mono (on Steam Deck), there’s a problem: C++ function pointers don’t round-trip through delegates there. A managed wrapper gets passed to FMod, so the audio crackles/pops a lot on Steam Deck. I’ve [filed an issue report about it](https://github.com/mono/mono/issues/21850) so it may eventually get fixed in mono, but I was curious whether anyone had suggestions for a clean workaround.

Right now the workaround I’ve come up with is to define my own version of DSP\_DESCRIPTION that uses IntPtr instead of delegates, and that seems to work. But it means if DSP\_DESCRIPTION or createDSP ever change I’ll need to manually update my custom pinvoke, which isn’t great for maintenance:

```csharp

            [DllImport(FMOD.VERSION.dll)]
            public static extern RESULT FMOD5_System_CreateDSP (IntPtr system, ref DSP_DESCRIPTION_P description, out IntPtr dsp);

            [StructLayout(LayoutKind.Sequential)]
            public struct DSP_DESCRIPTION_P
            {
                public uint pluginsdkversion;
                [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
                public byte[] name;
                public uint version;
                public int numinputbuffers;
                public int numoutputbuffers;
                public IntPtr create;
                public IntPtr release;
                public IntPtr reset;
                public IntPtr read;
                public IntPtr process;
                public IntPtr setposition;

                public int numparameters;
                public IntPtr paramdesc;
                public IntPtr setparameterfloat;
                public IntPtr setparameterint;
                public IntPtr setparameterbool;
                public IntPtr setparameterdata;
                public IntPtr getparameterfloat;
                public IntPtr getparameterint;
                public IntPtr getparameterbool;
                public IntPtr getparameterdata;
                public IntPtr shouldiprocess;
                public IntPtr userdata;

                public IntPtr sys_register;
                public IntPtr sys_deregister;
                public IntPtr sys_mix;
            }

```

It seems like this would probably be an issue for Unity developers as well but I couldn’t find any existing threads discussing this problem. Maybe IL2CPP is immune to this issue and most Unity developers are using that instead of Mono?

---

<div class="post-metadata">

**Author:** ![cameron-fmod](https://yyz2.discourse-cdn.com/flex036/user_avatar/qa.fmod.com/cameron-fmod/32/261_2.png) [@cameron-fmod](https://qa.fmod.com/u/cameron-fmod)\
**Post date:** [November 10, 2025, 10:49pm UTC](https://qa.fmod.com/t/callbacks-from-c-without-crackling-popping/23516/2 "2025-11-10T22:49:56Z")

</div>

I’m not sure about the occasional pops/crackling, this isn’t something we have encountered but I’ll write up a task to investigate this further.

Are you able to try a `DllImport` instead of getting the callback via a function call? We have tested and confirmed that `DllImport`ed functions passed to FMOD as delegates come through as raw function pointers when using Mono.

---

<div class="post-metadata">

**Author:** ![katelyngadd](https://yyz2.discourse-cdn.com/flex036/user_avatar/qa.fmod.com/katelyngadd/32/8597_2.png) [@katelyngadd](https://qa.fmod.com/u/katelyngadd)\
**Post date:** [November 10, 2025, 11:02pm UTC](https://qa.fmod.com/t/callbacks-from-c-without-crackling-popping/23516/3 "2025-11-10T23:02:26Z")

</div>

It looks like I started with this approach first, hoping that it would solve the crackling problems for me. If DllImport works that’s great to know and I will try it out.

---

<div class="post-metadata">

**Author:** ![cameron-fmod](https://yyz2.discourse-cdn.com/flex036/user_avatar/qa.fmod.com/cameron-fmod/32/261_2.png) [@cameron-fmod](https://qa.fmod.com/u/cameron-fmod)\
**Post date:** [December 16, 2025, 10:56pm UTC](https://qa.fmod.com/t/callbacks-from-c-without-crackling-popping/23516/4 "2025-12-16T22:56:04Z")

</div>

Are you able to share what you are doing in your C# callbacks? It may help in trying to determine the cause of the crackling/popping.

---

<div class="post-metadata">

**Author:** ![katelyngadd](https://yyz2.discourse-cdn.com/flex036/user_avatar/qa.fmod.com/katelyngadd/32/8597_2.png) [@katelyngadd](https://qa.fmod.com/u/katelyngadd)\
**Post date:** [December 16, 2025, 11:10pm UTC](https://qa.fmod.com/t/callbacks-from-c-without-crackling-popping/23516/5 "2025-12-16T23:10:10Z")

</div>

I copy the contents of the input buffer into a scratch buffer. Then the game processes it asynchronously. So the callback is very, very fast - basically just a memcpy into a ring buffer. Moving to C made the popping go away on windows where the roundtripping was already implemented. The good news is the mono team has fixed it in upstream, so the fix will eventually make its way to stuff like steam deck I think. So between it working with pinvokes and the mono fix I think you can treat this as resolved, it was just a surprising landmine to run into.

---

<div class="post-metadata">

**Author:** ![katelyngadd](https://yyz2.discourse-cdn.com/flex036/user_avatar/qa.fmod.com/katelyngadd/32/8597_2.png) [@katelyngadd](https://qa.fmod.com/u/katelyngadd)\
**Post date:** [January 29, 2026, 5:10pm UTC](https://qa.fmod.com/t/callbacks-from-c-without-crackling-popping/23516/6 "2026-01-29T17:10:58Z")

</div>

As an update on this, I’m now wiring up the callback the suggested way - with a p/invoke as a delegate - but I still get pretty bad popping/crackling specifically on steam deck with proton. Everything is great on Windows though. If you are interested in investigating I can provide a build, or if there are log files or something I can capture from fmod’s mixer I would be happy to provide them. My CPU and GPU usage according to the Steam Deck’s performance metrics are both around 20% and I’m no longer running any C# in fmod callbacks. I do have some C#-based FMOD Studio callbacks, but I don’t think those should cause popping or crackling, right?

I’m guessing this could be something to do with Mono still, since proton uses mono to run my code. It may go away once I migrate to using .NET 11 to run things, so once I get an opportunity to do that I will update this thread to mention whether it went away.

---

<div class="post-metadata">

**Author:** ![cameron-fmod](https://yyz2.discourse-cdn.com/flex036/user_avatar/qa.fmod.com/cameron-fmod/32/261_2.png) [@cameron-fmod](https://qa.fmod.com/u/cameron-fmod)\
**Post date:** [February 10, 2026, 4:05am UTC](https://qa.fmod.com/t/callbacks-from-c-without-crackling-popping/23516/7 "2026-02-10T04:05:30Z")

</div>

Apologies for the delay, I will see if I can reproduce this on a steam deck this week. If that doesn’t work then I will let you know what I need from you. Either way I will report back here with the results.

---

<div class="post-metadata">

**Author:** ![cameron-fmod](https://yyz2.discourse-cdn.com/flex036/user_avatar/qa.fmod.com/cameron-fmod/32/261_2.png) [@cameron-fmod](https://qa.fmod.com/u/cameron-fmod)\
**Post date:** [February 13, 2026, 12:20am UTC](https://qa.fmod.com/t/callbacks-from-c-without-crackling-popping/23516/8 "2026-02-13T00:20:49Z")

</div>

I have done some testing using callbacks similar to the way we show in [Programmer Sounds](https://www.fmod.com/docs/2.03/unity/examples-programmer-sounds.html) and [Timeline Callbacks](https://www.fmod.com/docs/2.03/unity/examples-timeline-callbacks.html), and I tested in both native Linux and Windows made apps. None of the testing resulted in any kind of crackling/popping.

Are you able to provide more information about your callbacks and possibly even a copy of the implementation or an example of it at least.

---

<div class="post-metadata">

**Author:** ![katelyngadd](https://yyz2.discourse-cdn.com/flex036/user_avatar/qa.fmod.com/katelyngadd/32/8597_2.png) [@katelyngadd](https://qa.fmod.com/u/katelyngadd)\
**Post date:** [February 22, 2026, 5:41am UTC](https://qa.fmod.com/t/callbacks-from-c-without-crackling-popping/23516/9 "2026-02-22T05:41:28Z")

</div>

This is the callback implementation:

```cpp
    __declspec(dllexport) FMOD_RESULT Collector_Read(
        FMOD_DSP_STATE* dsp_state, float* inbuffer, float* outbuffer, uint32_t length, int32_t inchannels, int32_t* outchannels
    ) {
        float* samples = CollectorBuffer;
        int writePosition = CollectorWritePosition, writeEnd = CollectorBufferSize;
        float accumulator, scale = 1.0f / inchannels;

        for (int i = 0, ii = 0; i < length; i++, ii += inchannels) {
            accumulator = 0;
            for (int j = 0; j < inchannels; j++) {
                accumulator += inbuffer[ii + j];
            }

            samples[writePosition] = accumulator * scale;
            if (++writePosition == writeEnd)
                writePosition = 0;
        }

        // Zero the output so we produce silence
        memset(outbuffer, 0, sizeof(float) * length * *outchannels);
        *outchannels = 1;

        CollectorWritePosition = writePosition;

        return FMOD_OK;
    }

```

I’d be happy to provide a steam key or a ZIP of the build so you can try to repro on your end. It could be something wrong with the steam deck I’m testing with specifically, or some sort of issue with Proton. I’ve now got the ability to test with .NET 11 Preview 1 so I will do some more testing there to see if this is limited to Proton’s version of Mono.

Are there some diagnostic flags I can set or logs I can record from the fmod mixer to identify whether something bad is happening like buffer underruns? That would help me rule out issues with my specific steam deck’s hardware.
