线程之间的线程通信

时间:2013-02-28 02:32:53

标签: c# .net naudio multithreading

所以我有一个参数化的线程启动,启动一些NAudio的东西...但我需要一个单独的线程告诉NAudio线程启动。当我尝试它时,它会崩溃。如何实现安全的跨线程通信?

这是线程(此类成为主线程中的音频对象):

class Audio
{
    public IWavePlayer OutDevice;
    public WaveStream OutStream;

    public Thread thread;

    public Audio(string file)
    {
        this.thread = new Thread(new ParameterizedThreadStart(InitAudio)); thread.Start(file);
    }

    private void InitAudio(object data) {

        this.OutDevice = new WaveOut();
        this.OutStream = new WaveChannel32(new Mp3FileReader(data.ToString()));
        this.OutDevice.Init(OutStream);
    }
}

我需要能够让我的主线程调用audio.OutDevice.Play();但我不能因为它是跨线程而且崩溃了。我该怎么做?

2 个答案:

答案 0 :(得分:0)

您的音频播放使用的是硬件资源,而且通常情况下,必须在创建它们的同一个线程上访问这些资源。在您的代码中,您没有留下继续访问该线程的空间。我很惊讶你有任何代码的声音,因为你的拥有线程将很快超出范围。这只是因为你有那些与班级相关的变量发生了什么。我个人认为在这种情况下你不需要一个单独的线程,因为我认为回放是或可以是非阻塞的。尽管如此,你可以按照你的计划(伪代码):

public bool ShouldPlay;
private void InitAudio(object data) {

        var OutDevice = new WaveOut();
        var OutStream = new WaveChannel32(new Mp3FileReader(data.ToString()));
        var OutDevice.Init(OutStream);

        while(!_exitEvent.WaitOne(50ms)){
                 if(ShouldPlay && !OutDevice.IsPlaying)
                        OutDevice.Play();
                 else if(!ShouldPlay && OutDevice.IsPlaying)
                        OutDevice.Stop();
            }
          OutDevice.Stop();
          OutDevice.Dispose();
          OutStream.Dispose();
    }

答案 1 :(得分:0)

如果要在后台线程上填充音频缓冲区,我建议使用WaveOutEvent类。这将创建自己的后台线程,用于通过管道拉动音频。然后,您可以从主线程调用Play和Stop。在这种情况下需要注意的主要线程问题是,如果需要在正在播放的文件中实现重新定位,因为重新定位将在GUI线程上发生,而Read可能正在另一个上进行。

对于WinForms / WPF应用程序,最可靠的机制是使用WaveOut的Windows消息回调(如果在GUI线程上创建WaveOut,默认情况下会得到这个)。这样可以避免担心要重新定位的线程。此外,通过使用GUI线程实现一切,它可以避免潜在的MTA与STA线程问题,如果您使用基于COM的API(如Windows Media API,MediaFoundation或DirectX Media Object重采样器),您将获得这些问题。