Autoplay next item in AudioTable

Hi everyone!

So I have a WALKMAN in my game that’s using an AudioTable together with Programmer Instrument to play music tracks. The tracks play and everything works except one crucial part, autoplay.

I know which key is the next one I want to play, I just simply can’t get it to work without freezing the game.

After a track has been played I want it to play the next one from an audio table. I can provide the next key no problem but everything seems to crash. This is my programmer instrument callback, everything is matching FMOD’s example except case EVENT_CALLBACK_TYPE.DESTROYED: where I try to play the next in my list.

Doing this freezes the game completely, anyone got a clue on how I can implement this?

Here’s my programmer music callback

[AOT.MonoPInvokeCallback(typeof(EVENT_CALLBACK))]
static RESULT MusicEventCallback(EVENT_CALLBACK_TYPE type, EventInstance instance, IntPtr parameterPtr)
{
	// Retrieve the user data
	instance.getUserData(out var stringPtr);

	// Get the string object
	GCHandle stringHandle = GCHandle.FromIntPtr(stringPtr);
	string key = stringHandle.Target as string;

	switch (type)
	{
		case EVENT_CALLBACK_TYPE.CREATE_PROGRAMMER_SOUND:
		{
			const MODE soundMode = MODE.LOOP_NORMAL | MODE.CREATECOMPRESSEDSAMPLE | MODE.NONBLOCKING;
			var parameter = (PROGRAMMER_SOUND_PROPERTIES) Marshal.PtrToStructure(parameterPtr, typeof(PROGRAMMER_SOUND_PROPERTIES));

			var keyResult = RuntimeManager.StudioSystem.getSoundInfo(key, out var dialogueSoundInfo);
			if (keyResult != RESULT.OK)
			{
				break;
			}
		
			var soundResult = RuntimeManager.CoreSystem.createSound(dialogueSoundInfo.name_or_data, soundMode | dialogueSoundInfo.mode, ref dialogueSoundInfo.exinfo, out var dialogueSound);
			if (soundResult == RESULT.OK)
			{
				parameter.sound = dialogueSound.handle;
				parameter.subsoundIndex = dialogueSoundInfo.subsoundindex;
				Marshal.StructureToPtr(parameter, parameterPtr, false);
			}

			break;
		}
		case EVENT_CALLBACK_TYPE.DESTROY_PROGRAMMER_SOUND:
		{
			var parameter = (PROGRAMMER_SOUND_PROPERTIES) Marshal.PtrToStructure(parameterPtr, typeof(PROGRAMMER_SOUND_PROPERTIES));
			var sound = new Sound {handle = parameter.sound};
			sound.release();
			
			CassettePlayer.instance.PlayNext(); // Play next song
			break;
		}
		case EVENT_CALLBACK_TYPE.DESTROYED:
		{
			// Now the event has been destroyed, unpin the string memory so it can be garbage collected
			stringHandle.Free();
			break;
		}
	}

	return RESULT.OK;
}