你如何阻止SoundEffect在XNA windows游戏关闭时崩溃?

时间:2011-02-24 17:45:08

标签: c# xna audio

我正在使用Visual C#Express在xna中创建一个Windows游戏。在游戏中,有六个SoundEffect对象经常调用它们的Play()方法。问题是,有时当游戏关闭时,它会崩溃。 当正在播放soundeffect时窗口关闭时,似乎会发生这种情况。 这是在Visual C#中弹出的消息:

未处理AccessViolationException

尝试读取或写入受保护的内存。这通常表明其他内存已损坏。

Visual Studio中没有任何可用的源代码可供调试,当点击“获取此异常的常规帮助”时,会弹出一个空白页面。

使用的代码看起来很像MSDN示例。这看起来像是存在于底层框架某处的问题,而不是我的代码。但我当然不确定。这已经发生了很多次。

http://msdn.microsoft.com/en-us/library/bb195053.aspx

以下是完整的例外情况:

System.AccessViolationException was unhandled
  Message=Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
  Source=Microsoft.Xna.Framework
  StackTrace:
       at Microsoft.Xna.Framework.Audio.AudioCallbackDispatcher.IsEventRegistered(EventType type)
       at Microsoft.Xna.Framework.Audio.AudioCallbackDispatcher.UnregisterEvent(EventType type)
       at Microsoft.Xna.Framework.Audio.KernelMicrophone.ShutdownCaptureEngine()
       at Microsoft.Xna.Framework.Audio.MicrophoneUnsafeNativeMethods.ShutdownCaptureEngine()
       at Microsoft.Xna.Framework.Audio.AudioRendererShutdownHandler.AppExitingEventHandler(Object sender, EventArgs args)
  InnerException:

(我也通过MediaPlayer播放音乐,但我认为它不相关。)

编辑:我似乎找到了一些有用的东西,但它有点像hackish,真的不应该是必要的。我仍然愿意接受任何更优雅的解决方案。

在Game1.UnloadContent()中调用此行。它将确保(如果你的声音效果都短于3秒),当程序实际关闭时没有声音播放。

System.Threading.Thread.Sleep(3000);

4 个答案:

答案 0 :(得分:2)

使SoundEffect对象成为类成员并在类解构上调用SoundEffect的Dispose()方法:

class MyClass
{
    ~MyClass()
    {
        effect.Dispose();
    }

    SoundEffect effect;

}

当你关闭游戏时,这应该让SoundEffect对象自行清理。您可以在此处阅读有关Disposable的对象:http://msdn.microsoft.com/en-us/library/system.idisposable.aspx

答案 1 :(得分:1)

你能让MyClass实现IDisposable并在该方法中处理SoundEffect吗?

答案 2 :(得分:1)

我认为这是一个框架中的错误是非常安全的。因为它在音频代码中,所以框架可能没有正确处理它从驱动程序获得的内容。很难说肯定。

可以说框架中出现的AccessViolationException并非“正常”。几乎可以肯定不是你的错

发生异常的函数IsEventRegisteredunsafe函数。因此,函数可能正在执行异常所说的内容:它正在访问无效的内存地址。

异常来自音频捕获(麦克风)的关闭代码,所以你在代码中使用麦克风做了什么吗?您可以尝试使用/不使用麦克风,看看会发生什么。

另外:如果在没有附加调试器的情况下运行会发生这种情况吗? (Ctrl + F5键)

至于解决问题:您的解决方案并非糟糕。

如果你不能等待三秒钟,并且你想弄清楚并且写一些非常有问题的(半不可移植,不必要向前兼容)代码:你可以使用反射来访问音频系统的私有属性。找到每次调用SoundEffectInstance时在内部创建的SoundEffect.Play个对象的列表,然后在关闭之前停止这些实例。

或者你可以通过永远不会调用Play来做同样的事情,而是调用CreateInstance并自己管理即发即弃音效。缺点是这需要编写大量代码!

答案 3 :(得分:0)

我有同样的问题,我在类终结器(析构函数)中为我的声音集合做了空值。适合我。

public class Audio
{
    private ContentManager content;
    public List<SoundEffectInstance> SoundInstance { get; private set; }
    public AudioEmitter Emitter { get; set; }
    public AudioListener Listener { get; set; }
    public List<SoundEffect> Sound { get; set; }
    public Audio(ContentManager content)
    {
        this.content = content;
        Emitter = new AudioEmitter();
        Listener = new AudioListener();
        Sound = new List<SoundEffect>();
        SoundInstance = new List<SoundEffectInstance>();
    }
    //set to null your sound instances and effects :D
    ~Audio()
    {
        Sound = null;
        SoundInstance = null;
    }
...