Exiting play mode while programmer sound is playing causes warnings

When exiting play mode after playing a programmer sound, FMOD will log a warning:
“[FMOD] EventInstance::flushReleaseQueue : Event instance has programmer sounds pending release, update thread will be blocked until programmer sounds are released.”

I can’t seem to figure out how to prevent this warning.

Here’s my code that handles playing programmer sounds:

public class NarrativeAudioPlayer : MonoBehaviour {

	#region Constants

	public const string EventPath = "event:/VO/vo_presenter";

	#endregion

	#region Fields

	[SerializeField] private EventReference voEvent;

	#endregion

	#region Events

	private EVENT_CALLBACK dialogueCallback;
	private EventInstance dialogue;

	public delegate void AudioCallback(NarrativeAudioPlayer audioPlayer, string key, ulong uniqueId, NetworkRunner runner);
	public static event AudioCallback onPlayAudio = default;

	#endregion

	#region Unity Methods

	void Start() {

		// Explicitly create the delegate object and assign it to a member so it doesn't get freed
		// by the garbage collected while it's being used

		dialogueCallback = new EVENT_CALLBACK(OnDialogueEvent);
	}

#if UNITY_EDITOR
	void Reset() {

		voEvent = EventReference.Find(EventPath);
	}
#endif
	#endregion

	#region Public Methods

	public EventInstance PlayDialogue(string key, ulong uniqueId, NetworkRunner runner, bool stopPrevious) {

		if (string.IsNullOrEmpty(key)) {
			return default;
		}

		//stop previous before playing new if required

		if (stopPrevious) {

			Stop();
		}

		//create new dialogue

		dialogue = RuntimeManager.CreateInstance(voEvent);

		// Pin the key string in memory and pass a pointer through the user data
		GCHandle stringHandle = GCHandle.Alloc(key);
			
		dialogue.setUserData(GCHandle.ToIntPtr(stringHandle));
		dialogue.setCallback(dialogueCallback);
		dialogue.start();
		dialogue.release();

		onPlayAudio?.Invoke(this, key, uniqueId, runner);

		return dialogue;
	}

	public void Pause() {

		if (dialogue.isValid()) {

			dialogue.setPaused(true);
		}
	}

	public void Resume() {

		if (dialogue.isValid()) {

			dialogue.setPaused(false);
		}
	}

	public void Stop() {

		if (dialogue.isValid()) {

			dialogue.release();
			dialogue.stop(FMOD.Studio.STOP_MODE.ALLOWFADEOUT);
			dialogue = default;
		}
	}

	#endregion

	#region Private Methods

	private static void CreateProgrammerSound(string key, IntPtr parameterPtr) {

		//FMOD.MODE soundMode = FMOD.MODE.LOOP_NORMAL | FMOD.MODE.CREATECOMPRESSEDSAMPLE | FMOD.MODE.NONBLOCKING;
		FMOD.MODE soundMode = FMOD.MODE.CREATESTREAM;
		var parameter = (PROGRAMMER_SOUND_PROPERTIES)Marshal.PtrToStructure(parameterPtr, typeof(PROGRAMMER_SOUND_PROPERTIES));

		SOUND_INFO dialogueSoundInfo;
		var keyResult = RuntimeManager.StudioSystem.getSoundInfo(key, out dialogueSoundInfo);

		if (keyResult != FMOD.RESULT.OK) {
			return;
		}

		FMOD.Sound dialogueSound;
		var soundResult = RuntimeManager.CoreSystem.createSound(dialogueSoundInfo.name_or_data, soundMode | dialogueSoundInfo.mode, ref dialogueSoundInfo.exinfo, out dialogueSound);

		if (soundResult == FMOD.RESULT.OK) {

			parameter.sound = dialogueSound.handle;
			parameter.subsoundIndex = dialogueSoundInfo.subsoundindex;
			Marshal.StructureToPtr(parameter, parameterPtr, false);
		}
	}

	private static void DestroyProgrammerSound(IntPtr parameterPtr) {

		var parameter = (PROGRAMMER_SOUND_PROPERTIES)Marshal.PtrToStructure(parameterPtr, typeof(PROGRAMMER_SOUND_PROPERTIES));
		var sound = new FMOD.Sound(parameter.sound);
		sound.release();
	}

	#endregion

	#region Events Callback

	[MonoPInvokeCallback(typeof(EVENT_CALLBACK))]
	private static FMOD.RESULT OnDialogueEvent(EVENT_CALLBACK_TYPE type, IntPtr instancePtr, IntPtr parameterPtr) {

		EventInstance instance = new EventInstance(instancePtr);

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

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

		if (type == EVENT_CALLBACK_TYPE.CREATE_PROGRAMMER_SOUND) {

			CreateProgrammerSound(key, parameterPtr);
		}
		else if (type == EVENT_CALLBACK_TYPE.DESTROY_PROGRAMMER_SOUND) {

			DestroyProgrammerSound(parameterPtr);
		}
		else if (type == EVENT_CALLBACK_TYPE.DESTROYED) {

			// Now the event has been destroyed, unpin the string memory so it can be garbage collected
			stringHandle.Free();
		}

		return FMOD.RESULT.OK;
	}

	#endregion
}

Is there anything I’m doing wrong here?

Using FMOD 2.02.13 for Unity

Hi,

Thank you for bringing this to our attention. You are not doing anything wrong, unfortunately, there is no way to avoid this warning. I have passed this on to our development team to look into further.

Ok no problem. Seems to be harmless anyway

1 Like

Exactly, it is just a warning so it shouldn’t affect your project.