return nil
}
+// DecodePLC recovers a lost packet using Opus Packet Loss Concealment feature.
+// The supplied buffer needs to be exactly the duration of audio that is missing.
+func (dec *Decoder) DecodePLC(pcm []int16) error {
+ if dec.p == nil {
+ return errDecUninitialized
+ }
+ if len(pcm) == 0 {
+ return fmt.Errorf("opus: target buffer empty")
+ }
+ if cap(pcm)%dec.channels != 0 {
+ return fmt.Errorf("opus: output buffer capacity must be multiple of channels")
+ }
+ n := int(C.opus_decode(
+ dec.p,
+ nil,
+ 0,
+ (*C.opus_int16)(&pcm[0]),
+ C.int(cap(pcm)/dec.channels),
+ 0))
+ if n < 0 {
+ return Error(n)
+ }
+ return nil
+}
+
+// DecodePLCFloat32 recovers a lost packet using Opus Packet Loss Concealment feature.
+// The supplied buffer needs to be exactly the duration of audio that is missing.
+func (dec *Decoder) DecodePLCFloat32(pcm []float32) error {
+ if dec.p == nil {
+ return errDecUninitialized
+ }
+ if len(pcm) == 0 {
+ return fmt.Errorf("opus: target buffer empty")
+ }
+ if cap(pcm)%dec.channels != 0 {
+ return fmt.Errorf("opus: output buffer capacity must be multiple of channels")
+ }
+ n := int(C.opus_decode_float(
+ dec.p,
+ nil,
+ 0,
+ (*C.float)(&pcm[0]),
+ C.int(cap(pcm)/dec.channels),
+ 0))
+ if n < 0 {
+ return Error(n)
+ }
+ return nil
+}
+
// LastPacketDuration gets the duration (in samples)
// of the last packet successfully decoded or concealed.
func (dec *Decoder) LastPacketDuration() (int, error) {
*/
}
+func TestCodecPLC(t *testing.T) {
+ // Create bogus input sound
+ const G4 = 391.995
+ const SAMPLE_RATE = 48000
+ const FRAME_SIZE_MS = 10
+ const FRAME_SIZE = SAMPLE_RATE * FRAME_SIZE_MS / 1000
+ const NUMBER_OF_FRAMES = 6
+ pcm := make([]int16, 0)
+
+ enc, err := NewEncoder(SAMPLE_RATE, 1, AppVoIP)
+ if err != nil || enc == nil {
+ t.Fatalf("Error creating new encoder: %v", err)
+ }
+
+ dec, err := NewDecoder(SAMPLE_RATE, 1)
+ if err != nil || dec == nil {
+ t.Fatalf("Error creating new decoder: %v", err)
+ }
+
+ mono := make([]int16, FRAME_SIZE*NUMBER_OF_FRAMES)
+ addSine(mono, SAMPLE_RATE, G4)
+
+ encodedData := make([][]byte, NUMBER_OF_FRAMES)
+ for i, idx := 0, 0; i < len(mono); i += FRAME_SIZE {
+ data := make([]byte, 1000)
+ n, err := enc.Encode(mono[i:i+FRAME_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.DecodePLC(pcmBuffer); err != nil {
+ t.Fatalf("Couldn't decode data: %v", err)
+ }
+ nonZero := 0
+ for n := range pcmBuffer {
+ if pcmBuffer[n] != 0 {
+ nonZero++
+ }
+ }
+ if nonZero == 0 {
+ t.Fatalf("DecodePLC produced only zero samples")
+ }
+ pcm = append(pcm, pcmBuffer...)
+ lost = false
+ }
+
+ pcmBuffer := make([]int16, NUMBER_OF_FRAMES*FRAME_SIZE)
+ n, err := dec.Decode(encodedData[i], pcmBuffer)
+ if err != nil {
+ t.Fatalf("Couldn't decode data: %v", err)
+ }
+ pcmBuffer = pcmBuffer[:n]
+ if n != FRAME_SIZE {
+ t.Fatalf("Length mismatch: %d samples expected, %d out", FRAME_SIZE, 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))
+ }
+
+ // Commented out for the same reason as in TestStereo
+ /*
+ fmt.Printf("in,out\n")
+ for i := range mono {
+ fmt.Printf("%d,%d\n", mono[i], pcm[i])
+ }
+ */
+
+}
+
+func TestCodecPLCFloat32(t *testing.T) {
+ // Create bogus input sound
+ const G4 = 391.995
+ const SAMPLE_RATE = 48000
+ const FRAME_SIZE_MS = 10
+ const FRAME_SIZE = SAMPLE_RATE * FRAME_SIZE_MS / 1000
+ const NUMBER_OF_FRAMES = 6
+ pcm := make([]float32, 0)
+
+ enc, err := NewEncoder(SAMPLE_RATE, 1, AppVoIP)
+ if err != nil || enc == nil {
+ t.Fatalf("Error creating new encoder: %v", err)
+ }
+
+ dec, err := NewDecoder(SAMPLE_RATE, 1)
+ if err != nil || dec == nil {
+ t.Fatalf("Error creating new decoder: %v", err)
+ }
+
+ mono := make([]float32, FRAME_SIZE*NUMBER_OF_FRAMES)
+ addSineFloat32(mono, SAMPLE_RATE, G4)
+
+ encodedData := make([][]byte, NUMBER_OF_FRAMES)
+ for i, idx := 0, 0; i < len(mono); i += FRAME_SIZE {
+ data := make([]byte, 1000)
+ n, err := enc.EncodeFloat32(mono[i:i+FRAME_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([]float32, samples)
+ if err = dec.DecodePLCFloat32(pcmBuffer); err != nil {
+ t.Fatalf("Couldn't decode data: %v", err)
+ }
+ nonZero := 0
+ for n := range pcmBuffer {
+ if pcmBuffer[n] != 0.0 {
+ nonZero++
+ }
+ }
+ if nonZero == 0 {
+ t.Fatalf("DecodePLC produced only zero samples")
+ }
+ pcm = append(pcm, pcmBuffer...)
+ lost = false
+ }
+
+ pcmBuffer := make([]float32, NUMBER_OF_FRAMES*FRAME_SIZE)
+ n, err := dec.DecodeFloat32(encodedData[i], pcmBuffer)
+ if err != nil {
+ t.Fatalf("Couldn't decode data: %v", err)
+ }
+ pcmBuffer = pcmBuffer[:n]
+ if n != FRAME_SIZE {
+ t.Fatalf("Length mismatch: %d samples expected, %d out", FRAME_SIZE, 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))
+ }
+
+ // Commented out for the same reason as in TestStereo
+ /*
+ 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) {
// Create bogus input sound
const G4 = 391.995