From 68fb7a26d928fed3a6109392469af3c8d46d3075 Mon Sep 17 00:00:00 2001 From: elinor Date: Mon, 26 Mar 2018 10:39:25 +0300 Subject: [PATCH] Added decodeFECFloat32 + test --- decoder.go | 25 ++++++++++ opus_test.go | 126 +++++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 132 insertions(+), 19 deletions(-) diff --git a/decoder.go b/decoder.go index 9b5b117..50453bb 100644 --- a/decoder.go +++ b/decoder.go @@ -138,6 +138,31 @@ func (dec *Decoder) DecodeFEC(data []byte, pcm []int16) error { return nil } +// Decode encoded Opus data into the supplied buffer with forward error +// correction. The supplied buffer will be entirely filled. +func (dec *Decoder) DecodeFECFloat32(data []byte, pcm []float32) 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_float( + dec.p, + (*C.uchar)(&data[0]), + C.opus_int32(len(data)), + (*C.float)(&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) { var samples C.opus_int32 diff --git a/opus_test.go b/opus_test.go index f894d5b..68ac45d 100644 --- a/opus_test.go +++ b/opus_test.go @@ -59,6 +59,38 @@ func TestCodec(t *testing.T) { // passes error codes through, and that's that. } +func TestCodecFloat32(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 + pcm := make([]float32, FRAME_SIZE) + enc, err := NewEncoder(SAMPLE_RATE, 1, AppVoIP) + if err != nil || enc == nil { + t.Fatalf("Error creating new encoder: %v", err) + } + addSineFloat32(pcm, SAMPLE_RATE, G4) + data := make([]byte, 1000) + n, err := enc.EncodeFloat32(pcm, data) + if err != nil { + t.Fatalf("Couldn't encode data: %v", err) + } + dec, err := NewDecoder(SAMPLE_RATE, 1) + if err != nil || dec == nil { + t.Fatalf("Error creating new decoder: %v", err) + } + // TODO: Uh-oh.. it looks like I forgot to put a data = data[:n] here, yet + // the test is not failing. Why? + n, err = dec.DecodeFloat32(data, pcm) + if err != nil { + t.Fatalf("Couldn't decode data: %v", err) + } + if len(pcm) != n { + t.Fatalf("Length mismatch: %d samples in, %d out", len(pcm), n) + } +} + func TestCodecFEC(t *testing.T) { // Create bogus input sound const G4 = 391.995 @@ -137,42 +169,98 @@ func TestCodecFEC(t *testing.T) { // 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]) - //} + /* + fmt.Printf("in,out\n") + for i := range mono { + fmt.Printf("%d,%d\n", mono[i], pcm[i]) + } + */ } -func TestCodecFloat32(t *testing.T) { +func TestCodecFECFloat32(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 - pcm := make([]float32, FRAME_SIZE) + const PACKET_SIZE = 480 // 10ms packet + pcm := make([]float32, 0) + enc, err := NewEncoder(SAMPLE_RATE, 1, AppVoIP) if err != nil || enc == nil { t.Fatalf("Error creating new encoder: %v", err) } - addSineFloat32(pcm, SAMPLE_RATE, G4) - data := make([]byte, 1000) - n, err := enc.EncodeFloat32(pcm, data) - if err != nil { - t.Fatalf("Couldn't encode data: %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) } - // TODO: Uh-oh.. it looks like I forgot to put a data = data[:n] here, yet - // the test is not failing. Why? - n, err = dec.DecodeFloat32(data, pcm) - if err != nil { - t.Fatalf("Couldn't decode data: %v", err) + + mono := make([]float32, FRAME_SIZE) + addSineFloat32(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.EncodeFloat32(mono[i:i+PACKET_SIZE], data) + if err != nil { + t.Fatalf("Couldn't encode data: %v", err) + } + data = data[:n] + encodedData[idx] = data + idx++ } - if len(pcm) != n { - t.Fatalf("Length mismatch: %d samples in, %d out", len(pcm), n) + + 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([]float32, samples) + if err = dec.DecodeFECFloat32(encodedData[i], pcmBuffer); err != nil { + t.Fatalf("Couldn't decode data: %v", err) + } + pcm = append(pcm, pcmBuffer...) + lost = false + } + + pcmBuffer := make([]float32, FRAME_SIZE) + n, err := dec.DecodeFloat32(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 := 0; i < len(mono); i++ { + fmt.Printf("%f,%f\n", mono[i], pcm[i]) + } + */ } func TestStereo(t *testing.T) { -- 2.48.1