我发现在我的应用程序中经常报告错误。我知道它发生在哪里,我只是不知道为什么。该应用程序播放声音效果(不是背景音乐),我正在使用Xna.Audio,我有一个计时器定期调用FrameworkDispatcher.Update()。我正在使用SoundEffect.CreateInstance,所以我可以使用声音效果循环。看起来更改音量时会发生错误。我不知道为什么。是否存在可能失败的已知情况?
功能 :::偏移
xxx_RaiseException ::: 32
WatsonUnhandledManagedException ::: 300
Dbg_NotifyManagedException ::: 136
FirstPassException ::: 1044
TransitionStub ::: 0
Microsoft.Xna.Framework.Helpers.ThrowExceptionFromErrorCode ::: 76
Microsoft.Xna.Framework.Audio.SoundEffectInstance.set_Volume ::: 232
Microsoft.Xna.Framework.Audio.SoundEffectInstance..ctor ::: 232
Microsoft.Xna.Framework.Audio.SoundEffect.CreateInstance ::: 192
AgiliTrain.PhoneyTools.Media.SoundEffectPlayer..ctor ::: 96
WildSafari.ClassicModeGame.animalVisibleTimer_Tick ::: 344
...剪断....
对于那些要求,这里有更多的代码。 SoundEffectPlayer获取SoundEffect,创建一个实例,然后启动XNA FrameworkDispatcher(通过GameTimer)。此代码取自PhoneyTools,如果您需要更多上下文,请查看codeplex项目。当我想播放效果时,我只是新建一个SoundEffectPlayer,并传递我想要的内容。
public class SoundEffectPlayer
{
GameTimer _xnaTimer = new GameTimer();
SoundEffectInstance _effect = null;
public float _duration;
public SoundEffectPlayer(SoundEffect effect, bool loop)
{
_effect = effect.CreateInstance();
_effect.IsLooped = loop;
_duration = (float)effect.Duration.TotalSeconds;
}
public void Play(float volume)
{
_xnaTimer.Start();
_effect.Play();
_effect.Volume = volume;
}
public void Stop()
{
_effect.Stop(true);
_xnaTimer.Stop();
}
}
public class GameTimer
{
DispatcherTimer _timer = new DispatcherTimer()
{
Interval = TimeSpan.FromMilliseconds(50),
};
public GameTimer()
{
_timer.Tick += new EventHandler(_timer_Tick);
}
void _timer_Tick(object sender, EventArgs e)
{
FrameworkDispatcher.Update();
}
public void Start()
{
if (!_timer.IsEnabled) _timer.Start();
}
public void Stop()
{
if (_timer.IsEnabled) _timer.Stop();
}
}
答案 0 :(得分:1)
虽然我没有有效的解决方案,但仍尝试提供帮助......
SoundEffectInstance的setter属性并不像人们想象的那么简单:
set
{
lock (this.voiceHandleLock)
{
if (this.IsDisposed)
{
throw new ObjectDisposedException(base.GetType().Name, FrameworkResources.ObjectDisposedException);
}
if ((value < 0f) || (value > 1f))
{
throw new ArgumentOutOfRangeException("value");
}
Helpers.ThrowExceptionFromErrorCode(SoundEffectUnsafeNativeMethods.SetVolume(this.voiceHandle, value));
this.currentVolume = value;
}
}
基本上我们所追求的部分是在最后一行之前。
如果来自 SoundEffectUnsafeNativeMethods.SetVolume 的调用返回任何小于0的代码,则会触发您获得的异常。
以下是不安全方法中发生的事情:
public static unsafe int modopt(IsLong) SetVolume(uint soundEffectInstanceHandle, float volume)
{
lock (SoundEffectSubsystemSyncObject)
{
if ((soundEffectInstanceHandle != 0) && (soundEffectInstanceHandle != uint.MaxValue))
{
CHandleTable* tablePtr = ?g_pTable@CHandleTable@@0PAV1@A;
KernelSoundEffectInstance* instancePtr = CHandleTable.LookUp<class Microsoft::Xna::Framework::Audio::KernelSoundEffectInstance>((CHandleTable modopt(IsConst)* modopt(IsConst) modopt(IsConst)) ?g_pTable@CHandleTable@@0PAV1@A, soundEffectInstanceHandle, 0);
if (instancePtr == null)
{
return -2147024809;
}
return **(((int*) instancePtr))[0x34](instancePtr, volume);
}
return -2147024809;
}
}
您可以尝试使用try ... catch包围_effect.CreateInstance的创建并重新抛出一个更全面且有用的异常,其中包含有关您正在尝试创建的SoundEffect对象的信息(基本上您可以记下所有字段的值以供检查。(不确定从MS获得的只是堆栈跟踪或实际的异常消息)。
似乎在WP7上,设置音量的调用会转到某些操作系统指针表,这些表在幕后做了一些魔术,并在此表中查找声音效果句柄。
如果由于某种原因找不到它或类似的东西(不知道为什么,也许我们可以把它与XNA开发人员一起使用),它会抛出你得到的这个例外。
我知道这不是一个解决方案,但也许这是朝着正确方向迈出的一步。
答案 1 :(得分:0)
通常,不应该针对您描述的情况抛出异常,只要您按原样构建XNA兼容性层(详细信息here)。
但是,我注意到您正在使用PhoneyTools.Media.SoundEffectPlayer
- 为什么?这可能是您遇到问题的原因。
此外,您似乎有不明确的引用 - effect
和_effect
- 在播放内容时您正在使用哪一个?