使用C#中的WPF框架编写应用程序(我真的很陌生,不要太苛刻我的编码风格哈哈)。当我退出时,我希望播放一些“再见”音频(使用NAudio 1.8.4从MPQ文件中读取流),即使主窗口消失也不要中断;因此我在名为PlayerThread的类中使用前景线程。
我使用PlayerThread构造函数播放声音
foregroundChannel = new PlayerThread(soundStream, null, null);
但是我以后没有跟踪它,我只是依靠PlayerThread在游戏后“自然地”结束。
这是PlayerThread构造函数:
public PlayerThread(MpqFileStream stream, Action<PlayerThread> over, Dispatcher callerDispatcher)
{
noCallback = false;
dispatcher = callerDispatcher;
fadeOut = false;
soundStream = stream;
ThreadStart threadStart = RunThread;
if (callerDispatcher != null)
{
callback = over;
threadStart += () =>
{
dispatcher.Invoke(() =>
{
Cleanup();
});
};
}
this.m_playerThread = new Thread(RunThread)
{
Name = "Audio Player Thread",
IsBackground = false
};
this.m_playerThread.SetApartmentState(ApartmentState.STA);
this.m_playerThread.Start();
}
这是它的工作:
private void RunThread()
{
internalPlayer = new WaveOut();
Mp3FileReader mp3FileReader = new Mp3FileReader(soundStream);
inputStream = new WaveChannel32(mp3FileReader);
internalPlayer.Init(inputStream);
internalPlayer.Play();
while (internalPlayer.PlaybackState == PlaybackState.Playing && !fadeOut)
{
System.Threading.Thread.Sleep(100);
}
if (fadeOut)
{
while (((float)0F).CompareTo(inputStream.Volume) < 0)
{
System.Threading.Thread.Sleep(150);
inputStream.Volume -= 0.1F;
}
}
internalPlayer.Dispose();
inputStream.Dispose();
mp3FileReader.Dispose();
soundStream.Dispose(); // Yeah I'm so desperate for a solution I'm just Disposing everything even though I don't think it helps
}
单击退出时,将执行以下行:
soundEngine.FadeOutBackground();
soundEngine.PlayVoice(SoundNamesConstants.BYE);
soundEngine.WaveGoodbye();
Close();
soundEngine.WaitForTheCrewBeforeWeighingAnchor();
最后,这是Cleanup()中的代码:
if (!noCallback)
callback.Invoke(this);
这里的回调非常无关紧要,我用它来切换音乐与淡出效果。另外,在这种情况下不会发生,因为我只是将noCallback设置为false。
如果有用,这是资源使用情况图表。红线是我按退出的时候。
更新
根据@sacha的建议添加Thread.Join()
同步:
public void WaitForTheCrewBeforeWeighingAnchor() // yes, every word matters
{
backgroundChannel.Join();
foreach (PlayerThread pt in foregroundChannels)
pt.Join();
}
没有问题加入backgroundChannel线程但从未加入foregroundChannels中唯一的线程。使用第5-6行反转第3行具有相同的结果,系统地未能pt.Join();
。此PlayerThread是单击退出时创建的。
更新2 这不是线程问题。这只是发生,因为并不总是满足条件internalPlayer.PlaybackState == PlaybackState.Playing
(使用断点检查),所以我们只是保持while循环。目前正在寻找更好的方法来检查比赛结束。
答案 0 :(得分:1)
WaveChannel32构造函数创建一个零填充缓冲区,这对于您进入混音器的场景非常有用。在这种情况下,它只是导致我的流到&#34;从来没有&#34;端。
添加:
inputStream.PadWithZeroes = false;
完全解决了我的问题。在这种情况下,并不需要加入。
了解更多信息:
永不结束的流问题
IWavePlayer的每个实现者确定它的方式 应该在Read方法上自动停止播放 source IWaveProvider返回0(实际上Read应该总是返回 count参数,除非已到达流的末尾。)
但是,NAudio中有一些WaveStreams / IWaveProviders 从不停止返回音频。这不是一个错误 - 这是很正常的 某些场景的行为。也许BufferedWaveProvider是最好的 例如 - 如果没有足够的话,它将返回一个零填充的缓冲区 排队的数据用于播放。这对于从中流式传输非常有用 网络中数据可能无法快速到达但您却没有 希望播放停止。类似地,WaveChannel32有一个名为的属性 PadWithZeroes允许您打开或关闭此行为,这可以 适用于您进入调音台的场景。
来自:http://mark-dot-net.blogspot.be/2011/05/naudio-and-playbackstopped-problem.html
答案 1 :(得分:0)
听起来你需要同步你的线程,主线程应该在退出之前等待其他线程完成。请查看Thread.Join
:https://msdn.microsoft.com/en-us/library/95hbf2ta(v=vs.110).aspx