This project is read-only.

Trouble converting WaveIn Ethernet SoundServer to WASAPI

May 13, 2015 at 5:01 PM
I have a working Wavein CSCore ethernet sound server application that I haven't been able to successfully convert to WASAPI. When I use WASAPI, the data received at the other end of the ethernet connection is just loud and unintelligible noise, instead of understandable speech. With the wavein app, all is OK. The code for each is below.

I know that my problem is that I don't understand the CSCore classes and methods, but I have spent a couple of days and read everything I could find on the internet and still am failing.

Any help is appreciated!

``` The pertinent portion of the working Wavein code is:
        waveinformat = new WaveFormatExtensible(48000,16,1,AudioSubTypes.Pcm);
        mic_in = new CSCore.SoundIn.WaveIn();
        mic_in.BufferSizeMs = 200;
        mic_in.WaveFormat = waveinformat;
        mic_in.Initialize();
        mic_in.DataAvailable += mic_in_DataAvailable;

        public byte[] mic_data_bytes;
public void mic_in_DataAvailable(object sender, CSCore.SoundIn.DataAvailableEventArgs e)
    {
        mic_data_bytes = e.Data;
        if (Globals.sendMic)
        {
            mic_data_queue.Enqueue(mic_data_bytes);
            mic_counter++;
        }
    }
The pertinent portion of Version 1 of the non-working WasapiCapture code is:
         public CSCore.SoundIn.WasapiCapture mic_in;
.....
        mic_in = new CSCore.SoundIn.WasapiCapture();
        mic_in.Initialize();
        var micSource = new SoundInSource(mic_in);
        micSource.ChangeSampleRate(48000);
        micSource.DataAvailable += micSource_DataAvailable;
.....
    public void micSource_DataAvailable(object sender, CSCore.SoundIn.DataAvailableEventArgs e)
    {
        mic_data_bytes = e.Data;
        if(Globals.sendMic)
        {
            mic_data_queue.Enqueue(mic_data_bytes);
            mic_counter++;
        }
    }
Version 2 of the non-working Wasapi code is:
    public CSCore.SoundIn.WasapiCapture mic_in;  // WasAPI
        mic_in = new CSCore.SoundIn.WasapiCapture();
        mic_in.Initialize();
        mic_in.DataAvailable += mic_in_DataAvailable;
.....
    public void mic_in_DataAvailable(object sender, CSCore.SoundIn.DataAvailableEventArgs e)
    {
        mic_data_bytes = e.Data;
        if(Globals.sendMic)
        {
            mic_data_queue.Enqueue(mic_data_bytes);
            mic_counter++;
        }
    }
Thanks Again!
May 13, 2015 at 7:50 PM
How do you play the recorded data? Make sure to transmit the data without any loss and pass the format of the recorded audio data to the playback.
May 14, 2015 at 12:48 AM
Edited May 15, 2015 at 2:43 AM
Thanks for the response!

The data is coming from a microphone windows audio device [the default Recording audio device for my windows installation]. As I noted, it is running at 48000 Hz 16 bit sampling rate.

The data is not played at the other end of the ethernet connection. This is all part of a software defined radio server and client that I have been coding [and using]. The audio signal bytes are extracted from the data after it has been received at the other end of the udp connection, and this data is used to modulate the RF output of a software defined radio.

My application works perfectly using the CSCore WaveIn method to provide the audio data source. I want to be able to substitute a few lines of wasapiCapture code for the WaveIn code, because WaveIn has been deprecated. Using WaveIn, I am having no problems with data transmission across the ethernet, and the WaveIn data is being received perfectly with no dropouts or glitches, and it modulates the RF output exactly as desired. So it is not because of a failure of WaveIn that I want to make the change.

I just need to get the bytes produced by the WasapiCapture code to my udpserver so that they appear exactly the same as the bytes produced by the WaveIn code. Everything else is already taken care of and working.

Thanks again!
May 14, 2015 at 9:17 AM
Is there a particular reason why it has to be 48kHz, 16 bit pcm?
You would have to convert data recorded by Wasapi before sending it. But that will cost performance.
May 14, 2015 at 9:37 AM
Edited May 15, 2015 at 2:47 AM
Thanks for your answer! That need for conversion IS the problem, isn't it? :)

Yes. The structure of the data is defined by the output of an FPGA-based software defined radio. I am replacing the FPGA-created digital audio output with computer generated audio so that the radio can be used from a remote location. There are several hundred units [or perhaps the number of units in the field is in 1000 range; I am not sure]. In any event, it would not be practical to change the FPGA data format due to the number of pre-existing hardware units at remote locations around the world. The software I am writing must be "backwards compatible" with the pre-existing FPGA_based hardware. The interface between my code and the hardware is encapsulated in 3 lines of code:
                                Form1.lg_mic_buffer.TryDequeue(out Sample1);
                                Form1.lg_mic_buffer.TryDequeue(out Sample2);
                                Sample = (float)(MicAGC * GainConstant * (double)(short)((Sample1) | (Sample2 << 8)));
In the future, I can certainly speed internet transfer by using a codec to compress the data at one end and then decompress and reconvert/decompress the data at the other end, but right now I am just trying to understand how to convert the wasapi data to the specific format used in the project. Having that level of understanding is essential for me to proceed further.

Thanks again! CSCore is a great and incredibly useful and well-constructed project. I have just not been smart enough to get it to do what I need in this case.
May 14, 2015 at 1:24 PM
So try to specify the defaultFormat. It will try to use that format, but there is no guarantee that WasapiCapture will use that format.
So you will have to do some conversation yourself.
Just as a little hint:
        private static IWaveSource micSource;
        private static WasapiCapture mic_in;

        static void Foo()
        {
            mic_in = new WasapiCapture();
            mic_in.Initialize();

            var soundInSource = new SoundInSource(mic_in);
            micSource = soundInSource
                .ChangeSampleRate(48000)
                .ToSampleSource()
                .ToStereo()
                .ToWaveSource(16); //16 bits

            byte[] buffer = new byte[micSource.WaveFormat.BytesPerSecond];
            soundInSource.DataAvailable += (s, e) =>
            {
                int read;
                while ((read = micSource.Read(buffer, 0, buffer.Length)) > 0)
                {
                    ProcessData(buffer, read);
                }
            };
        }

        static void ProcessData(byte[] data, int count)
        {
            if(Globals.sendMic)
                ...
        }
Marked as answer by filoe on 5/15/2015 at 5:14 AM
May 14, 2015 at 9:57 PM
Thanks!

This is exactly what I needed!

I very much appreciate the help and this should set me on the right track :-)

Thanks again for all the great work that you do :-)

May 15, 2015 at 1:14 PM
Glad I could help you :).