We just upgraded to Unity 2021.2.* and realized our programmer sounds no longer function. We’re getting this stack trace:
NotSupportedException: IL2CPP does not support marshaling delegates that point to instance methods to native code. The method we're attempting to marshal is: FMOD.SOUND_PCMREAD_CALLBACK::Invoke
at FMOD.System.FMOD5_System_CreateSound (System.IntPtr system, System.IntPtr name_or_data, FMOD.MODE mode, FMOD.CREATESOUNDEXINFO& exinfo, System.IntPtr& sound) [0x00000] in <00000000000000000000000000000000>:0
at Audio.FMODSound+<HandlePlayDialogueRoutineAsyncRoutine>d__33.MoveNext () [0x00000] in <00000000000000000000000000000000>:0
at UnityEngine.SetupCoroutine.InvokeMoveNext (System.Collections.IEnumerator enumerator, System.IntPtr returnValueAddress) [0x00000] in <00000000000000000000000000000000>:0
at PixelCrushers.DialogueSystem.SequencerCommands.SequencerCommandDialogueWait.Awake () [0x00000] in <00000000000000000000000000000000>:0
at PixelCrushers.DialogueSystem.Sequencer.ActivateCommand (System.String commandName, System.String endMessage, UnityEngine.Transform speaker, UnityEngine.Transform listener, System.String[] args) [0x00000] in <00000000000000000000000000000000>:0
at PixelCrushers.DialogueSystem.Sequencer.OnSequencerMessage (System.String message) [0x00000] in <00000000000000000000000000000000>:0
at LeanTween.update () [0x00000] in <00000000000000000000000000000000>:0
PixelCrushers.DialogueSystem.SequencerCommands.SequencerCommandDialogueWait:Awake()
PixelCrushers.DialogueSystem.Sequencer:ActivateCommand(String, String, Transform, Transform, String[])
PixelCrushers.DialogueSystem.Sequencer:OnSequencerMessage(String)
LeanTween:update()
Tested on:
FMOD 2.01.14, 2.02.05
Platforms: iOS, macOS
Unity: 2.02.07
Here’s a repro. Just build it for MacOS or iOS and it should reproduce the issue.
Once the player loads to a blue screen, hit space bar.
Thank you for the repro, it looks like this is related to a known issue with FMOD when using IL2CPP and Unity 2021.2. The current workaround is to assign null to the pcmreadcallback, pcmsetposcallback and nonblockcallback in the SOUND_INFO.exinfo
struct before calling createSound
. Can you please try that and see if that gets around the exception and lets programmer sounds play correctly?
Thanks very much for taking a look! I tried out the suggested workaround:
private IEnumerator HandlePlayDialogueRoutineAsyncRoutine(string dialogueTableKey, Action<EventInstance> soundReadyCallback)
{
// Return Value
EventInstance eventInstance;
eventInstance.handle = IntPtr.Zero;
// Load Sound Path
FMOD.Studio.SOUND_INFO dialogueSoundInfo;
FMOD.RESULT keyResult = FMODUnity.RuntimeManager
.StudioSystem
.getSoundInfo(dialogueTableKey, out dialogueSoundInfo);
if (keyResult != FMOD.RESULT.OK)
{
Debug.LogError("Couldn't find dialogue with key: " + dialogueTableKey);
soundReadyCallback?.Invoke(eventInstance);
yield break;
}
// TODO - Workaround - https://qa.fmod.com/t/fmod-programmer-sounds-no-longer-work-unity-2021-2/18137
dialogueSoundInfo.exinfo.pcmreadcallback = null;
dialogueSoundInfo.exinfo.pcmsetposcallback = null;
dialogueSoundInfo.exinfo.nonblockcallback = null;
// TODO
// Load Sound
FMOD.Sound dialogueSound;
FMOD.MODE soundMode = FMOD.MODE.LOOP_NORMAL
| FMOD.MODE.CREATECOMPRESSEDSAMPLE
| FMOD.MODE.NONBLOCKING;
FMOD.RESULT soundResult = FMODUnity.RuntimeManager.CoreSystem.createSound(
dialogueSoundInfo.name_or_data, soundMode | dialogueSoundInfo.mode,
ref dialogueSoundInfo.exinfo, out dialogueSound);
if (soundResult != FMOD.RESULT.OK)
{
Debug.LogError("Couldn't load sound: " + dialogueTableKey);
soundReadyCallback?.Invoke(eventInstance);
yield break;
}
// Wait to Load
int maxFrameWait = 120;
FMOD.OPENSTATE openstate;
uint percentbuffered;
bool starving;
bool diskbusy;
dialogueSound.getOpenState(out openstate, out percentbuffered, out starving, out diskbusy);
while (openstate != FMOD.OPENSTATE.READY)
{
yield return null;
dialogueSound.getOpenState(out openstate, out percentbuffered, out starving, out diskbusy);
if (--maxFrameWait <= 0)
{
dialogueSound.release();
Debug.LogError("Failed to load dialogue sound " + dialogueTableKey);
soundReadyCallback?.Invoke(eventInstance);
yield break;
}
}
// Create Instance
eventInstance = CreateInstance(DialogueEvent.eventPath);
// Store Loaded Sound Data
FMODUserData userData = eventInstance.GetUserData();
userData.fmodSound = dialogueSound;
userData.fmodSoundInfo = dialogueSoundInfo;
// Return the instance
soundReadyCallback(eventInstance);
}
However, it didn’t seem to have any effect. I still get this exception:
NotSupportedException: IL2CPP does not support marshaling delegates that point to instance methods to native code. The method we're attempting to marshal is: FMOD.FILE_OPEN_CALLBACK::Invoke │
at FMOD.System.createSound (System.IntPtr name_or_data, FMOD.MODE mode, FMOD.CREATESOUNDEXINFO& exinfo, FMOD.Sound& sound) [0x00000] in <00000000000000000000000000000000>:0 │
at Audio.FMODSound+<HandlePlayDialogueRoutineAsyncRoutine>d__42.MoveNext () [0x00000] in <00000000000000000000000000000000>:0 │
at UnityEngine.SetupCoroutine.InvokeMoveNext (System.Collections.IEnumerator enumerator, System.IntPtr returnValueAddress) [0x00000] in <00000000000000000000000000000000>:0 │
at PixelCrushers.DialogueSystem.SequencerCommands.SequencerCommandDialogueWait.Awake () [0x00000] in <00000000000000000000000000000000>:0 │
at PixelCrushers.DialogueSystem.Sequencer.ActivateCommand (System.String commandName, System.String endMessage, UnityEngine.Transform speaker, UnityEngine.Transform listener, System.String[] args) [0x00000] in <00000000000000000000000000000000>:0 │
at PixelCrushers.DialogueSystem.Sequencer.OnSequencerMessage (System.String message) [0x00000] in <00000000000000000000000000000000>:0 │
at LeanTween.update () [0x00000] in <00000000000000000000000000000000>:0 │
PixelCrushers.DialogueSystem.SequencerCommands.SequencerCommandDialogueWait:Awake() │
PixelCrushers.DialogueSystem.Sequencer:ActivateCommand(String, String, Transform, Transform, String[]) │
PixelCrushers.DialogueSystem.Sequencer:OnSequencerMessage(String) │
LeanTween:update()
Did I understand correctly?
Apologies for the oversight there, looks like you’ll also need to null out the other exinfo callbacks:
dialogueSoundInfo.exinfo.pcmreadcallback = null;
dialogueSoundInfo.exinfo.pcmsetposcallback = null;
dialogueSoundInfo.exinfo.nonblockcallback = null;
dialogueSoundInfo.exinfo.fileuseropen = null;
dialogueSoundInfo.exinfo.fileuserclose = null;
dialogueSoundInfo.exinfo.fileuserread = null;
dialogueSoundInfo.exinfo.fileuserseek = null;
dialogueSoundInfo.exinfo.fileuserasyncread = null;
dialogueSoundInfo.exinfo.fileuserasynccancel = null;
1 Like
That seems to have worked! Thanks for the workaround! Is this something that will ultimately be fixed by Unity or in a future release of FMOD? I just want to make sure we get the fix before launch.
Good to hear that worked! This is an issue with our C# wrapper that will be fixed in an upcoming release- it’s a simple solution and is affecting core functionality so I would expect it to be resolved soon.