zephyrproject-rtos / liblc3codec

LC3 codec implementation
63 stars 37 forks source link

Encoding high volume low sample rate provides invalid LC3 frames #9

Open Casper-Bonde-Bose opened 2 years ago

Casper-Bonde-Bose commented 2 years ago

When encoding a 400Hz sinewave at 16kHz sample rate it was observed that the codec was clipping the sine, hence volume reduced by 10% as this removed the clipping. But even with this reduction other codecs will discard the data due to invalid content in the frame.

A capture was shared with Ellisys for analysis, and their response were:

In the very first SDU of that trace, the first 40 bytes can be properly decoded with the given parameters, namely a 10ms frame duration and 16kHz sampling frequency. For the second part, the decoder detects an impossible value in the side band information. The number of spectral lines for this configuration is 160 (in this case identical to the number of samples per frame). That maps to a compressed "last non zeroed index" field length of 7 bits. Those 7 bits have the compressed value 97, that expands to 196. Since the "last non zeroed index" cannot be higher than the number of spectral lines, that sideband information is considered invalid and the frame not accepted. To avoid false positives, the LC3 auto-detection requires all frames in an SDU to be decodable, which is thus not the case in this trace

The trace was using the current default settings in the unicast sample application. 32kbps, 16kHz, 10ms frames, volume: (INT16_MAX - 3000), 400Hz sine.

A volume of ~75% works around this issue (INT32_MAX - 8000). Also at 48kHz the issue do not seem to exist - even at full volume (+/-INT16_MAX).

UPDATE 2. of May 2022: PLEASE NOTE: When looking at this, please note that the issue occurs for HIGH volume. Above a certain gain level the LC3 encoder will start to produce invalid frames. Also please note that the nature of LC3 will introduce a "ramp-up" period where the output amplitude is not 100% even though you supply a 100% gain input signal. Hence please ensure you skip the first few frames for the analysis. Also please note that several different combinations of frames/SDU were tested, and the issue disappears if gain is reduced - hence this issue is not related to how data is packed in to the SDU.

cptnpopcorn commented 2 years ago

Hi Casper, just to put this into perspective, in your setup with two frames packed into a single SDU, all the first frames were decodable but not the second one. How high do you estimate the probability that the codec introduces errors in exactly every 2nd frame ? It is not completely excluded, but frankly, I would first take a look into your SDU payload composition code, before blaming the codec ;)

pschatzmann commented 2 years ago

I also tried with a 400Hz sinewave at 16kHz on an ESP32 and I don't see any clipping as well: Screen Shot 2022-04-30 at 18 55 11 :

Casper-Bonde-Bose commented 2 years ago

Hi Casper, just to put this into perspective, in your setup with two frames packed into a single SDU, all the first frames were decodable but not the second one. How high do you estimate the probability that the codec introduces errors in exactly every 2nd frame ? It is not completely excluded, but frankly, I would first take a look into your SDU payload composition code, before blaming the codec ;)

@cptnpopcorn Try putting only one frame in each and you will see the same. Alternatively just reduce the gain to 50% and you will be able to decode. Also if you run both sides of the sample application you will have no problem decoding the data. I believe the reason you are able to decode the first frame is that LC3 have a "fade-in" period where it does not provide full amplitude even though you provide it. I did not look into the details but my guess is that this is due to the look-ahead buffer being empty for the first frame. To make it more severe try using 100% gain.

Casper-Bonde-Bose commented 2 years ago

I also tried with a 400Hz sinewave at 16kHz on an ESP32 and I don't see any clipping as well: Screen Shot 2022-04-30 at 18 55 11 :

@pschatzmann But the bug reports an issue when you use full amplitude - and the image shows you are not using full amplitude. Try to set the gain to 100% and decode the second or third frame(after the "ramp-up" period) - then you will see the clipping - also try to decode with another codec or capture it with a sniffer for decode - if the codec have sanity-checks on the values in the encoded data it will fail decoding altogether.

asoulier commented 2 years ago

Hi,

About clipping, it's a known artifact of the "Long-Term Post Filter" (LTPF), that adds gain on pure sine signals. It's a specificity of this parametric tools. The gain will be less with higher sinus frequency, and will be maximum around 1 dB (volume under 90% will be OK).

image

Note that this tool is only enabled at low bitrate. You will see those artifacts for any samplerates, that enables this tools. For testing purpose you can easy disable this tool at encoder side. In analyse() function of the lc3.c file, you can call unconditionally lc3_ltpf_disable() :

//    if (nn_flag)
        lc3_ltpf_disable(&side->ltpf);

(There is also artifacts when high energy is detected near nyquist frequency).

But in any case, this should not bring you invalid bitstream. @Casper-Bonde-Bose If you can share the inputs and outputs of the encoder, I'll be happy to have a look.

The root repository has landed on github (https://github.com/google/liblc3). It will be easier for me to post issues here ;)

Thanks.