加载延迟超出警告 - Programmer Instrument - Unity
Loading delay exceeded warning - Programmer Instrument - Unity
每当我尝试将 FMOD 中的示例代码用于 Programmer Instrument
时,我都会收到一条警告:“超出加载延迟,声音可能会在不正确的时间播放”
我想也许我需要等待 FMOD.Sound openState == READY,但这似乎没有用。我错过了什么吗?这是我的代码:
public static void PlayDialogue(string key, Action callback = null)
{
// Create Instance
FMOD.Studio.EventInstance dialogueInstance = FMODUnity.RuntimeManager.CreateInstance(instance.dialogueEvent);
// Pin the key string in memory and pass a pointer through the user data
GCHandle stringHandle = GCHandle.Alloc(key, GCHandleType.Pinned);
dialogueInstance.setUserData(GCHandle.ToIntPtr(stringHandle));
dialogueInstance.setCallback(instance.dialogueCallback);
}
[AOT.MonoPInvokeCallback(typeof(FMOD.Studio.EVENT_CALLBACK))]
static FMOD.RESULT DialogueCallback(FMOD.Studio.EVENT_CALLBACK_TYPE type, IntPtr instancePtr, IntPtr parameterPtr)
{
// Get Instance
FMOD.Studio.EventInstance instance = new FMOD.Studio.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;
switch (type)
{
case FMOD.Studio.EVENT_CALLBACK_TYPE.CREATE_PROGRAMMER_SOUND:
{
FMOD.MODE soundMode = FMOD.MODE.LOOP_NORMAL
| FMOD.MODE.CREATECOMPRESSEDSAMPLE
| FMOD.MODE.NONBLOCKING;
FMOD.Studio.PROGRAMMER_SOUND_PROPERTIES programmerSoundProperties =
(FMOD.Studio.PROGRAMMER_SOUND_PROPERTIES)Marshal.PtrToStructure(
parameterPtr, typeof(FMOD.Studio.PROGRAMMER_SOUND_PROPERTIES));
FMOD.Sound dialogueSound;
if (key.Contains("."))
{
// Load Sound by Given Path
FMOD.RESULT soundResult = FMODUnity.RuntimeManager.CoreSystem.createSound(
Application.streamingAssetsPath + "/" + key, soundMode, out dialogueSound);
if (soundResult == FMOD.RESULT.OK)
{
programmerSoundProperties.sound = dialogueSound.handle;
programmerSoundProperties.subsoundIndex = -1;
Marshal.StructureToPtr(programmerSoundProperties, parameterPtr, false);
// Wait To Play
WaitForLoadThenPlay(instancePtr, parameterPtr);
}
}
else
{
// Load Sound Path
FMOD.Studio.SOUND_INFO dialogueSoundInfo;
FMOD.RESULT keyResult = FMODUnity.RuntimeManager.StudioSystem.getSoundInfo(key, out dialogueSoundInfo);
if (keyResult != FMOD.RESULT.OK) break;
// Load Sound
FMOD.RESULT soundResult = FMODUnity.RuntimeManager.CoreSystem.createSound(
dialogueSoundInfo.name_or_data, soundMode | dialogueSoundInfo.mode, ref dialogueSoundInfo.exinfo, out dialogueSound);
if (soundResult == FMOD.RESULT.OK)
{
programmerSoundProperties.sound = dialogueSound.handle;
programmerSoundProperties.subsoundIndex = dialogueSoundInfo.subsoundindex;
Marshal.StructureToPtr(programmerSoundProperties, parameterPtr, false);
// Wait To Play
WaitForLoadThenPlay(instancePtr, parameterPtr);
}
}
break;
}
case FMOD.Studio.EVENT_CALLBACK_TYPE.DESTROY_PROGRAMMER_SOUND:
{
FMOD.Studio.PROGRAMMER_SOUND_PROPERTIES parameter =
(FMOD.Studio.PROGRAMMER_SOUND_PROPERTIES)Marshal.PtrToStructure(
parameterPtr, typeof(FMOD.Studio.PROGRAMMER_SOUND_PROPERTIES));
FMOD.Sound sound = new FMOD.Sound(parameter.sound);
sound.release();
break;
}
case FMOD.Studio.EVENT_CALLBACK_TYPE.DESTROYED:
{
// Now the event has been destroyed, unpin the string memory so it can be garbage collected
stringHandle.Free();
break;
}
}
return FMOD.RESULT.OK;
}
private static void WaitForLoadThenPlay(IntPtr instancePtr, IntPtr parameterPtr)
=> instance.StartCoroutine(instance.WaitForLoadThenPlayRoutine(instancePtr, parameterPtr));
private IEnumerator WaitForLoadThenPlayRoutine(IntPtr instancePtr, IntPtr parameterPtr)
{
// Get Instance
FMOD.Studio.EventInstance instance = new FMOD.Studio.EventInstance(instancePtr);
// Grab Sound Reference
FMOD.Studio.PROGRAMMER_SOUND_PROPERTIES parameter =
(FMOD.Studio.PROGRAMMER_SOUND_PROPERTIES)Marshal.PtrToStructure(
parameterPtr, typeof(FMOD.Studio.PROGRAMMER_SOUND_PROPERTIES));
FMOD.Sound sound = new FMOD.Sound(parameter.sound);
// Wait for Load
FMOD.OPENSTATE state = FMOD.OPENSTATE.BUFFERING;
uint percentbuffered;
bool starving;
bool diskbusy;
while (state != FMOD.OPENSTATE.READY)
{
yield return null;
sound.getOpenState(out state, out percentbuffered, out starving, out diskbusy);
}
instance.start();
instance.release();
}
这是我最后做的。我不知道它是否有意义,但它确实消除了警告。我真的希望他们能修复文档。示例脚本无法正常工作。
public static void PlayDialogue(string key, Action callback = null) => instance.StartCoroutine(PlayDialogueRoutine(key, callback));
public static IEnumerator PlayDialogueRoutine(string key, Action callback = null)
{
// Check if Already Playing
if (instance.activeDialogue.ContainsKey(key))
{
Debug.LogError("Tried to play already playing dialogue");
callback?.Invoke();
yield break;
}
// Load Sound Path
FMOD.Studio.SOUND_INFO dialogueSoundInfo;
FMOD.RESULT keyResult = FMODUnity.RuntimeManager.StudioSystem.getSoundInfo(key, out dialogueSoundInfo);
if (keyResult != FMOD.RESULT.OK)
{
Debug.LogError("Couldn't find dialogue with key: " + key);
callback?.Invoke();
yield break;
}
// 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: " + key);
callback?.Invoke();
yield break;
}
// Wait to Load
int maxFrameWait = 120;
FMOD.OPENSTATE openstate = FMOD.OPENSTATE.BUFFERING;
uint percentbuffered;
bool starving;
bool 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 " + key);
yield break;
}
}
// Create Instance
FMOD.Studio.EventInstance dialogueInstance = FMODUnity.RuntimeManager.CreateInstance(instance.dialogueEvent);
// Store Reference (and remove in play stopped callback)
instance.activeDialogue[key] = dialogueInstance;
// Pin Memory
FMODDialogueParameterWrapper soundWrapper = new FMODDialogueParameterWrapper(dialogueSound, dialogueSoundInfo, () =>
{
instance.activeDialogue.Remove(key);
callback?.Invoke();
});
GCHandle soundWrapperHandle = GCHandle.Alloc(soundWrapper, GCHandleType.Pinned);
dialogueInstance.setUserData(GCHandle.ToIntPtr(soundWrapperHandle));
// Set Callback
dialogueInstance.setCallback(instance.dialogueCallback,
FMOD.Studio.EVENT_CALLBACK_TYPE.CREATE_PROGRAMMER_SOUND
| FMOD.Studio.EVENT_CALLBACK_TYPE.CREATE_PROGRAMMER_SOUND
| FMOD.Studio.EVENT_CALLBACK_TYPE.DESTROYED
| FMOD.Studio.EVENT_CALLBACK_TYPE.STOPPED);
// Play One Shot
dialogueInstance.start();
dialogueInstance.release();
}
[AOT.MonoPInvokeCallback(typeof(FMOD.Studio.EVENT_CALLBACK))]
static FMOD.RESULT DialogueCallback(FMOD.Studio.EVENT_CALLBACK_TYPE type, IntPtr instancePtr, IntPtr parameterPtr)
{
// Get Instance
FMOD.Studio.EventInstance instance = new FMOD.Studio.EventInstance(instancePtr);
// Retrieve the user data FMODDialogueParameterWrapper
IntPtr dialogueParameterWrapperPtr;
FMOD.RESULT result = instance.getUserData(out dialogueParameterWrapperPtr);
if (result != FMOD.RESULT.OK)
{
Debug.LogError("Failed to fetch user data for dialogue callback: " + result);
}
else if (dialogueParameterWrapperPtr != IntPtr.Zero)
{
GCHandle dialogueParameterWrapperHandle = GCHandle.FromIntPtr(dialogueParameterWrapperPtr);
FMODDialogueParameterWrapper dialogueParameterWrapper =
(FMODDialogueParameterWrapper)dialogueParameterWrapperHandle.Target;
switch (type)
{
case FMOD.Studio.EVENT_CALLBACK_TYPE.CREATE_PROGRAMMER_SOUND:
{
FMOD.Studio.PROGRAMMER_SOUND_PROPERTIES programmerSoundProperties =
(FMOD.Studio.PROGRAMMER_SOUND_PROPERTIES)Marshal.PtrToStructure(
parameterPtr, typeof(FMOD.Studio.PROGRAMMER_SOUND_PROPERTIES));
programmerSoundProperties.sound = dialogueParameterWrapper.sound.handle;
programmerSoundProperties.subsoundIndex = dialogueParameterWrapper.soundInfo.subsoundindex;
Marshal.StructureToPtr(programmerSoundProperties, parameterPtr, false);
break;
}
case FMOD.Studio.EVENT_CALLBACK_TYPE.DESTROY_PROGRAMMER_SOUND:
{
FMOD.Studio.PROGRAMMER_SOUND_PROPERTIES parameter =
(FMOD.Studio.PROGRAMMER_SOUND_PROPERTIES)Marshal.PtrToStructure(
parameterPtr, typeof(FMOD.Studio.PROGRAMMER_SOUND_PROPERTIES));
FMOD.Sound sound = new FMOD.Sound(parameter.sound);
sound.release();
break;
}
case FMOD.Studio.EVENT_CALLBACK_TYPE.DESTROYED:
{
// Now the event has been destroyed, unpin the string memory so it can be garbage collected
Debug.Log("Freeing");
dialogueParameterWrapperHandle.Free();
break;
}
case FMOD.Studio.EVENT_CALLBACK_TYPE.STOPPED:
{
dialogueParameterWrapper.onStopCallback?.Invoke();
break;
}
}
}
return FMOD.RESULT.OK;
}
[StructLayout(LayoutKind.Sequential)]
class FMODDialogueParameterWrapper
{
public FMOD.Sound sound;
public FMOD.Studio.SOUND_INFO soundInfo;
public Action onStopCallback;
public FMODDialogueParameterWrapper(FMOD.Sound sound, FMOD.Studio.SOUND_INFO soundInfo, Action onStopCallback)
{
this.sound = sound;
this.soundInfo = soundInfo;
this.onStopCallback = onStopCallback;
}
}
每当我尝试将 FMOD 中的示例代码用于 Programmer Instrument
时,我都会收到一条警告:“超出加载延迟,声音可能会在不正确的时间播放”我想也许我需要等待 FMOD.Sound openState == READY,但这似乎没有用。我错过了什么吗?这是我的代码:
public static void PlayDialogue(string key, Action callback = null)
{
// Create Instance
FMOD.Studio.EventInstance dialogueInstance = FMODUnity.RuntimeManager.CreateInstance(instance.dialogueEvent);
// Pin the key string in memory and pass a pointer through the user data
GCHandle stringHandle = GCHandle.Alloc(key, GCHandleType.Pinned);
dialogueInstance.setUserData(GCHandle.ToIntPtr(stringHandle));
dialogueInstance.setCallback(instance.dialogueCallback);
}
[AOT.MonoPInvokeCallback(typeof(FMOD.Studio.EVENT_CALLBACK))]
static FMOD.RESULT DialogueCallback(FMOD.Studio.EVENT_CALLBACK_TYPE type, IntPtr instancePtr, IntPtr parameterPtr)
{
// Get Instance
FMOD.Studio.EventInstance instance = new FMOD.Studio.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;
switch (type)
{
case FMOD.Studio.EVENT_CALLBACK_TYPE.CREATE_PROGRAMMER_SOUND:
{
FMOD.MODE soundMode = FMOD.MODE.LOOP_NORMAL
| FMOD.MODE.CREATECOMPRESSEDSAMPLE
| FMOD.MODE.NONBLOCKING;
FMOD.Studio.PROGRAMMER_SOUND_PROPERTIES programmerSoundProperties =
(FMOD.Studio.PROGRAMMER_SOUND_PROPERTIES)Marshal.PtrToStructure(
parameterPtr, typeof(FMOD.Studio.PROGRAMMER_SOUND_PROPERTIES));
FMOD.Sound dialogueSound;
if (key.Contains("."))
{
// Load Sound by Given Path
FMOD.RESULT soundResult = FMODUnity.RuntimeManager.CoreSystem.createSound(
Application.streamingAssetsPath + "/" + key, soundMode, out dialogueSound);
if (soundResult == FMOD.RESULT.OK)
{
programmerSoundProperties.sound = dialogueSound.handle;
programmerSoundProperties.subsoundIndex = -1;
Marshal.StructureToPtr(programmerSoundProperties, parameterPtr, false);
// Wait To Play
WaitForLoadThenPlay(instancePtr, parameterPtr);
}
}
else
{
// Load Sound Path
FMOD.Studio.SOUND_INFO dialogueSoundInfo;
FMOD.RESULT keyResult = FMODUnity.RuntimeManager.StudioSystem.getSoundInfo(key, out dialogueSoundInfo);
if (keyResult != FMOD.RESULT.OK) break;
// Load Sound
FMOD.RESULT soundResult = FMODUnity.RuntimeManager.CoreSystem.createSound(
dialogueSoundInfo.name_or_data, soundMode | dialogueSoundInfo.mode, ref dialogueSoundInfo.exinfo, out dialogueSound);
if (soundResult == FMOD.RESULT.OK)
{
programmerSoundProperties.sound = dialogueSound.handle;
programmerSoundProperties.subsoundIndex = dialogueSoundInfo.subsoundindex;
Marshal.StructureToPtr(programmerSoundProperties, parameterPtr, false);
// Wait To Play
WaitForLoadThenPlay(instancePtr, parameterPtr);
}
}
break;
}
case FMOD.Studio.EVENT_CALLBACK_TYPE.DESTROY_PROGRAMMER_SOUND:
{
FMOD.Studio.PROGRAMMER_SOUND_PROPERTIES parameter =
(FMOD.Studio.PROGRAMMER_SOUND_PROPERTIES)Marshal.PtrToStructure(
parameterPtr, typeof(FMOD.Studio.PROGRAMMER_SOUND_PROPERTIES));
FMOD.Sound sound = new FMOD.Sound(parameter.sound);
sound.release();
break;
}
case FMOD.Studio.EVENT_CALLBACK_TYPE.DESTROYED:
{
// Now the event has been destroyed, unpin the string memory so it can be garbage collected
stringHandle.Free();
break;
}
}
return FMOD.RESULT.OK;
}
private static void WaitForLoadThenPlay(IntPtr instancePtr, IntPtr parameterPtr)
=> instance.StartCoroutine(instance.WaitForLoadThenPlayRoutine(instancePtr, parameterPtr));
private IEnumerator WaitForLoadThenPlayRoutine(IntPtr instancePtr, IntPtr parameterPtr)
{
// Get Instance
FMOD.Studio.EventInstance instance = new FMOD.Studio.EventInstance(instancePtr);
// Grab Sound Reference
FMOD.Studio.PROGRAMMER_SOUND_PROPERTIES parameter =
(FMOD.Studio.PROGRAMMER_SOUND_PROPERTIES)Marshal.PtrToStructure(
parameterPtr, typeof(FMOD.Studio.PROGRAMMER_SOUND_PROPERTIES));
FMOD.Sound sound = new FMOD.Sound(parameter.sound);
// Wait for Load
FMOD.OPENSTATE state = FMOD.OPENSTATE.BUFFERING;
uint percentbuffered;
bool starving;
bool diskbusy;
while (state != FMOD.OPENSTATE.READY)
{
yield return null;
sound.getOpenState(out state, out percentbuffered, out starving, out diskbusy);
}
instance.start();
instance.release();
}
这是我最后做的。我不知道它是否有意义,但它确实消除了警告。我真的希望他们能修复文档。示例脚本无法正常工作。
public static void PlayDialogue(string key, Action callback = null) => instance.StartCoroutine(PlayDialogueRoutine(key, callback));
public static IEnumerator PlayDialogueRoutine(string key, Action callback = null)
{
// Check if Already Playing
if (instance.activeDialogue.ContainsKey(key))
{
Debug.LogError("Tried to play already playing dialogue");
callback?.Invoke();
yield break;
}
// Load Sound Path
FMOD.Studio.SOUND_INFO dialogueSoundInfo;
FMOD.RESULT keyResult = FMODUnity.RuntimeManager.StudioSystem.getSoundInfo(key, out dialogueSoundInfo);
if (keyResult != FMOD.RESULT.OK)
{
Debug.LogError("Couldn't find dialogue with key: " + key);
callback?.Invoke();
yield break;
}
// 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: " + key);
callback?.Invoke();
yield break;
}
// Wait to Load
int maxFrameWait = 120;
FMOD.OPENSTATE openstate = FMOD.OPENSTATE.BUFFERING;
uint percentbuffered;
bool starving;
bool 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 " + key);
yield break;
}
}
// Create Instance
FMOD.Studio.EventInstance dialogueInstance = FMODUnity.RuntimeManager.CreateInstance(instance.dialogueEvent);
// Store Reference (and remove in play stopped callback)
instance.activeDialogue[key] = dialogueInstance;
// Pin Memory
FMODDialogueParameterWrapper soundWrapper = new FMODDialogueParameterWrapper(dialogueSound, dialogueSoundInfo, () =>
{
instance.activeDialogue.Remove(key);
callback?.Invoke();
});
GCHandle soundWrapperHandle = GCHandle.Alloc(soundWrapper, GCHandleType.Pinned);
dialogueInstance.setUserData(GCHandle.ToIntPtr(soundWrapperHandle));
// Set Callback
dialogueInstance.setCallback(instance.dialogueCallback,
FMOD.Studio.EVENT_CALLBACK_TYPE.CREATE_PROGRAMMER_SOUND
| FMOD.Studio.EVENT_CALLBACK_TYPE.CREATE_PROGRAMMER_SOUND
| FMOD.Studio.EVENT_CALLBACK_TYPE.DESTROYED
| FMOD.Studio.EVENT_CALLBACK_TYPE.STOPPED);
// Play One Shot
dialogueInstance.start();
dialogueInstance.release();
}
[AOT.MonoPInvokeCallback(typeof(FMOD.Studio.EVENT_CALLBACK))]
static FMOD.RESULT DialogueCallback(FMOD.Studio.EVENT_CALLBACK_TYPE type, IntPtr instancePtr, IntPtr parameterPtr)
{
// Get Instance
FMOD.Studio.EventInstance instance = new FMOD.Studio.EventInstance(instancePtr);
// Retrieve the user data FMODDialogueParameterWrapper
IntPtr dialogueParameterWrapperPtr;
FMOD.RESULT result = instance.getUserData(out dialogueParameterWrapperPtr);
if (result != FMOD.RESULT.OK)
{
Debug.LogError("Failed to fetch user data for dialogue callback: " + result);
}
else if (dialogueParameterWrapperPtr != IntPtr.Zero)
{
GCHandle dialogueParameterWrapperHandle = GCHandle.FromIntPtr(dialogueParameterWrapperPtr);
FMODDialogueParameterWrapper dialogueParameterWrapper =
(FMODDialogueParameterWrapper)dialogueParameterWrapperHandle.Target;
switch (type)
{
case FMOD.Studio.EVENT_CALLBACK_TYPE.CREATE_PROGRAMMER_SOUND:
{
FMOD.Studio.PROGRAMMER_SOUND_PROPERTIES programmerSoundProperties =
(FMOD.Studio.PROGRAMMER_SOUND_PROPERTIES)Marshal.PtrToStructure(
parameterPtr, typeof(FMOD.Studio.PROGRAMMER_SOUND_PROPERTIES));
programmerSoundProperties.sound = dialogueParameterWrapper.sound.handle;
programmerSoundProperties.subsoundIndex = dialogueParameterWrapper.soundInfo.subsoundindex;
Marshal.StructureToPtr(programmerSoundProperties, parameterPtr, false);
break;
}
case FMOD.Studio.EVENT_CALLBACK_TYPE.DESTROY_PROGRAMMER_SOUND:
{
FMOD.Studio.PROGRAMMER_SOUND_PROPERTIES parameter =
(FMOD.Studio.PROGRAMMER_SOUND_PROPERTIES)Marshal.PtrToStructure(
parameterPtr, typeof(FMOD.Studio.PROGRAMMER_SOUND_PROPERTIES));
FMOD.Sound sound = new FMOD.Sound(parameter.sound);
sound.release();
break;
}
case FMOD.Studio.EVENT_CALLBACK_TYPE.DESTROYED:
{
// Now the event has been destroyed, unpin the string memory so it can be garbage collected
Debug.Log("Freeing");
dialogueParameterWrapperHandle.Free();
break;
}
case FMOD.Studio.EVENT_CALLBACK_TYPE.STOPPED:
{
dialogueParameterWrapper.onStopCallback?.Invoke();
break;
}
}
}
return FMOD.RESULT.OK;
}
[StructLayout(LayoutKind.Sequential)]
class FMODDialogueParameterWrapper
{
public FMOD.Sound sound;
public FMOD.Studio.SOUND_INFO soundInfo;
public Action onStopCallback;
public FMODDialogueParameterWrapper(FMOD.Sound sound, FMOD.Studio.SOUND_INFO soundInfo, Action onStopCallback)
{
this.sound = sound;
this.soundInfo = soundInfo;
this.onStopCallback = onStopCallback;
}
}