【问题标题】:parallel operations with audio stream c#与音频流 c# 的并行操作
【发布时间】:2015-07-15 21:56:29
【问题描述】:

我在 c#(wpf) 中录制声音,当声卡中的数据可用时,它会调用此事件:

void myWaveIn_DataAvailable(object sender, WaveInEventArgs e)
    {
        for (int index = 0; index < e.BytesRecorded; index += 2)//Here I convert in a loop the stream into floating number samples
        {

            short sample = (short)((e.Buffer[index + 1] << 8) |
                                    e.Buffer[index + 0]); 
            samples32Queue.Enqueue(sample/32768f);
        }
        //***Do some Processing with data inside Queue
    }

如您所见,我将每个样本从记录的缓冲区推送到声明如下的队列:

Queue<float> samples32Queue = new Queue<float>();

正如您在for loop 之后的事件内部看到的那样,我想对队列进行一些处理。我担心在处理数据时,新的样本会来自声卡,我的处理会丢失。

  1. 正确的方法是什么?
  2. 我从事件中调用的处理是静态方法/非静态的吗?

【问题讨论】:

  • 它是 RT 系统吗?如果没有,您可以缓冲样本并稍后处理它们。如果是,那么您别无选择 - 您必须确保您的处理功能比传入的样本“更快”。
  • 你好,我试着让它RT
  • 每个样本的处理必须在新样本到达之前结束吗?或者可以建模为生产者-消费者设计?
  • 没有。我可以稍后继续处理它
  • 在这种情况下,考虑使用 BlockingCollection 而不是 Queue - msdn.microsoft.com/en-us/library/dd997371(v=vs.110).aspx

标签: c# wpf multithreading parallel-processing audio-streaming


【解决方案1】:

鉴于您可以缓冲样本并稍后处理它们,请考虑使用 BlockingCollection。 BlockingCollection 是生产者-消费者模式的绝佳解决方案,据我了解,这是您的情况。一方面,您有 myWaveIn_DataAvailable() 方法作为生产者将样本添加到集合中,而在另一端,您有另一个消费线程(但不一定是另一个线程)收集样本并处理它们。有多种方法可以实现消费者,它们在 MSDN 中有很好的记录。

编辑: 看下面的例子,我没有测试它,但它应该给你一个起点:

class ProducerConsumerExample
{
    BlockingCollection<float> samples32Collection;
    Thread consumer;
    public ProducerConsumerExample()
    {
        samples32Collection = new BlockingCollection<float>();
        consumer = new Thread(() => LaunchConsumer());
        consumer.Start();   //you don't have to luanch the consumer here...
    }
    void Terminate()    //Call this to terminate the consumer
    {
        consumer.Abort();
    }
    void myWaveIn_DataAvailable(object sender, WaveInEventArgs e)
    {
        for (int index = 0; index < e.BytesRecorded; index += 2)//Here I convert in a loop the stream into floating number samples
        {

            short sample = (short)((e.Buffer[index + 1] << 8) |
                                    e.Buffer[index + 0]);
            samples32Collection.Add(sample / 32768f);
        }
    }

    void LaunchConsumer()
    {
        while (true /* insert your abort condition here*/)
        {
            try
            {
                var sample = samples32Collection.Take();   //this thread will wait here until the producer add new item(s) to the collection
                Process(sample);    //in the meanwhile, more samples could be added to the collection 
                                    //but they will not be processed until this thread is done with Process(sample)
            }
            catch (InvalidOperationException) { }
        }
    }
}

【讨论】:

  • 您好,在您之前提供的 msdn 链接中,有一个 Tasks 示例。如果我的制作人是一个事件,我怎样才能让它像一个任务?我的消费者应该是什么样子?很抱歉打扰您,我对 c# 和并行编程很陌生...
猜你喜欢
  • 1970-01-01
  • 2011-06-08
  • 2022-10-18
  • 1970-01-01
  • 1970-01-01
  • 2023-03-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多