setCallback not working 😀

Hey guys,

I’m trying to use the setCallback function, but nothing I do seems to work. My timeline has two Destination Markers that should work to spawn an NPC when the dialogue reaches certain points. However, the NPC is never spawned, but I don’t get any errors or anything. I don’t even receive my debug log that I put inside FMOD.Studio.EVENT_CALLBACK.

The worst part is that I spent so much time trying to make this work that at one point I just gave up and decided to use two Command Instruments to change a parameter and check the value of that parameter in Unity to spawn the NPC, but even the Command Instruments are not working and the parameter I made doesn’t change value. Is my timeline cursed or am I doing too many things wrong? Can someone help me with that?

Here is my code:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using FMODUnity;
using FMOD.Studio;
using System;
using System.Runtime.InteropServices;

public class F_Dialogue : MonoBehaviour
{
    class TimelineInfo
    {
        public FMOD.StringWrapper LastMarker = new FMOD.StringWrapper();
        public Warden warden;
    }

    TimelineInfo timelineInfo;
    GCHandle timelineHandle;

    FMOD.Studio.EVENT_CALLBACK markerCallback;

    public static F_Dialogue Instance { get; private set; }
    private EmoteManager emoteManager;
    private Transform camTransform; //where event instances are attached

    private void Awake()
    {
        Instance = this;
    }

    private void Start()
    {
        emoteManager = GetComponent<EmoteManager>();
        camTransform = LocalReferenceManager.Instance.camHolder.transform;

        // Explicitly create the delegate object and assign it to a member so it doesn't get freed
        // by the garbage collector while it's being used
        markerCallback = new FMOD.Studio.EVENT_CALLBACK(HandleMarkerCallback);
    }

    public void PlayDialogue(DialogueDatabase _data, EventReference _reference, Warden _warden)
    {
        EventInstance _instance = RuntimeManager.CreateInstance(_reference);
        currentDiaEvent = _instance;
        RuntimeManager.AttachInstanceToGameObject(_instance, camTransform);

        if (_warden != null)
        {
            timelineInfo = new TimelineInfo
            {
                warden = _warden
            };

            // Pin the timelineInfo object in memory and pass a pointer through the user data
            timelineHandle = GCHandle.Alloc(timelineInfo);
            _instance.setUserData(GCHandle.ToIntPtr(timelineHandle));

            _instance.setCallback(markerCallback, FMOD.Studio.EVENT_CALLBACK_TYPE.TIMELINE_MARKER);
            Debug.Log("Callback set for warden");
        }

        emoteManager.QueueTimedEmotes(_data.emotes);

        PrintEventPath(_instance);

        _instance.start();
        StartCoroutine(WaitForSoundToFinish(_instance));
    }

    private IEnumerator WaitForSoundToFinish(EventInstance instance)
    {
        instance.getPlaybackState(out PLAYBACK_STATE state);
        while (state != PLAYBACK_STATE.STOPPED)
        {
            yield return new WaitForSeconds(0.1f);
            instance.getPlaybackState(out state);
        }
        instance.setUserData(IntPtr.Zero);
        instance.stop(FMOD.Studio.STOP_MODE.IMMEDIATE);
        instance.release();
        timelineHandle.Free();
    }

    [AOT.MonoPInvokeCallback(typeof(FMOD.Studio.EVENT_CALLBACK))]
    static FMOD.RESULT HandleMarkerCallback(FMOD.Studio.EVENT_CALLBACK_TYPE type, IntPtr instancePtr, IntPtr parameterPtr)
    {
        FMOD.Studio.EventInstance instance = new FMOD.Studio.EventInstance(instancePtr);

        // Retrieve the user data
        IntPtr timelineInfoPtr;
        instance.getUserData(out timelineInfoPtr);

        if (timelineInfoPtr != IntPtr.Zero)
        {
            GCHandle timelineHandle = GCHandle.FromIntPtr(timelineInfoPtr);
            TimelineInfo timelineInfo = (TimelineInfo)timelineHandle.Target;

            if (type == FMOD.Studio.EVENT_CALLBACK_TYPE.TIMELINE_MARKER)
            {
                var data = (FMOD.Studio.TIMELINE_MARKER_PROPERTIES)Marshal.PtrToStructure(parameterPtr, typeof(FMOD.Studio.TIMELINE_MARKER_PROPERTIES));
                timelineInfo.LastMarker = data.name;

                if            (timelineInfo.LastMarker == "WardenIn")
            {
                timelineInfo.warden.SpawnWarden();
                Debug.Log("WardenIn");
            }
            else if (timelineInfo.LastMarker == "WardenOff")
            {
                timelineInfo.warden.DespawnWarden();
                Debug.Log("WardenOff");
            }

            Debug.Log("Callback triggered"); // Add this line to check if the callback is being triggered
        }
    }

    return FMOD.RESULT.OK;
}

private void PrintEventPath(EventInstance instance)
{
    instance.getDescription(out EventDescription eventDescription);
    eventDescription.getPath(out string eventPath);
    Debug.Log("Event path: " + eventPath);
}

Hi,

I was able to get the callback to trigger by slightly changing your code as follows:

Changed Code
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using FMODUnity;
using FMOD.Studio;
using System;
using System.Runtime.InteropServices;

public class F_Dialogue : MonoBehaviour
{
	public FMODUnity.EventReference reference;

	class TimelineInfo
	{
		public FMOD.StringWrapper LastMarker = new FMOD.StringWrapper();
		//public Warden warden;
	}

	TimelineInfo timelineInfo;
	GCHandle timelineHandle;

	FMOD.Studio.EVENT_CALLBACK markerCallback;

	public static F_Dialogue Instance { get; private set; }
	//private EmoteManager emoteManager;
	public Transform camTransform; //where event instances are attached

	private void Awake()
	{
		Instance = this;
	}

	private void Start()
	{
		//emoteManager = GetComponent<EmoteManager>();
		//camTransform = LocalReferenceManager.Instance.camHolder.transform;

		// Explicitly create the delegate object and assign it to a member so it doesn't get freed
		// by the garbage collector while it's being used
		markerCallback = new FMOD.Studio.EVENT_CALLBACK(HandleMarkerCallback);
	}

	private void Update()
	{
		if (Input.GetKeyDown(KeyCode.Escape))
		{
			PlayDialogue(reference);

		}
	}

	public void PlayDialogue(/*DialogueDatabase _data*/ EventReference _reference)//, Warden _warden)
	{
		EventInstance _instance = RuntimeManager.CreateInstance(_reference);
		//currentDiaEvent = _instance;
		RuntimeManager.AttachInstanceToGameObject(_instance, camTransform);

		//if (_warden != null)
		//{
		//timelineInfo = new TimelineInfo
		//{
		//	warden = _warden
		//};

		// Pin the timelineInfo object in memory and pass a pointer through the user data
		//timelineHandle = GCHandle.Alloc(timelineInfo);
		//_instance.setUserData(GCHandle.ToIntPtr(timelineHandle));

		_instance.setCallback(markerCallback, FMOD.Studio.EVENT_CALLBACK_TYPE.TIMELINE_MARKER);
		Debug.Log("Callback set for warden");
		//}

		//emoteManager.QueueTimedEmotes(_data.emotes);

		PrintEventPath(_instance);

		_instance.start();
		StartCoroutine(WaitForSoundToFinish(_instance));
	}

	private IEnumerator WaitForSoundToFinish(EventInstance instance)
	{
		instance.getPlaybackState(out PLAYBACK_STATE state);
		while (state != PLAYBACK_STATE.STOPPED)
		{
			yield return new WaitForSeconds(0.1f);
			instance.getPlaybackState(out state);
		}
		instance.setUserData(IntPtr.Zero);
		instance.stop(FMOD.Studio.STOP_MODE.IMMEDIATE);
		instance.release();
		timelineHandle.Free();
	}

	[AOT.MonoPInvokeCallback(typeof(FMOD.Studio.EVENT_CALLBACK))]
	static FMOD.RESULT HandleMarkerCallback(FMOD.Studio.EVENT_CALLBACK_TYPE type, IntPtr instancePtr, IntPtr parameterPtr)
	{
		FMOD.Studio.EventInstance instance = new FMOD.Studio.EventInstance(instancePtr);

		// Retrieve the user data
		//IntPtr timelineInfoPtr;
		//instance.getUserData(out timelineInfoPtr);

		//if (timelineInfoPtr != IntPtr.Zero)
		//{
		//	GCHandle timelineHandle = GCHandle.FromIntPtr(timelineInfoPtr);
		//	TimelineInfo timelineInfo = (TimelineInfo)timelineHandle.Target;

		//	if (type == FMOD.Studio.EVENT_CALLBACK_TYPE.TIMELINE_MARKER)
		//	{
		//		var data = (FMOD.Studio.TIMELINE_MARKER_PROPERTIES)Marshal.PtrToStructure(parameterPtr, typeof(FMOD.Studio.TIMELINE_MARKER_PROPERTIES));
		//		timelineInfo.LastMarker = data.name;

		//		if (timelineInfo.LastMarker == "WardenIn")
		//		{
		//			timelineInfo.warden.SpawnWarden();
		//			Debug.Log("WardenIn");
		//		}
		//		else if (timelineInfo.LastMarker == "WardenOff")
		//		{
		//			timelineInfo.warden.DespawnWarden();
		//			Debug.Log("WardenOff");
		//		}

		//	}
		//}

		Debug.Log("Callback triggered"); // Add this line to check if the callback is being triggered
		return FMOD.RESULT.OK;
	}

	private void PrintEventPath(EventInstance instance)
	{
		instance.getDescription(out EventDescription eventDescription);
		eventDescription.getPath(out string eventPath);
		Debug.Log("Event path: " + eventPath);
	}
}

I cannot see any issues with your code, would it be possible to see your FMOD Studio Event? I will link our Timeline Scripting Example here Unity Integration | Scripting Examples - Timeline Callbacks. Hopefully, these will help.

Hi Connor,

Thanks for your answer.

I used this exactly example to make my code. But, I coundn’t make it work or even figure out why it is not working

Here is the time line that I was doing my tests on. As you can I have the markers, and also the command instruments to try to change the global parameters. But unfortunately none of them worked.

Hi,

On the line
_instance.setCallback(markerCallback, FMOD.Studio.EVENT_CALLBACK_TYPE.TIMELINE_MARKER);
Could we add some more Callback Flags to see if it is just not hitting the Timeline Marker Callback:
_instance.setCallback(markerCallback, FMOD.Studio.EVENT_CALLBACK_TYPE.TIMELINE_MARKER | EVENT_CALLBACK_TYPE.CREATED | EVENT_CALLBACK_TYPE.STARTING | EVENT_CALLBACK_TYPE.STARTED);

Let me know how that goes.