为了C#游戏开发一直在搞乱FMOD,我很早就遇到了麻烦,我似乎无法绕过。我想做一些分支音频的东西并将一些游戏动作同步到节拍等等,所以我尝试将同步点添加到我的音乐曲目中。这是代码:
public class Music
{
private Sound music;
private Channel channel;
private IntPtr syncPtr;
public string File { get; private set; }
public Music(string file)
{
File = file;
}
public void Load()
{
music = new Sound();
Audio.System.createSound(File, MODE.HARDWARE, ref music);
}
public void Unload()
{
music.release();
}
public virtual void Play()
{
Audio.System.playSound(channel == null ? CHANNELINDEX.FREE : CHANNELINDEX.REUSE, music, false, ref channel);
music.addSyncPoint(500, TIMEUNIT.MS, "wooo", ref syncPtr);
channel.setCallback(channelCallback);
}
private RESULT channelCallback(IntPtr channelraw, CHANNEL_CALLBACKTYPE type, IntPtr commanddata1, IntPtr commanddata2)
{
if (type == CHANNEL_CALLBACKTYPE.SYNCPOINT)
Console.WriteLine("sync!");
return RESULT.OK;
}
}
然后......
m = new Music(MUS_TUTORIAL); //m is static
m.Load();
m.Play();
这首歌加载并播放正常...直到它达到我添加的500毫秒同步点。此时,VC#从FMOD.EventSystem.update()中吐出以下错误:
对垃圾收集的类型委托进行了回调 '游戏!FMOD.CHANNEL_CALLBACK ::调用'。这可能会导致应用程序崩溃,损坏和 数据丢失。将委托传递给非托管代码时,它们必须保持活着状态 托管应用程序,直到确保它们永远不会被调用。
所以不知何故FMOD正在失去我传递给它的委托的踪迹。持有委托的Music实例并没有被垃圾收集 - 我现在将它存储在一个静态变量中 - 但我尝试使用静态方法也无济于事。如果我禁用CallbackOnCollectedDelegate MDA,则错误将成为空引用异常,因此MDA不会出错。我想我必须完全不了解FMOD在这里做了什么。
任何C#+ FMOD大师都能看到我的错误吗?
答案 0 :(得分:27)
channel.setCallback(channelCallback);
这是问题陈述。 FMod是非托管代码。您正在此处创建委托对象并将其传递给非托管代码。问题是,垃圾收集器无法跟踪本机代码所持有的引用。下一个垃圾收集将找到 no 对该对象的引用并收集它。 Kaboom在本机代码进行回调时。
你需要自己保留一个引用,这样就不会发生:
public class Music
{
private SomeDelegateType callback
//...
public Music(string file)
{
File = file;
callback = new SomeDelegateType(channelCallback);
}
public virtual void Play()
{
Audio.System.playSound(channel == null ? CHANNELINDEX.FREE : CHANNELINDEX.REUSE, music, false, ref channel);
music.addSyncPoint(500, TIMEUNIT.MS, "wooo", ref syncPtr);
channel.setCallback(callback);
}
您需要从FMod包装器代码中找到实际的委托类型,我只是猜到了“SomeDelegateType”。
答案 1 :(得分:0)
我在VB.NET和自定义C ++ DLL之间遇到了类似的问题。感谢@Hans。我欠了这个网站多次,因为它让我度过了所有的问题。添加我的问题+解决方案,希望它能帮助其他人在不同的环境中看到相同的解决方案。
声明这个(在模块中)
Public Delegate Sub CB_FUNC(ByVal x As Integer, ByVal y As Integer)
Public Declare Sub vidProc_cb_MouseClick Lib "C:\Users\.....\vidProc\product\vidProc.dll" (ByVal addr_update As CB_FUNC)
在button_click sub中进行了简单的调用:
vidProc_cb_MouseClick(AddressOf updateXY)
我会收到'CallbackOnCollectedDelegate'错误。不是立即,但在与表单上的其他对象交互后,然后尝试调用回调(在我的情况下是在OpenCV窗口中单击鼠标)。
1)声明(在表格类,声明中)
Private addr_update As CB_FUNC
2)在Form Load
上定义addr_updateaddr_update = New CB_FUNC(AddressOf updateXY)
3)使用新指针调用我的'set callback'函数(在button_click sub中)
vidProc_cb_MouseClick(addr_update)
我想我理解@Hans并正确实现它(我无法重现错误)。希望这有助于某人。