Matan
Matan

Reputation: 456

Converting WAV Stream to Opus using NAudio

I am using .Net's SpeechSynthesizer to generate WAV stream from a string. I then need to convert that stream from WaveStream to Opus.

I am using the following libraries:

I am synthesizing the speech using this function:

public static Stream Speak(string text)
{
    SpeechSynthesizer s = new SpeechSynthesizer();
    MemoryStream stream = new MemoryStream();
    s.SetOutputToWaveStream(stream);
    s.Speak(text);
    s.SetOutputToNull();
    return stream;
}

And in order to make the conversion I am using the following function:

public static Stream SpeakOgg(string text)
{
    MemoryStream orgstream = Speak(text) as MemoryStream;
    orgstream.Seek(0, SeekOrigin.Begin);

    WaveFileReader reader = new WaveFileReader(orgstream);

    WaveFormat newFormat = new WaveFormat(16000, reader.WaveFormat.Channels);
    WaveFormatConversionStream newStream = new WaveFormatConversionStream(newFormat, reader);
    WaveStream conv = WaveFormatConversionStream.CreatePcmStream(newStream);

    byte[] bytes = new byte[conv.Length];
    conv.Position = 0;
    conv.Read(bytes, 0, (int)conv.Length);

    OpusEncoder encoder = OpusEncoder.Create(newStream.WaveFormat.SampleRate, newStream.WaveFormat.Channels, Opus.Application.Voip);
    int encodedLength = 0;
    byte[] encoded = encoder.Encode(bytes, (int)conv.Length, out encodedLength);

    MemoryStream finish = new MemoryStream();
    finish.Write(encoded, 0, encodedLength);

    return finish;
}

My problem is that the OpusEncoder throws an exception saying:

Encoding failed - BadArg

and it is thrown on the function call to "opus_encode". Can anyone help me track the problem?

Edit 1:

After looking around I found that the exception thrown is actually a define in Opus' API called: "OPUS_BAD_ARG", on which the documentation states:

One or more invalid/out of range arguments.

I still can't find the argument that is wrong...

Upvotes: 2

Views: 3968

Answers (1)

Logan S.
Logan S.

Reputation: 305

It's most likely the input length. 1. Remember that the input length is a count of 16-bit samples per channel, where your code just passes the number of bytes. Divide by (2 * numChannels) 2. The input length must be a valid Opus frame size (2.5, 5, 10, 20, 60ms, 20 is the default). So you need to pass a fixed number of samples over and over for the length of your input. In the case of 16khz mono that framesize is 320.

Upvotes: 3

Related Questions