[jitsi-dev] libjitsi Opus decoding problems


#1

Hello,

I'm using libjitsi's Opus class in a project. Both Opus.encode() and
Opus.decode() work perfectly with version 212 (before the outputOffset
parameter was added to these methods). However, I tried switching to a
later version (266) and changed my code to include the new outputOffset
(which I've simply set to zero) but I'm getting problems, Opus.decode() is
returning -1.

-Are there any tests for this class to be sure Opus is working and its not
just me making a mistake?

-Is there some way I can get more detailed error messages from Opus during
encode/decode? A general -1 error code without no console output tells me
very little.

I'm happy to post code snippets if that would help pinpoint the issue.

Ross


#2

Hello,

Hello,

I'm using libjitsi's Opus class in a project. Both Opus.encode() and
Opus.decode() work perfectly with version 212 (before the outputOffset
parameter was added to these methods). However, I tried switching to a
later version (266) and changed my code to include the new outputOffset
(which I've simply set to zero)

This should be just fine, it's what we currently do in our code.

but I'm getting problems, Opus.decode()
is returning -1.

-Are there any tests for this class to be sure Opus is working and its
not just me making a mistake?

There aren't any automated tests for this class.

-Is there some way I can get more detailed error messages from Opus
during encode/decode? A general -1 error code without no console output
tells me very little.

It isn't a general error code. It's an opus specific error code and it
just happens to be -1 in this case. It corresponds to OPUS_BAD_ARG. We
don't have all the opus error code constants copied in our Opus class,
but you can check them out in opus_defines.h [1].

I'm happy to post code snippets if that would help pinpoint the issue.

I don't have any guesses as to what might have happened at this point,
so I guess that might help.

Ross

Regards,
Boris

[1]
http://git.xiph.org/?p=opus.git;a=blob;f=include/opus_defines.h;h=3474e84c4342c3b8cf180863447724b839285d52;hb=ea95c533c8c3e8c6ec901fd6d34b8751e2c2243e

···

On 8/18/13 5:50 PM, Ross Rochford wrote:


#3

Here is the code. I've included some of the surrounding code that converts
from floats between -1.0 and 1.0 to little-endian 16 bit bytes, just in
case. This example fails at Opus.decode() when using libjitsi-266. But when
using libjitsi-212 and removing the outputOffset from the calls to
Opus.encode() and Opus.decode() (as in the commented-out lines) this works
without problems.

public class MainTest
{
    //compresses and decompresses a single 960-sample chunk of audio
    public static void main(String[] args)
    {
        int chunkSize = 960;
        int numChannels = 1;
        int decodeFEC = 0;
        long encoderId = Opus.encoder_create(48000, numChannels);
        float[] frame = createSineWave(chunkSize);

        ///////////compression//////////////////

        //convert float values into little-endian 16 bit numbers
        byte[] littleEndianSampleBytes = new byte[chunkSize*2*numChannels];
//opus wants little endian so we convert the floats to this first
        for(int i=0; i<chunkSize; i++)
        {
            short shortVal = (short)(frame[i]*32767.0);
            littleEndianSampleBytes[(i*2)] = (byte)shortVal;
            littleEndianSampleBytes[(i*2)+1] = (byte)(shortVal >> 8);
        }

        byte[] compressedSampleBytes = new byte[Opus.MAX_PACKET];

        //int resLen = Opus.encode(encoderId, littleEndianSampleBytes, 0,
frame_size, compressedSampleBytes, compressedSampleBytes.length);
        int resLen = Opus.encode(encoderId, littleEndianSampleBytes, 0,
chunkSize, compressedSampleBytes, 0, compressedSampleBytes.length);

        //copy to new, shorter byte array
        byte[] compressedBytes = new byte[resLen];
        System.arraycopy(compressedSampleBytes, 0, compressedBytes, 0,
resLen); //this could be avoided by having the length of the sub-array
returned as well, we would need a class 'ByteArray' that contains a length
field.

        ///////////decompression//////////////////

        long decoderId = Opus.decoder_create(48000, numChannels);

        byte[] decompressedFrameBytes = new byte[chunkSize*2*numChannels];
// 2 bytes per sample

        //int numSampsDecompressed = Opus.decode(decoderId, payloadBytes,
0, payloadBytes.length, decompressedFrameBytes,
decompressedFrameBytes.length, decodeFEC);
        int numSampsDecompressed = Opus.decode(decoderId,
compressedSampleBytes, 0, compressedSampleBytes.length,
decompressedFrameBytes, 0, decompressedFrameBytes.length, decodeFEC);

        //convert little endian 16 bit numbers back into floats
        float[][] sampleFloats = new float[numChannels][chunkSize];
        short[][] outShorts = new short[numChannels][chunkSize];
        for(int k=0; k<chunkSize; k++)
        {
            outShorts[0][k] = (short) (
((((short)decompressedFrameBytes[(k*2)+1])<<8)) |
(decompressedFrameBytes[(k*2)] & 0xFF) );
            sampleFloats[0][k] = (float)(outShorts[0][k]/32767.0);
        }

        System.out.println("finished");
    }

    public static float[] createSineWave(int length)
    {
        float[] sines = new float[length];
        for (int i = 0; i < length; i++)
        {
            double radians = (Math.PI/200) * i;
            sines[i] = (float) Math.sin(radians);
        }

         return sines;
    }
}

···

On Mon, Aug 19, 2013 at 8:30 AM, Boris Grozev <boris@jitsi.org> wrote:

Hello,

On 8/18/13 5:50 PM, Ross Rochford wrote:
> Hello,
>
> I'm using libjitsi's Opus class in a project. Both Opus.encode() and
> Opus.decode() work perfectly with version 212 (before the outputOffset
> parameter was added to these methods). However, I tried switching to a
> later version (266) and changed my code to include the new outputOffset
> (which I've simply set to zero)

This should be just fine, it's what we currently do in our code.

> but I'm getting problems, Opus.decode()
> is returning -1.
>
>
> -Are there any tests for this class to be sure Opus is working and its
> not just me making a mistake?

There aren't any automated tests for this class.

>
> -Is there some way I can get more detailed error messages from Opus
> during encode/decode? A general -1 error code without no console output
> tells me very little.

It isn't a general error code. It's an opus specific error code and it
just happens to be -1 in this case. It corresponds to OPUS_BAD_ARG. We
don't have all the opus error code constants copied in our Opus class,
but you can check them out in opus_defines.h [1].

>
>
> I'm happy to post code snippets if that would help pinpoint the issue.

I don't have any guesses as to what might have happened at this point,
so I guess that might help.

>
>
> Ross

Regards,
Boris

[1]

http://git.xiph.org/?p=opus.git;a=blob;f=include/opus_defines.h;h=3474e84c4342c3b8cf180863447724b839285d52;hb=ea95c533c8c3e8c6ec901fd6d34b8751e2c2243e


#4

Weird. This code runs fine here with 266 (tested with the mac and src
packages on mac) and latest git (which should be the same). Which
package are you using?

Regards,
Boris

···

On 8/20/13 2:09 AM, Ross Rochford wrote:

Here is the code. I've included some of the surrounding code that
converts from floats between -1.0 and 1.0 to little-endian 16 bit bytes,
just in case. This example fails at Opus.decode() when using
libjitsi-266.


#5

I'm using 212 and 266 on a mac (Mac OS 10.8, x86_64).

···

On Tue, Aug 20, 2013 at 3:17 AM, Boris Grozev <boris@jitsi.org> wrote:

On 8/20/13 2:09 AM, Ross Rochford wrote:
> Here is the code. I've included some of the surrounding code that
> converts from floats between -1.0 and 1.0 to little-endian 16 bit bytes,
> just in case. This example fails at Opus.decode() when using
> libjitsi-266.

Weird. This code runs fine here with 266 (tested with the mac and src
packages on mac) and latest git (which should be the same). Which
package are you using?

Regards,
Boris