# Get instance from ChannelControl in SYSTEM\_CALLBACK\_TYPE.ERROR

**URL:** <https://qa.fmod.com/t/get-instance-from-channelcontrol-in-system-callback-type-error/22690>\
**Category:** Unity\
**Tags:** csharp\
**Created:** [March 12, 2025, 2:59pm UTC](https://qa.fmod.com/t/get-instance-from-channelcontrol-in-system-callback-type-error/22690 "2025-03-12T14:59:47Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![Imapler](https://avatars.discourse-cdn.com/v4/letter/i/7feea3/32.png) [@Imapler](https://qa.fmod.com/u/Imapler)\
**Post date:** [March 12, 2025, 2:59pm UTC](https://qa.fmod.com/t/get-instance-from-channelcontrol-in-system-callback-type-error/22690/1 "2025-03-12T14:59:47Z")

</div>

I have registered a callback to get errors that looks like this and im trying to get the name of the thing to debug it but CHANNELGROUP is an interface and i cant figure out a way to determine the underlying type since all i have is the raw pointer.

```auto
        errorCallback = new FMOD.SYSTEM_CALLBACK(ERROR_CALLBACK);
        var result = system.setCallback(errorCallback, FMOD.SYSTEM_CALLBACK_TYPE.ERROR);

        private static FMOD.RESULT ERROR_CALLBACK(IntPtr system, FMOD.SYSTEM_CALLBACK_TYPE type, IntPtr commanddata1, IntPtr commanddata2, IntPtr userdata)
        {
            FMOD.ERRORCALLBACK_INFO callbackInfo = Marshal.PtrToStructure<FMOD.ERRORCALLBACK_INFO>(commanddata1);

            if(callbackInfo.instancetype == ERRORCALLBACK_INSTANCETYPE.CHANNELGROUP)
            {
                // get the name or other identifier of the callbackInfo.instance
            }
        }

```

---

<div class="post-metadata">

**Author:** ![jeff\_fmod](https://yyz2.discourse-cdn.com/flex036/user_avatar/qa.fmod.com/jeff_fmod/32/1766_2.png) [@jeff\_fmod](https://qa.fmod.com/u/jeff_fmod)\
**Post date:** [March 16, 2025, 11:32pm UTC](https://qa.fmod.com/t/get-instance-from-channelcontrol-in-system-callback-type-error/22690/2 "2025-03-16T23:32:03Z")

</div>

We provide parameterized constructors which you can use to wrap an `IntPtr` in its corresponding type. i.e

```cs
if (callbackInfo.instancetype == ERRORCALLBACK_INSTANCETYPE.CHANNELGROUP)
{
    FMOD.ChannelGroup cg = new FMOD.ChannelGroup(callbackInfo.instance);
    cg.getName(out string name, 256);
}
else if (callbackInfo.instancetype == ERRORCALLBACK_INSTANCETYPE.CHANNEL)
{
    FMOD.Channel c = new FMOD.Channel(callbackInfo.instance);
    channel.getName(out string name, 256);
}

```

---

<div class="post-metadata">

**Author:** ![Imapler](https://avatars.discourse-cdn.com/v4/letter/i/7feea3/32.png) [@Imapler](https://qa.fmod.com/u/Imapler)\
**Post date:** [March 17, 2025, 9:15am UTC](https://qa.fmod.com/t/get-instance-from-channelcontrol-in-system-callback-type-error/22690/3 "2025-03-17T09:15:06Z")

</div>

Ok but what do i do if it is an CHANNELCONTROL which is an IChannelControl interface in c#?

---

<div class="post-metadata">

**Author:** ![jeff\_fmod](https://yyz2.discourse-cdn.com/flex036/user_avatar/qa.fmod.com/jeff_fmod/32/1766_2.png) [@jeff\_fmod](https://qa.fmod.com/u/jeff_fmod)\
**Post date:** [March 17, 2025, 11:41pm UTC](https://qa.fmod.com/t/get-instance-from-channelcontrol-in-system-callback-type-error/22690/4 "2025-03-17T23:41:02Z")

</div>

I am not sure what an `IChannelControl` is, it doesn’t appear to be part of the FMOD Unity Integration that we ship, but I think I see what you mean- how do you take the instance pointer for a [`ChannelControl`](https://fmod.com/docs/2.02/api/core-api-channelcontrol.html) and convert it into either the `Channel` or `ChannelGroup`.  
If that is what you are after, you can do a similar thing to what I mentioned above but test the conversion from `IntrPtr` to the corresponding type with a successful API call:

```auto
if (callbackInfo.instancetype == FMOD.ERRORCALLBACK_INSTANCETYPE.CHANNELCONTROL)
{
    FMOD.Channel c = new FMOD.Channel(callbackInfo.instance);
    if (c.getCurrentSound(out FMOD.Sound sound) == FMOD.RESULT.OK)
    {
        sound.getName(out string soundName, 256);
        Debug.Log("soundName: " + soundName);
    }
    FMOD.ChannelGroup cg = new FMOD.ChannelGroup(callbackInfo.instance);
    if (cg.getName(out string cgName, 256) == FMOD.RESULT.OK)
    {
        Debug.Log("cgName: " + cgName);
    }
}

```

---

<div class="post-metadata">

**Author:** ![Imapler](https://avatars.discourse-cdn.com/v4/letter/i/7feea3/32.png) [@Imapler](https://qa.fmod.com/u/Imapler)\
**Post date:** [March 18, 2025, 7:22am UTC](https://qa.fmod.com/t/get-instance-from-channelcontrol-in-system-callback-type-error/22690/5 "2025-03-18T07:22:11Z")

</div>

I tried doing that but all i get out is garbage like a “�” or some random characters such as “xzK7”. Also it seems like both often return the same string.

The IChannelControl is in  
Assets/Plugins/FMOD/src/fmod.cs:2064  
and it is implemented by Channel and ChannelGroup.  
Im guessing its just a straight port of the abstract base class thats used in c++ which is not really useful in c# since there seem to be no way to check the pointer type.

There is also a [channelcontrol\_type](https://www.fmod.com/docs/2.01/api/core-api-channelcontrol.html#fmod_channelcontrol_type) but that only seems to be used for a CHANNELCONTROL\_CALLBACK.

Also seems strange to me that the callback returns the abstract type instead of the actual type.

---

<div class="post-metadata">

**Author:** ![jeff\_fmod](https://yyz2.discourse-cdn.com/flex036/user_avatar/qa.fmod.com/jeff_fmod/32/1766_2.png) [@jeff\_fmod](https://qa.fmod.com/u/jeff_fmod)\
**Post date:** [March 19, 2025, 11:15pm UTC](https://qa.fmod.com/t/get-instance-from-channelcontrol-in-system-callback-type-error/22690/6 "2025-03-19T23:15:57Z")

</div>

> [@Imapler](#):
>
> The IChannelControl is in  
> Assets/Plugins/FMOD/src/fmod.cs:2064

Thanks, I have no idea why I couldn’t find this when searching previously.  
Not sure why we have `IChannelControl` either, outside of maybe for composite structures- but yes it’s probably just mirroring the C++ API.

> [@Imapler](#):
>
> I tried doing that but all i get out is garbage like a “�” or some random characters such as “xzK7”.

Can you please tell me the value of each `callbackInfo` member during one of these garbage name logs, and send me an updated snippet of your callback?

---

<div class="post-metadata">

**Author:** ![Imapler](https://avatars.discourse-cdn.com/v4/letter/i/7feea3/32.png) [@Imapler](https://qa.fmod.com/u/Imapler)\
**Post date:** [March 20, 2025, 8:03am UTC](https://qa.fmod.com/t/get-instance-from-channelcontrol-in-system-callback-type-error/22690/7 "2025-03-20T08:03:26Z")

</div>

Here are two examples of results and the code I use. I remove the execution paths that arent taken for brevity.

I dont get any ok results so it makes sense that I get garbage out but if I cant get the sound of the ChannelGroup because it was stolen, its not a very useful instance. What I actually want is both the stolen and the thief as that would make it easier to debug.

```auto
 FMOD.ERRORCALLBACK_INFO
functionname "ChannelControl::stop" nativeUtf8Ptr 0x7ffe21a5ce88
functionparams "" nativeUtf8Ptr 0xf4323f030
instance 0x203c0041
instancetype CHANNELCONTROL
result ERR_CHANNEL_STOLEN

channel.getCurrentSound ERR_CHANNEL_STOLEN
sound.getName ERR_INVALID_PARAM
sound description "c:\game\x.sourcegen.componentaccessgenerator\x.sourcegen.componentaccessgenerator.componentmanagergeneration.generator\temp\generatedcode\y.shared\gameplayconditionchecker__componentmanagergeneration_sls_795.g.cs"

channelGroup.getName ERR_INVALID_HANDLE
channelGroup description "event:/AMB/Local/Amb_Local/Fire/AMB_Local_Fire_Torch_Generic_Loop_FILTER"

-------------

```

```auto
 FMOD.ERRORCALLBACK_INFO
functionname "ChannelControl::stop" nativeUtf8Ptr 0x7ffe21a5cc40
functionparams "" nativeUtf8Ptr 0xf4323efe0
instance 0x203c0041
instancetype CHANNELCONTROL
result ERR_CHANNEL_STOLEN

channel.getCurrentSound ERR_CHANNEL_STOLEN
sound.getName ERR_INVALID_PARAM 
sound description "" <-- square is ETX

channelGroup.getName ERR_INVALID_HANDLE 
channelGroup description "xq\t��" <-- square is SOH

--------------

```

The code for getting the data above

```auto
[AOT.MonoPInvokeCallback(typeof(FMOD.SYSTEM_CALLBACK))]
private static FMOD.RESULT ERROR_CALLBACK(IntPtr system, FMOD.SYSTEM_CALLBACK_TYPE type, IntPtr commanddata1, IntPtr commanddata2, IntPtr userdata)
{
    FMOD.ERRORCALLBACK_INFO callbackInfo = Marshal.PtrToStructure<FMOD.ERRORCALLBACK_INFO>(commanddata1);

    var func = (string)callbackInfo.functionname;
    var param = (string)callbackInfo.functionparams;
    var instancetype = callbackInfo.instancetype;
    var instance = callbackInfo.instance;

    var description = "";
    const int NAME_MAX_LENGTH = 256;
    switch (instancetype)
    {
        case FMOD.ERRORCALLBACK_INSTANCETYPE.CHANNELCONTROL:
        {
            FMOD.Channel channel = new FMOD.Channel(instance);
            var result1 = channel.getCurrentSound(out FMOD.Sound sound);
            var result2 = sound.getName(out description, NAME_MAX_LENGTH);

            FMOD.ChannelGroup channelGroup = new FMOD.ChannelGroup(instance);
            var result3 = channelGroup.getName(out description, NAME_MAX_LENGTH);
            break;
        }
    }
}

```

My actual code looks like this

```auto
switch (instancetype)
{
    case FMOD.ERRORCALLBACK_INSTANCETYPE.CHANNELCONTROL:
    {
        var channel = new FMOD.Channel(instance);
        if (channel.getCurrentSound(out FMOD.Sound sound) == FMOD.RESULT.OK)
        {
            var result = sound.getName(out description, NAME_MAX_LENGTH);
            return result == FMOD.RESULT.OK;
        }
        else
        {
            FMOD.ChannelGroup channelGroup = new FMOD.ChannelGroup(instance);
            var result = channelGroup.getName(out description, NAME_MAX_LENGTH);
            return result == FMOD.RESULT.OK;
        }
    }
}

```

---

<div class="post-metadata">

**Author:** ![Imapler](https://avatars.discourse-cdn.com/v4/letter/i/7feea3/32.png) [@Imapler](https://qa.fmod.com/u/Imapler)\
**Post date:** [March 20, 2025, 8:22am UTC](https://qa.fmod.com/t/get-instance-from-channelcontrol-in-system-callback-type-error/22690/8 "2025-03-20T08:22:48Z")

</div>

While we are on the topic of stolen audio logs, we also have another debug log thats set up like this

```auto
var debugCallback = new FMOD.DEBUG_CALLBACK(DEBUG_CALLBACK);
var result = FMOD.Debug.Initialize(fmodSettings.LoggingLevel, FMOD.DEBUG_MODE.CALLBACK, debugCallback, null);

[AOT.MonoPInvokeCallback(typeof(FMOD.DEBUG_CALLBACK))]
private static FMOD.RESULT DEBUG_CALLBACK(FMOD.DEBUG_FLAGS flags, IntPtr filePtr, int line, IntPtr funcPtr, IntPtr messagePtr)
{
    FMOD.StringWrapper funcWrapper = new FMOD.StringWrapper(funcPtr);
    FMOD.StringWrapper messageWrapper = new FMOD.StringWrapper(messagePtr);

    string func = (string)funcWrapper;
    string message = (string)messageWrapper;

    RuntimeUtils.DebugLog($"[FMOD] {func} : {message}", flags);

    return FMOD.RESULT.OK;
}

```

And the message looks like this  
`"[FMOD] ChannelI::updateVirtualState : Channel 0x23EC002D Stolen with audibility 0.180135"`

Is there any way to get that pointer and instancetype without having to parse the string?

---

<div class="post-metadata">

**Author:** ![jeff\_fmod](https://yyz2.discourse-cdn.com/flex036/user_avatar/qa.fmod.com/jeff_fmod/32/1766_2.png) [@jeff\_fmod](https://qa.fmod.com/u/jeff_fmod)\
**Post date:** [March 24, 2025, 1:54am UTC](https://qa.fmod.com/t/get-instance-from-channelcontrol-in-system-callback-type-error/22690/9 "2025-03-24T01:54:15Z")

</div>

> [@Imapler](#):
>
> I dont get any ok results so it makes sense that I get garbage out but if I cant get the sound of the ChannelGroup because it was stolen, its not a very useful instance.

Okay in the context of channel stealing I can see why you wouldn’t be getting a workable `Channel` from the instance pointer.

> [@Imapler](#):
>
> Is there any way to get that pointer and instancetype without having to parse the string?

We don’t have a way to get the pointer or instance type during a `DEBUG_CALLBACK`, that callback is really just intended for passing you a formatted string message to give to your own logging system.

If you want more details on the now destroyed `Channel`, you could potentially retrieve it ahead of time and store it in a dictionary, using the instance pointer to look up the corresponding sound name in the error callback. I acknowledge though that this is an unreasonable amount of effort just to figure out which sound has disappeared, and this is pretty clearly a limitation with our logging- I will suggest to the Dev team that we add some information on the stolen `Sound` name either in that `updateVirtualState` log or in the `ERRORCALLBACK_INFO`.

In the meantime, the recommended way to debug voice stealing is to use the [FMOD Studio Profiler](https://fmod.com/docs/2.02/studio/profiling.html). You might not be able to easily figure out which `Channel` stole a voice from which other `Channel`, but with the [Lifespans](https://fmod.com/docs/2.02/studio/profiling.html#reading-a-recorded-session) graph you’ll be able to see which voices are dropping in and out, which is probably the next best things.

---

<div class="post-metadata">

**Author:** ![Imapler](https://avatars.discourse-cdn.com/v4/letter/i/7feea3/32.png) [@Imapler](https://qa.fmod.com/u/Imapler)\
**Post date:** [March 24, 2025, 7:37am UTC](https://qa.fmod.com/t/get-instance-from-channelcontrol-in-system-callback-type-error/22690/10 "2025-03-24T07:37:48Z")

</div>

> [@jeff\_fmod](#):
>
> …unreasonable amount of effort…

👍

> [@jeff\_fmod](#):
>
> In the meantime, the recommended way…

Thats really useful, i had done some profiling but i missed the lifetime option.  
However some of what im seeing is not really explained well in lifetime link you provided.

 ![image](https://canada1.discourse-cdn.com/flex036/uploads/fmod/original/2X/0/0548abaf6e740a2f66366d68edf59a3c513d487d.png)  
Im guessing the bright line is the playing event and the faded lines are virtualized?

![image](https://canada1.discourse-cdn.com/flex036/uploads/fmod/original/2X/1/1aaa8684fe899fb450ad788218401a71a309b476.png)  
Whats the difference between a solid line and dotted line (referenced?)

![image](https://canada1.discourse-cdn.com/flex036/uploads/fmod/original/2X/a/acc8f6f6e20c8fc620a54ce7b2ff41c54d242c5f.png)  
Also im guessing the left and right “cap” of the line is just there to show start/stop?

![image](https://canada1.discourse-cdn.com/flex036/uploads/fmod/original/2X/1/1aaa8684fe899fb450ad788218401a71a309b476.png)  
And that this is just the dotted version of the start/stop “caps”?

---

<div class="post-metadata">

**Author:** ![Imapler](https://avatars.discourse-cdn.com/v4/letter/i/7feea3/32.png) [@Imapler](https://qa.fmod.com/u/Imapler)\
**Post date:** [March 24, 2025, 3:11pm UTC](https://qa.fmod.com/t/get-instance-from-channelcontrol-in-system-callback-type-error/22690/11 "2025-03-24T15:11:57Z")

</div>

> [@jeff\_fmod](#):
>
> you could potentially retrieve it ahead of time and store it in a dictionary, using the instance pointer to look up the corresponding sound name in the error callback

I tried this but i cant manage to connect the two ends.

When i send the event i have the event instance and from that i can get a ChannelGroup that has 0 getNumChannels and then when i get the error i get a Channel that i cant get the group or sounds from since it has been stolen.

---

<div class="post-metadata">

**Author:** ![jeff\_fmod](https://yyz2.discourse-cdn.com/flex036/user_avatar/qa.fmod.com/jeff_fmod/32/1766_2.png) [@jeff\_fmod](https://qa.fmod.com/u/jeff_fmod)\
**Post date:** [March 25, 2025, 4:30am UTC](https://qa.fmod.com/t/get-instance-from-channelcontrol-in-system-callback-type-error/22690/12 "2025-03-25T04:30:17Z")

</div>

Correct in all cases, faded lines are virtual, dotted lines are referenced, and the caps are for start/stop points, with different stylings for referenced and non-referenced event instances. There are also arrows which can have multiple meanings, such as when the event enters the “Stopping” state but hasn’t yet stopped:  
 ![image](https://canada1.discourse-cdn.com/flex036/uploads/fmod/original/2X/d/da51279dab4776e3d9e281f6cfb5b0a02c40ada7.png)

When sample data hasn’t yet loaded:  
 ![image](https://canada1.discourse-cdn.com/flex036/uploads/fmod/original/2X/a/a21818d6b249559003ae24eefbf4c1230b6a1550.png)

And when sample data has finished loading:  
 ![image](https://canada1.discourse-cdn.com/flex036/uploads/fmod/original/2X/1/1aeb5d09fe6e74776d5d10698baeea8007cb43da.png)

> [@Imapler](#):
>
> When i send the event i have the event instance and from that i can get a ChannelGroup that has 0 getNumChannels and then when i get the error i get a Channel that i cant get the group or sounds from since it has been stolen.

`Channel`s aren’t created immediately, and events can own various different `Channels` over their lifetime, so you would need to be constantly updating this hypothetical map of events and their `Channel`s. Additionally, the Core API layout of `Channel`s and `ChannelGroup`s can be a little surprising. The `ChannelGroup` returned from [`EventInstance::getChannelGroup`](https://fmod.com/docs/2.02/api/studio-api-eventinstance.html#studio_eventinstance_getchannelgroup) is the event’s [master track](https://fmod.com/docs/2.02/studio/glossary.html#master-track), so if you have multiple tracks in your event you will need to query the master track’s sub groups. Here is an example that recursively builds up a map of all `Channel`s and their corresponding `Sound` names for debug purposes:

```csharp
    Dictionary<int, string> channelNames = new Dictionary<int, string>();

    void AddChannels(ChannelGroup cg)
    {
        cg.getNumChannels(out int numChannels);
        for (int i = 0; i < numChannels; i++)
        {
            cg.getChannel(i, out Channel channel);
            channel.getCurrentSound(out Sound sound);
            sound.getName(out string name);

            int key = channel.handle.ToInt32();
            channelNames[key] = name;
        }
    }

    void AddGroupChannels(ChannelGroup cg)
    {
        cg.getNumGroups(out int numGroups);
        for (int i = 0; i < numGroups; i++)
        {
            cg.getGroup(i, out ChannelGroup subgroup);
            AddGroupChannels(subgroup);
        }
        AddChannels(cg);
    }
...
    // Call during update
    FMODUnity.RuntimeManager.CoreSystem.getMasterChannelGroup(out FMOD.ChannelGroup mCG);
    AddGroupChannels(mCG);

```

This doesn’t necessarily scale well as you would be traversing the entire channel hierarchy every update, but for debug purposes while we look into improving the logging it might help.

---

<div class="post-metadata">

**Author:** ![Imapler](https://avatars.discourse-cdn.com/v4/letter/i/7feea3/32.png) [@Imapler](https://qa.fmod.com/u/Imapler)\
**Post date:** [March 25, 2025, 12:02pm UTC](https://qa.fmod.com/t/get-instance-from-channelcontrol-in-system-callback-type-error/22690/13 "2025-03-25T12:02:34Z")

</div>

Thanks, that helps a lot, i would not have guessed thats the way to do it.

It seems to work for the most part, the only problem is that some of the stolen errors seem to happen when i call eventInstance.start which means that it hassent had time to cache the channels yet but it is a lot better than nothing.

It might be a tall order but it would be nice if the debug callbacks included the callstack so you can see where it was in the c# code when it triggered the error, right now it just cuts of before the callback, i assume because the call comes from the c++ side.

---

<div class="post-metadata">

**Author:** ![jeff\_fmod](https://yyz2.discourse-cdn.com/flex036/user_avatar/qa.fmod.com/jeff_fmod/32/1766_2.png) [@jeff\_fmod](https://qa.fmod.com/u/jeff_fmod)\
**Post date:** [March 25, 2025, 10:44pm UTC](https://qa.fmod.com/t/get-instance-from-channelcontrol-in-system-callback-type-error/22690/14 "2025-03-25T22:44:11Z")

</div>

> [@Imapler](#):
>
> i would not have guessed thats the way to do it.

Yeah we should really have an explainer somewhere on how an `EventInstance` is structured in terms of `Channels` and `ChannelGroups`, I will write up a task for that as well.

> [@Imapler](#):
>
> the only problem is that some of the stolen errors seem to happen when i call eventInstance.start

That would be the optimization to prevent a `Channel` from starting at all if its [audibility](https://fmod.com/docs/2.02/api/white-papers-virtual-voices.html#audibility-calculation) is too low to steal from an existing voice. I can’t think of any way to identify those voices using the current API unfortunately.

> [@Imapler](#):
>
> it would be nice if the debug callbacks included the callstack so you can see where it was in the c# code when it triggered the error

By default, the API calls you make into FMOD are pushed into a command buffer that are executed asynchronously by the [Studio Update Thread](https://fmod.com/docs/2.02/api/glossary.html#studio-update-thread), so the call stack of any log would be exclusively in FMOD and you wouldn’t be able to see the C# caller.  
However, if you add `FMOD.Studio.INITFLAGS.SYNCHRONOUS_UPDATE` to the `INITFLAGS` in `RuntimeManager.Initialize` (_Assets\Plugins\FMOD\src\RuntimeManager.cs line ~316_) the Studio Update Thread won’t be created and the command will execute immediately, so you will be able to see the C# caller. For debugging this could be useful, but I probably wouldn’t leave it in for release as it would mean every API call blocks the main thread while executing.

---

<div class="post-metadata">

**Author:** ![Imapler](https://avatars.discourse-cdn.com/v4/letter/i/7feea3/32.png) [@Imapler](https://qa.fmod.com/u/Imapler)\
**Post date:** [March 26, 2025, 7:10am UTC](https://qa.fmod.com/t/get-instance-from-channelcontrol-in-system-callback-type-error/22690/15 "2025-03-26T07:10:55Z")

</div>

Thank you, that answers all my questions regarding this
