Audio stream for multiple outputs (single producer, multi-consumer)

805 views Asked by At

I am attempting to propagate a single sound source to multiple outputs (such as one microphone input to multiple sound cards or channels). The output does not have to be sync'd (a few ms delay is acceptable) but it would be nice if it could be sync'd.

I have successfully written code that loops a microphone input to an output using a WaveIn, a BufferedWaveProvider, and a WaveOut. However when I try to read one BufferedWaveProvider with two instances of WaveOut, the two outputs create this odd 'interleaved' choppy sound. Here is a code snippet for the output portion;

    private void CreateWaveOutDevice()
    {
        waveProvider = new BufferedWaveProvider(waveIn.WaveFormat);
        waveOut = new WaveOut();
        waveOut.DeviceNumber = 0;  //Sound card 1
        waveOut.DesiredLatency = 100;
        waveOut.Init(waveProvider);
        waveOut.PlaybackStopped += wavePlayer_PlaybackStopped;

        waveOut2 = new WaveOut();
        waveOut2.DeviceNumber = 1;  //Sound card 2
        waveOut2.DesiredLatency = 100;
        waveOut2.Init(waveProvider);
        waveOut2.PlaybackStopped += wavePlayer_PlaybackStopped;

        waveOut.Play();
        waveOut2.Play();
    }

I think the reason this is happening is because when the waveProvider circular buffer is read, the data is deleted so the two read methods are 'fighting' over the data which results in the choppy sound.

So I really have two questions; 1.) I see the Naudio library contains many types of waveStreams (RawSourceWaveStream is particularly interesting) However, I have been unable to find a good example of how to read a single stream with multiple waveOut methods. I have also been unable to create working code using waveStream with multiple outputs. Is anyone familiar with waveStreams and knows if this is something that can be done?

2.) If the Naudio wave streams cannot be used in a single producer multiple consumer situation then I believe I would need to make a circular buffer that is not cleared on a read, but only when the buffer is full and new data is pushed in. The code won't care if the data was read or not it just keeps filling the buffer. Would this be the correct approach?

I've spent days searching so hopefully this hasn't already been asked. Thanks for reading.

1

There are 1 answers

2
Mark Heath On BEST ANSWER

If you're just reading from a microphone and want two WaveOut's to play it, then the simple option is to create two BufferedWaveProviders, one for each WaveOut, and then when audio is received, send it to both.

Likewise if you were playing from an audio file to two soundcards, the easiest way is to use two reader objects and start them both separately.

There is unfortunately no easy way to synchronize, short of starting and stopping both players at the same time.

There are a few more advanced ways to try to split off an audio stream to two readers, but there can be complications especially if the two readers are not able to read at roughly the same rate.