我正在开发一个使用waveOut...中的winmm.dll API连续播放音频的应用程序。该应用程序使用“越级”缓冲区,它们基本上是一堆样本数组,您可以将它们转储到音频队列中。 Windows将按顺序无缝地播放它们,并且在每个缓冲区完成后,Windows会调用回调函数。在此函数中,我将下一组样本加载到缓冲区中,然后对其进行处理,然后将缓冲区转储回音频队列。这样,音频将无限期播放。

出于动画目的,我正在尝试将waveOutGetPosition合并到应用程序中(因为“缓冲已完成”回调足够不规则,以致于会导致生涩的动画)。 waveOutGetPosition返回当前的播放位置,因此非常精确。

问题在于,在我的应用程序中,对waveOutGetPosition的调用最终会导致应用程序锁定-声音停止并且调用永不返回。我将事情归结为一个简单的应用程序来演示问题。您可以在此处运行该应用程序:

http://www.musigenesis.com/SO/waveOut%20demo.exe

如果您只是一遍又一遍地听到一小段钢琴的声音,那就可以了。这只是为了演示问题。这个项目的源代码在这里(所有内容都在LeapFrogPlayer.cs中):

http://www.musigenesis.com/SO/WaveOutDemo.zip

第一个按钮以跳过模式运行应用程序,而无需调用waveOutGetPosition。如果单击此按钮,则该应用程序将一直播放而不会中断(X按钮将其关闭并关闭)。第二个按钮启动跳越器,还启动一个表单计时器,该计时器调用waveOutGetPosition并显示当前位置。单击此按钮,该应用程序将运行一小段时间,然后将其锁定。在我的笔记本电脑上,它通常会在15-30秒内锁定;最多只花了一分钟。

我不知道如何解决此问题,因此我们将非常欢迎您提供任何帮助或建议。我发现有关此问题的帖子很少,但似乎存在潜在的死锁,可能是由于多次调用waveOutGetPosition或同时发生的对此waveOutWrite的调用。我可能经常调用此命令,以致系统无法处理。

编辑:忘记了,我正在Windows Vista上运行它。在其他操作系统上可能根本不会发生这种情况。

编辑2 :除以下(未答复)帖子外,我几乎没有在线找到有关此问题的信息:

http://social.msdn.microsoft.com/Forums/en-US/windowsgeneraldevelopmentissues/thread/c6a1e80e-4a18-47e7-af11-56a89f638ad7

编辑3 :好吧,我现在可以随意重现此问题。如果我在waveOutGetPosition之后(在下面的代码行中)立即调用waveOutWrite,则应用程序每次都会挂起。它也以一种特别糟糕的方式挂起-似乎将我的整个操作系统锁定了一段时间,而不仅仅是应用程序本身。因此,如果waveOutGetPosition死锁与waveOutWrite几乎在同一时间发生,而不仅仅是在字面上同时出现,那么它似乎会死锁,这可能解释了为什么锁对我不起作用。 Yeesh。

最佳答案

它在mmsys API代码内部陷入僵局。当主线程忙于执行waveOutWrite()时,在回调死锁中调用waveOutGetPosition()。它是可修复的,您将需要一个锁,以便这两个函数不能同时执行。将此字段添加到LeapFrogPlayer:

    private object mLocker = new object();

并在GetElapsedMilliseconds()中使用它:
        if (!noAPIcall)
        {
          lock (mLocker) {
            ret = WaveOutX.waveOutGetPosition(_hWaveOut, ref _timestruct,
                _timestructsize);
          }
        }

和HandleWaveCallback():
        // play the next buffer
        lock (mLocker) {
          int ret = WaveOutX.waveOutWrite(_hWaveOut, ref _header[_currentBuffer],
              Marshal.SizeOf(_header[_currentBuffer]));
          if (ret != WaveOutX.MMSYSERR_NOERROR) {
            throw new Exception("error writing audio");
          }
        }

这可能会有副作用,尽管我没有注意到。看看NAudio project.

下次创建项目的可上传.zip时,请使用Build + Clean。

关于c# - waveOutWrite和waveOutGetPosition死锁的问题,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/2452345/

10-09 06:41