Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Forward error correction flag in decode (decode_fec flag) #17

Closed
stop-start opened this issue Mar 13, 2018 · 9 comments
Closed

Forward error correction flag in decode (decode_fec flag) #17

stop-start opened this issue Mar 13, 2018 · 9 comments

Comments

@stop-start
Copy link

Currently, when decoding, the decode_fec flag is set to 0 in the decode function, meaning that there is no error correction in case of lost packets.
We need to be able to set it to 1.

In order to not break anything I thought either add a "DecodeWithFEC" which would be identical to "Decode" but with the flag set to 1 (same for DecodeFloat32), or having the flag on by default.

@hraban
Copy link
Owner

hraban commented Mar 13, 2018

Hi elinor, thanks for opening the discussion before submitting a patch :) ! and for your interest in contributing.

I've had a good look at this flag and how it should work, and tbh: I'm not completely clear on how it should be used, even in the original C API. Do you know what the point is, exactly? As far as I understand it: if you have lost a packet, and your incoming packet contains error correcting data (i.e. FEC enabled on the encoder, with appropriate assumed packet loss), it can be used to restore (an approximation?) of the lost packet. So, say your encoder sends packets: A, B, C, D. You only receive A, C, D. You call the decoder:

decode(A, pcm, decode_fec=false)
decode(C, pcm, decode_fec=true) // pcm must have the exact frame size of the missed data
decode(C, pcm, decode_fec=false)
decode(D, pcm, decode_fec=false)

Do you know if this is exactly how it's supposed to be used?

@stop-start
Copy link
Author

Hi hraban,

As a disclaimer I'm not expert and haven't used this feature yet.
But yes, basically that's what it should do and how it should do it. From the documentation if the next packet doesn't contain the info needed then missing packet will simply be considered lost.
In my previous post I was mistaken when I suggested to let the flag set to 1. It should be set on the frame following the the missing one.

On a related matter, in the c api, there's an option to send a NULL pointer for "data" in order to indicate a lost packet. Here, the decode function will just return the error "opus: no data supplied".

@hraban
Copy link
Owner

hraban commented Mar 13, 2018

yeah, the opus source code is basically the only reliable source of info I was able to find on this. it seems buffer = null invokes PLC: packet loss correction (?) , filling the pcm with "silence" of some sorts (is it just 000? or something smarter, based on the bordering wave functions?) and advancing the state of the decoder appropriately. I agree on the empty buffer thing, and while I don't like overloading method semantics, especially not using 'nil', I'm weary to add two whole more methods just for PLC. Especially considering how hybrid it is with FEC (if FEC data cannot fill an entire buffer, the first part of the pcm is filled with PLC, the rest with FEC).

All in all, I think we should probably add two methods:

(d *Decoder) DecodeFEC(next []byte, pcm []int16) error
(d *Decoder) DecodeFECFloat32(next []byte, pcm []float32) error

No need to return int if I understand it correctly, because this will always fill up the pcm buffer exactly, no?

Either which way, this will need some rigurous testing. Maybe full, value based testing can't be added to the test suite (signal -> opus -> signal is hard to test, opus being lossy and all), but we should at least pipe it to excel and see if the error decoded signal makes sense. I'll open another issue for allowing nil buffers, although I'm curious what the actual effect is on the decoded signal of supplying a null buffer.

What do you think?

@stop-start
Copy link
Author

From what I read, their doc doesn't mention how their PLC implementation works. I think PLC stands for packet loss concealment (thanks wikipedia: https://en.wikipedia.org/wiki/Packet_loss_concealment)

I agree regarding the two methods and I think you're right about the fact that will fill up the pcm buffer, at least that's what I'm hoping for since my goal with this is to keep the length of the audio as close as possible to the original.

If you're ok with it, I would like to submit a PR in the coming days but I'm not sure I understand you regarding the testing process.

@hraban
Copy link
Owner

hraban commented Mar 13, 2018 via email

@stop-start
Copy link
Author

stop-start commented Mar 19, 2018

I'm having some trouble with testing/using this. Like you said we don't really know what we're supposed to get and I don't really hear any differences between using FEC or telling opus that the packet is lost.
The packets need to be encoded the right way and although it seems they are (I'm currently using code written in C for the encoding part), all I hear when a packet is drop that the sound is cut.
Maybe i don't encode the right way or I don't use the decodeFEC right.
Anyway I'm still looking into how to check this.

@hraban
Copy link
Owner

hraban commented Mar 19, 2018 via email

@stop-start
Copy link
Author

I looked in encode.go and didn't see an option to configure the encoder with OPUS_SET_INBAND_FEC(1) and OPUS_SET_PACKET_LOSS_PERC.
It can be easily added though

@hraban
Copy link
Owner

hraban commented Mar 19, 2018 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants