]> Sergey Matveev's repositories - go-opus.git/commitdiff
Added decode with fec + test
authorelinor <elinor.alp@gmail.com>
Mon, 26 Mar 2018 07:33:31 +0000 (10:33 +0300)
committerelinor <elinor.alp@gmail.com>
Mon, 26 Mar 2018 07:33:31 +0000 (10:33 +0300)
decoder.go
opus_test.go

index 99b8e61024d6f368b178eeff833e715b60f84347..9b5b11756909765ac9d0ce8b74c4940a547fe5ff 100644 (file)
@@ -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 {
index 77ea94fda45bd76ab325122df60003f85fd1fa7c..f894d5bf5b46468bc4d3d5f8c8ebf46aea5f91d2 100644 (file)
@@ -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