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