How do you stop SoundEffect from crashing XNA windows games when they are closed?
I am creating a game for windows in xna using Visual C# Express. In the game, there are six SoundEffect objects which regularly have their Play() methods called. The problem is that sometimes when the game is closed it crashes. It appears to happen whenever the window is closed while a soundeffect is playing. This is the message which pops up in Visual C#:
AccessViolationException was unhandled
Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
There isn't any source available in visual studio to debug and when the "get general help for this exception" is clicked, a blank page pops up..
The code used looks a lot like the MSDN example. This looks like a problem that exists somewhere in the underlying framework somewhere, not my code. But of course I don't know for sure. This has happened many times.
http://msdn.microsoft.com/en-us/library/bb195053.aspx
Here are the complete exception details:
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:
(I also have music playing via MediaPlayer, but I don't think it's related.)
EDIT: I seem to have found something which works, but it's kind of hackish and really shouldn't be necessary. I'm still open to any more elegant solutions.
Call this line in Game1.UnloadContent(). It will make sure (if your sound effects are all shorter than 3 seconds) that no sound is playing when the program actually closes.
开发者_如何学GoSystem.Threading.Thread.Sleep(3000);
Make the SoundEffect object a class member and call the SoundEffect's Dispose() method on class deconstruction:
class MyClass
{
~MyClass()
{
effect.Dispose();
}
SoundEffect effect;
}
This should let the SoundEffect object clean itself up when you close the game. You can read about objects that are Disposable here: http://msdn.microsoft.com/en-us/library/system.idisposable.aspx
Can you make MyClass implement IDisposable and dispose of the SoundEffect in that method?
I think it's pretty safe to say that this is a bug in the framework. Because it's in the audio code, perhaps the framework is not handling something it's getting from a driver correctly. It's hard to say for sure.
Suffice to say that an AccessViolationException
coming out of the framework is not "normal". It's almost certainly not your fault.
The function IsEventRegistered
that the exception occurs in is an unsafe
function. So it's likely that function is doing exactly what the exception says: it is accessing an invalid memory address.
The exception is coming from the shutdown code for audio capture (microphone), so are you doing anything with the microphone in your code? You could possibly experiment with using/not using the microphone and see what happens.
Also: does this happen when you run without the debugger attached? (Ctrl+F5)
As for fixing the problem: Your solution is not a bad work-around.
If you cannot afford to wait the three seconds, and you want to get your hands dirty and write some very questionable (semi-unportable, not-necessaraly-forward-compatible) code: You could use reflection to access the private properties of the audio system. Find the list of SoundEffectInstance
objects that are created internally whenever you call SoundEffect.Play
, and then stop those instances before you shutdown.
Or you could do effectively the same thing by never calling Play
, but instead calling CreateInstance
and managing fire-and-forget sound effects on your own. The downside is that this requires writing an awful lot of code!
I had the same problem and I did nulls for my sound collections in class finalizer(destructor). Works for me.
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;
}
...
精彩评论