Как бы я использовал NAudio для сжатия входящих данных PCM с микрофона? - PullRequest
1 голос
/ 13 мая 2019

Я работаю над приложением VOIP, которое будет передавать аудиоданные по сети с помощью NAudio. Я не хочу передавать потоковое сырье PCM из-за проблем с пропускной способностью, поэтому я пытаюсь кодировать сэмплы в µ-законе. До сих пор я не смог найти никаких объяснений того, как именно это делается. Я предполагаю, что должен использовать NAudio.Codecs.MuLawEncoder.LinearToMuLawSample(short s), но проблема в том, что мне дан байтовый массив в событии DataAvailable.

Я пробовал перебирать буфер DataAvailable, вызывая LinearToMuLawSample для каждого байта. Тем не менее, фактический размер массива, очевидно, не меняется, и поэтому я не получаю никакого уменьшения размера.

Вот код, отвечающий за кодировку:

byte[] sample = _rawSamples.Take(); //take from sample buffer

for (int i = 0; i < sample.Length; i++) //actual conversion code
    sample[i] = MuLawEncoder.LinearToMuLawSample(sample[i]);

_encodedSamples.Add(sample); //add to network buffer

Вот содержимое моего обработчика DataAvailable:

private void _input_DataAvailable(object sender, WaveInEventArgs e)
{
    byte[] buffer = e.Buffer;
    Array.Resize(ref buffer, e.BytesRecorded);

    _rawSamples.Add(audioData);
}

И, наконец, вот как я объявляю свой WaveIn:

_input = new WaveIn();
_input.BufferMilliseconds = 100;
_input.DataAvailable += _input_DataAvailable;
_input.RecordingStopped += _input_InputRecordingStopped;

По сути, я ищу способ взять данные PCM в виде байтового массива и преобразовать их в формат, подходящий для отправки по сети. Я не совсем понимаю, как класс MuLawEncoder может на самом деле кодировать / сжимать аудиоданные таким образом.

1 Ответ

0 голосов
/ 21 мая 2019

Обновление

Я смог заставить его работать, используя примеры на https://github.com/naudio/NAudio/blob/master/NAudioDemo/NetworkChatDemo/. Вот ключевые функции, которые я использовал в итоге:

private byte[] EncodeSamples(byte[] data)
{
    byte[] encoded = new byte[data.Length / 2];
    int outIndex = 0;

    for (int n = 0; n < data.Length; n += 2)
        encoded[outIndex++] = MuLawEncoder.LinearToMuLawSample(BitConverter.ToInt16(data, n));

    return encoded;
}

private byte[] DecodeSamples(byte[] data)
{
    byte[] decoded = new byte[data.Length * 2];
    int outIndex = 0;
    for (int n = 0; n < data.Length; n++)
    {
        short decodedSample = MuLawDecoder.MuLawToLinearSample(data[n]);
        decoded[outIndex++] = (byte)(decodedSample & 0xFF);
        decoded[outIndex++] = (byte)(decodedSample >> 8);
    }
    return decoded;
}

Ключ шагал по данным по два байта за раз, преобразовывал каждую пару в Int16, передавал ее в LinearToMuLawSample и упаковывал возвращаемые значения в новый массив, равный половине размера.

...