From: elinor Date: Mon, 26 Mar 2018 07:33:31 +0000 (+0300) Subject: Added decode with fec + test X-Git-Tag: v2.0.0~21^2~12 X-Git-Url: http://www.git.stargrave.org/?a=commitdiff_plain;h=5ba421ac739bfc037bdad415edf61a7644c0229a;p=go-opus.git Added decode with fec + test --- diff --git a/decoder.go b/decoder.go index 99b8e61..9b5b117 100644 --- a/decoder.go +++ b/decoder.go @@ -112,8 +112,34 @@ func (dec *Decoder) DecodeFloat32(data []byte, pcm []float32) (int, error) { return n, nil } +// Decode encoded Opus data into the supplied buffer with forward error +// correction. The supplied buffer will be entirely filled. +func (dec *Decoder) DecodeFEC(data []byte, pcm []int16) error { + if dec.p == nil { + return errDecUninitialized + } + if len(data) == 0 { + return fmt.Errorf("opus: no data supplied") + } + if len(pcm) == 0 { + return fmt.Errorf("opus: target buffer empty") + } + + n := int(C.opus_decode( + dec.p, + (*C.uchar)(&data[0]), + C.opus_int32(len(data)), + (*C.opus_int16)(&pcm[0]), + C.int(cap(pcm)), + 1)) + if n < 0 { + return Error(n) + } + return nil +} + // Gets the duration (in samples) of the last packet successfully decoded or concealed. -func (dec *Decoder) LastPacketDuration() (int,error){ +func (dec *Decoder) LastPacketDuration() (int, error) { var samples C.opus_int32 res := C.bridge_decoder_get_last_packet_duration(dec.p, &samples) if res != C.OPUS_OK { diff --git a/opus_test.go b/opus_test.go index 77ea94f..f894d5b 100644 --- a/opus_test.go +++ b/opus_test.go @@ -59,6 +59,90 @@ func TestCodec(t *testing.T) { // passes error codes through, and that's that. } +func TestCodecFEC(t *testing.T) { + // Create bogus input sound + const G4 = 391.995 + const SAMPLE_RATE = 48000 + const FRAME_SIZE_MS = 60 + const FRAME_SIZE = SAMPLE_RATE * FRAME_SIZE_MS / 1000 + const PACKET_SIZE = 480 // 10ms packet + pcm := make([]int16, 0) + + enc, err := NewEncoder(SAMPLE_RATE, 1, AppVoIP) + if err != nil || enc == nil { + t.Fatalf("Error creating new encoder: %v", err) + } + enc.SetPacketLossPerc(30) + enc.SetInBandFEC(1) + + dec, err := NewDecoder(SAMPLE_RATE, 1) + if err != nil || dec == nil { + t.Fatalf("Error creating new decoder: %v", err) + } + + mono := make([]int16, FRAME_SIZE) + addSine(mono, SAMPLE_RATE, G4) + + encodedData := make([][]byte, FRAME_SIZE/PACKET_SIZE) + for i, idx := 0, 0; i < len(mono); i += PACKET_SIZE { + data := make([]byte, 1000) + n, err := enc.Encode(mono[i:i+PACKET_SIZE], data) + if err != nil { + t.Fatalf("Couldn't encode data: %v", err) + } + data = data[:n] + encodedData[idx] = data + idx++ + } + + lost := false + for i := 0; i < len(encodedData); i++ { + // "Dropping" packets 2 and 4 + if i == 2 || i == 4 { + lost = true + continue + } + if lost { + samples, err := dec.LastPacketDuration() + if err != nil { + t.Fatalf("Couldn't get last packet duration: %v", err) + } + + pcmBuffer := make([]int16, samples) + if err = dec.DecodeFEC(encodedData[i], pcmBuffer); err != nil { + t.Fatalf("Couldn't decode data: %v", err) + } + pcm = append(pcm, pcmBuffer...) + lost = false + } + + pcmBuffer := make([]int16, FRAME_SIZE) + n, err := dec.Decode(encodedData[i], pcmBuffer) + if err != nil { + t.Fatalf("Couldn't decode data: %v", err) + } + pcmBuffer = pcmBuffer[:n] + if len(pcmBuffer) != n { + t.Fatalf("Length mismatch: %d samples in, %d out", len(pcmBuffer), n) + } + pcm = append(pcm, pcmBuffer...) + } + + if len(mono) != len(pcm) { + t.Fatalf("Input/Output length mismatch: %d samples in, %d out", len(mono), len(pcm)) + } + + // This is hard to check programatically, but I plotted the graphs in a + // spreadsheet and it looked great. The encoded waves both start out with a + // string of zero samples before they pick up, and the G4 is phase shifted + // by half a period, but that's all fine for lossy audio encoding. + + //fmt.Printf("in,out\n") + //for i := range mono { + // fmt.Printf("%d,%d\n", mono[i], pcm[i]) + //} +} + func TestCodecFloat32(t *testing.T) { // Create bogus input sound const G4 = 391.995