aijingsun6 / NSpeex

NSpeex - Speex for .Net(http://nspeex.codeplex.com/)
26 stars 9 forks source link

Random decoded error #1

Open DavideC84 opened 4 years ago

DavideC84 commented 4 years ago

Hi, i'm trying to write here because i have an issue that have been stopping the dev of my app for weeks.

I'm writing a realtime voice chat application, with a centralized server (dedicated) architecture, using C# (dedicated server is a .net core app while for the client i'm using C# to script the game engine Unity3D).

For the encoding/decoding part i'm using NSpeex.

Basically, it works like this:

delivery. Each chunk is 554 bytes.

When i've got enough bytes to start decoding (554 bytes), the segment is taken and sent to the decoder.

Once it has been decoded, i take the resulting PCM samples and pass them to the playing buffer which sends them to the soundcard when i have enough data to start playing.


Now, it works GOOD! Most of the time...

but from time to time, out of the blue and totally random, the decoder (and only the decoder) throws an Exception like: "more than two sidebands found" or "invalid sideband mode" and

simply stops working, making my app unable to continue working.

From my understanding of the Speex library, this means that the decoder doesn't find the bits where it expect them to be... but WHY it happens only from time to time?!

I've seen it happen when i feed the encoder/decoder with segments of the wrong size but in this case i've debugged the hell out of it and i'm sure i'm passing always the same data amount.

..could this be a network related problem? I don't think so, i'm using reliable TCP and i'm sure every packet reachs the destination and in the correct order.

What could it be? How should i proceed to debug the problem further?

Thanks in advance, Davide

aijingsun6 commented 4 years ago

sorry to hear that. i searched the exception message whole of the code,but none of them has found.

i have not meet the situation for yet.

i suggest some methods to solve your problems.

  1. paste your exception stacks.
  2. do unit test with function encode and decode
  3. check your code ,maybe some parameters is wrong.

best regards.

DavideC84 commented 4 years ago

Hello! Thanks for your reply. Nothing to be sorry, thanks for your time and work.

You can find the exception messages i'm referring to in the file NbDecoder.cs

"Invalid sideband mode encountered"

I'm using NSpeex in Unity Engine so i can't make unit tests. I've already checked my code for weeks but i can't see anything wrong...

I do feed the decoder with many little segments per second and it does work flawlessy.. sometimes it decodes thousand and thousand audio segments and then something happens and boom. Exception is thrown. :)

Actually at the moment i had to switch to another encoder and solved the problem this way but if possible i would like to implement Speex because it's compression is very good.

I don't exclude something in my code can be wrong, but i need to know the exact reason for that exception so i can have a clue of the direction to look into the debugging stage.

Davide

aijingsun6 commented 4 years ago

hi, by your answer, i guess the wrong encoder you has used. the right way to use SpeexEncoder below.

SpeexEncoder(BandMode mode)

mode is decided by your samples per sec.

paste your code releted here please.

Riton2013 commented 2 years ago

I meet the same problem, when I mix up data before decode(data is still a byte[] and length doesn't change), It almost crash all the time. How can I do make it still running if I mix up data, it can sound noisy or even mute. We use speex in Android and iOS, thay wroks good in the same way. Looking forward your reply, thanks so mush!!

DavideC84 commented 2 years ago

Unfortunately i ended up using another encoder/decoder, since i was not able to avoid the random crashes with Speex.

Riton2013 commented 1 year ago

finally fixed the problem:

SpeexDecoder.cs

public int Decode(byte[] inData, int inOffset, int inCount, short[] outData, int outOffset, bool lostFrame) 
{

            if (decodedData.Length < outData.Length * 2)
            {
                // resize the decoded data buffer
                decodedData = new float[outData.Length * 2];
            }

            if (lostFrame || inData == null)
            {
                decoder.Decode(null, decodedData);
                for (int i = 0; i < frameSize; i++, outOffset++)
                {
                    outData[outOffset] = ConvertToShort(decodedData[i]);
                }
                return frameSize;
            }

            bits.ReadFrom(inData, inOffset, inCount);
            int samplesDecoded = 0;
            while (decoder.Decode(bits, decodedData) == 0)
            {
                for (int i = 0; i < frameSize; i++, outOffset++)
                {

                    outData[outOffset] = ConvertToShort(decodedData[i]);
                }
                samplesDecoded += frameSize;
            }

            return samplesDecoded;
 }

to

 public int Decode(byte[] inData, int inOffset, int inCount, short[] outData, int outOffset, bool lostFrame)
        {

                if (decodedData.Length < outData.Length * 2)
                {
                    // resize the decoded data buffer
                    decodedData = new float[outData.Length * 2];
                }

                if (lostFrame || inData == null)
                {
                    decoder.Decode(null, decodedData);
                    for (int i = 0; i < frameSize; i++, outOffset++)
                    {
                        outData[outOffset] = ConvertToShort(decodedData[i]);
                    }
                    return frameSize;
                }

                bits.ReadFrom(inData, inOffset, inCount);
                int samplesDecoded = 0;
                int result = decoder.Decode(bits, decodedData);
                if (result == 0)
                {
                    for (int i = 0; i < frameSize; i++, outOffset++)
                    {
                        outData[outOffset] = ConvertToShort(decodedData[i]);
                    }
                    samplesDecoded += frameSize;

                }

                return samplesDecoded;

        }

NbDecoder.cs

do
                {
                    if (bits.BitsRemaining() < 5)
                        return -1;

                    if (bits.Unpack(1) != 0)
                    { /*
                                                 * Skip wideband block (for
                                                 * compatibility)
                                                 */
                        // Wideband
                        /* Get the sub-mode that was used */
                        m = bits.Unpack(NSpeex.SbCodec.SB_SUBMODE_BITS);
                        int advance = NSpeex.SbCodec.SB_FRAME_SIZE[m];
                        if (advance < 0)
                        {
                            //throw new InvalidFormatException(
                            //      "Invalid sideband mode encountered (1st sideband): "
                            //              + m);
                             return -2;
                        }
                        advance -= (NSpeex.SbCodec.SB_SUBMODE_BITS + 1);
                        bits.Advance(advance);
                        if (bits.Unpack(1) != 0)
                        { /*
                                                     * Skip ultra-wideband block
                                                     * (for compatibility)
                                                     */
                            /* Get the sub-mode that was used */
                            m = bits.Unpack(NSpeex.SbCodec.SB_SUBMODE_BITS);
                            advance = NSpeex.SbCodec.SB_FRAME_SIZE[m];
                            if (advance < 0)
                            {
          //                      throw new InvalidFormatException(
                                        //"Invalid sideband mode encountered. (2nd sideband): "
                                        //      + m);
                                 return -2;
                            }
                            advance -= (NSpeex.SbCodec.SB_SUBMODE_BITS + 1);
                            bits.Advance(advance);
                            if (bits.Unpack(1) != 0)
                            { /* Sanity check */
          //                      throw new InvalidFormatException(
                                        //"More than two sideband layers found");
                                 return -2;
                            }
                        }
                        // */
                    }

                    if (bits.BitsRemaining() < 4)
                        return 1;

                    /* Get the sub-mode that was used */
                    m = bits.Unpack(NSpeex.NbCodec.NB_SUBMODE_BITS);
                    if (m == 15)
                    { /* We found a terminator */
                        return 1;
                    }
                    else if (m == 14)
                    { /* Speex in-band request */
                        inband.SpeexInbandRequest(bits);
                    }
                    else if (m == 13)
                    { /* User in-band request */
                        inband.UserInbandRequest(bits);
                    }
                    else if (m > 8)
                    { /* Invalid mode */
        //                throw new InvalidFormatException(
                                //"Invalid mode encountered: " + m);
                         return -2;
                    }
                } while (m > 8);
                submodeID = m;
            }

replace throw Exception to return -2

DavideC84 commented 1 year ago

Mate, you're a myth! Great work!