Programmer sound on Nintendo Switch

Hello
I recently started porting our game to Nintendo Switch, and I’m running into some problems regarding programmer sounds.

When playing dialogues in the game, I use this code to pass on the dialogue name:

DialogUserData d = new DialogUserData(key, speakerType, notify); GCHandle stringHandle = GCHandle.Alloc(d, GCHandleType.Pinned); dialogueInstance.setUserData(GCHandle.ToIntPtr(stringHandle)); dialogueInstance.setCallback(dialogueCallback);

DialogueUserData is a struct that looks like this:

[StructLayout(LayoutKind.Sequential)]
struct DialogUserData {
public string Key;
public int Speaker;
public uint NotifyIndex;

        public DialogUserData(string key, int speaker, uint onNotify) {
            Key=key;
            NotifyIndex = onNotify;
            Speaker = speaker;
        }

}

This works great on desktop, but when I try this code on the switch I get the following error:

ArgumentException: Object contains non-primitive or non-blittable data.
at System.Runtime.InteropServices.GCHandle.GetTargetHandle (System.Object obj, System.Int32 handle, System.Runtime.InteropServices.GCHandleType type) [0x00000] in <00000000000000000000000000000000>:0
at System.Runtime.InteropServices.GCHandle…ctor (System.Object value, System.Runtime.InteropServices.GCHandleType type) [0x00000] in <00000000000000000000000000000000>:0
at System.Runtime.InteropServices.GCHandle.Alloc (System.Object value, System.Runtime.InteropServices.GCHandleType type) [0x00000] in <00000000000000000000000000000000>:0
at Scripts.Bjorn.AudioManager.PlayDialog (System.String key, UnityEngine.GameObject go, System.Boolean is3D, Scripts.Bjorn.AudioManager+EventNotifyDelegate onNotify, System.Int32 speakerType) [0x00000]

Im guessing this has to do with the string not being a blittable value, however I did try pass on just a string instead of a struct to test if that would work, and it did not produce an error. Why is this the case?
Even though passing a simple string worked, I still got another error further down:

NotSupportedException: To marshal a managed method, please add an attribute named ‘MonoPInvokeCallback’ to the method definition.
at FMOD.Studio.EventInstance.FMOD_Studio_EventInstance_SetCallback (System.IntPtr _event, FMOD.Studio.EVENT_CALLBACK callback, FMOD.Studio.EVENT_CALLBACK_TYPE callbackmask) [0x00000] in <00000000000000000000000000000000>:0
at FMOD.Studio.EventInstance.setCallback (FMOD.Studio.EVENT_CALLBACK callback, FMOD.Studio.EVENT_CALLBACK_TYPE callbackmask) [0x00000] in <00000000000000000000000000000000>:0
at Scripts.Bjorn.AudioManager.PlayDialog (System.String key, UnityEngine.GameObject go, System.Boolean is3D, Scripts.Bjorn.AudioManager+EventNotifyDelegate onNotify, System.Int32 speakerType) [0x00000]

So I guess I have two problems:

  1. How do I pass a struct (cointaining a string) as the user data for the event?
  2. What is the other error that occurs with .setCallback ?

So I managed to fix my first problem by changing my code to this:

GCHandle stringHandle = GCHandle.Alloc(key, GCHandleType.Pinned);
DialogUserData d = new DialogUserData(GCHandle.ToIntPtr(stringHandle), speakerType, notify);
GCHandle dataHandle = GCHandle.Alloc(d, GCHandleType.Pinned);
dialogueInstance.setUserData(GCHandle.ToIntPtr(dataHandle));

where the struct looks like this:

[StructLayout(LayoutKind.Sequential)]
struct DialogUserData {
public IntPtr Key;

  public int Speaker;
  public uint NotifyIndex; 

  public DialogUserData(IntPtr key, int speaker, uint onNotify) {
            Key=key;
            NotifyIndex = onNotify;
            Speaker = speaker;
  }

}

Im still curious how it’s possible to pin a single string, but not a struct containing a string though.

I found a solution to the other problem in another thread here on the forum. Adding the attribute [AOT.MonoPInvokeCallback (typeof (FMOD.Studio.EVENT_CALLBACK))] above my callback function was all I needed to do.
I think this should be included in the scripting examples for future reference.

1 Like

The examples should have included:

[AOT.MonoPInvokeCallback (typeof (FMOD.Studio.EVENT_CALLBACK))]

Thanks for pointing that out, I have fixed this for the upcoming release.