NAudio WaveOut.PlaybackState 属性 未更新

NAudio WaveOut.PlaybackState property is not updated

在 C# 中使用 WPF 框架编写应用程序(我真的很新,不要对我的编码风格太苛刻)。我想要一些 "goodbye" 音频在我退出时播放(使用 NAudio 1.8.4 从 MPQ 文件中读取流)并且即使主 window 消失也不会被打断;出于这个原因,我在 class 中使用了一个名为 PlayerThread 的前台线程。

我使用 PlayerThread 构造函数播放声音

 foregroundChannel = new PlayerThread(soundStream, null, null);

不过我后面不追究了,就是靠PlayerThread玩完"naturally"结束

这是 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中的唯一线程。将第 3 行与第 5-6 行反转具有相同的结果,系统地失败 pt.Join();。这个PlayerThread是点击exit时创建的。


更新 2 这不是线程问题。这只是因为条件 internalPlayer.PlaybackState == PlaybackState.Playing 并不总是满足(使用断点检查),所以我们只是停留在 while 循环中。目前正在寻找更好的方法来检查播放结束。

听起来您需要同步您的线程,其中主线程应等待其他线程完成才能退出。看看 Thread.Join : https://msdn.microsoft.com/en-us/library/95hbf2ta(v=vs.110).aspx

WaveChannel32 构造函数创建一个零填充缓冲区,这对于您向混音器馈送的场景很有用。在这种情况下,它只是导致我的流 "never" 结束。

添加:

inputStream.PadWithZeroes = false;

完全解决了我的问题。在这种情况下不需要加入。

更多信息:

The Never-Ending Stream Problem

The way that each implementor of IWavePlayer determines whether it should automatically stop playback is when the Read method on the source IWaveProvider returns 0 (In fact Read should always return the count parameter unless the end of the stream has been reached).

However, there are some WaveStreams / IWaveProviders in NAudio that never stop returning audio. This isn’t a bug – it is quite normal behaviour for some scenarios. Perhaps BufferedWaveProvider is the best example – it will return a zero-filled buffer if there is not enough queued data for playback. This is useful for streaming from the network where data might not be arriving fast enough but you don’t want playback to stop. Similarly WaveChannel32 has a property called PadWithZeroes allowing you to turn this behaviour on or off, which can be useful for scenarios where you are feeding into a mixer.

From : http://mark-dot-net.blogspot.be/2011/05/naudio-and-playbackstopped-problem.html