2019-02-15 18:10:35 +03:00
|
|
|
/*
|
|
|
|
NAME
|
|
|
|
mtsSender_test.go
|
|
|
|
|
|
|
|
DESCRIPTION
|
|
|
|
mtsSender_test.go contains tests that validate the functionalilty of the
|
|
|
|
mtsSender under senders.go. Tests include checks that the mtsSender is
|
|
|
|
segmenting sends correctly, and also that it can correct discontinuities.
|
|
|
|
|
|
|
|
AUTHORS
|
|
|
|
Saxon A. Nelson-Milton <saxon@ausocean.org>
|
|
|
|
|
|
|
|
LICENSE
|
|
|
|
mtsSender_test.go is Copyright (C) 2017-2019 the Australian Ocean Lab (AusOcean)
|
|
|
|
|
|
|
|
It is free software: you can redistribute it and/or modify them
|
|
|
|
under the terms of the GNU General Public License as published by the
|
|
|
|
Free Software Foundation, either version 3 of the License, or (at your
|
|
|
|
option) any later version.
|
|
|
|
|
|
|
|
It is distributed in the hope that it will be useful, but WITHOUT
|
|
|
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
|
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
|
|
for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
2019-03-01 02:32:43 +03:00
|
|
|
in gpl.txt. If not, see http://www.gnu.org/licenses.
|
2019-02-15 18:10:35 +03:00
|
|
|
*/
|
|
|
|
package revid
|
|
|
|
|
2019-02-16 09:03:39 +03:00
|
|
|
import (
|
2019-02-16 20:05:59 +03:00
|
|
|
"errors"
|
2019-02-16 09:03:39 +03:00
|
|
|
"fmt"
|
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
2019-03-01 02:33:39 +03:00
|
|
|
"github.com/Comcast/gots/packet"
|
|
|
|
"github.com/Comcast/gots/pes"
|
|
|
|
|
2019-02-16 09:03:39 +03:00
|
|
|
"bitbucket.org/ausocean/av/stream/mts"
|
2019-02-16 16:22:40 +03:00
|
|
|
"bitbucket.org/ausocean/av/stream/mts/meta"
|
2019-02-16 09:03:39 +03:00
|
|
|
"bitbucket.org/ausocean/utils/logger"
|
|
|
|
"bitbucket.org/ausocean/utils/ring"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Ring buffer sizes and read/write timeouts.
|
|
|
|
const (
|
|
|
|
rbSize = 100
|
|
|
|
rbElementSize = 150000
|
|
|
|
wTimeout = 10 * time.Millisecond
|
|
|
|
rTimeout = 10 * time.Millisecond
|
|
|
|
)
|
|
|
|
|
2019-03-01 02:46:54 +03:00
|
|
|
type sender struct {
|
2019-03-01 03:47:40 +03:00
|
|
|
buf [][]byte
|
|
|
|
testDiscontinuities bool
|
|
|
|
discontinuityAt int
|
|
|
|
currentPkt int
|
2019-02-16 09:03:39 +03:00
|
|
|
}
|
|
|
|
|
2019-03-01 02:46:54 +03:00
|
|
|
func (ts *sender) send(d []byte) error {
|
2019-03-01 03:47:40 +03:00
|
|
|
if ts.testDiscontinuities && ts.currentPkt == ts.discontinuityAt {
|
|
|
|
ts.currentPkt++
|
2019-02-16 20:05:59 +03:00
|
|
|
return errors.New("could not send")
|
2019-02-16 17:01:30 +03:00
|
|
|
}
|
2019-02-16 20:05:59 +03:00
|
|
|
cpy := make([]byte, len(d))
|
|
|
|
copy(cpy, d)
|
2019-03-01 03:41:20 +03:00
|
|
|
ts.buf = append(ts.buf, cpy)
|
2019-03-01 03:47:40 +03:00
|
|
|
ts.currentPkt++
|
2019-02-16 09:03:39 +03:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func log(lvl int8, msg string, args ...interface{}) {
|
|
|
|
var l string
|
|
|
|
switch lvl {
|
|
|
|
case logger.Warning:
|
|
|
|
l = "warning"
|
|
|
|
case logger.Debug:
|
|
|
|
l = "debug"
|
|
|
|
case logger.Info:
|
|
|
|
l = "info"
|
|
|
|
case logger.Error:
|
|
|
|
l = "error"
|
|
|
|
case logger.Fatal:
|
|
|
|
l = "fatal"
|
|
|
|
}
|
|
|
|
msg = l + ": " + msg
|
|
|
|
for i := 0; i < len(args); i++ {
|
|
|
|
msg += " %v"
|
|
|
|
}
|
|
|
|
fmt.Printf(msg, args)
|
|
|
|
}
|
|
|
|
|
2019-02-16 16:22:40 +03:00
|
|
|
type tstPacker struct {
|
|
|
|
rb *ring.Buffer
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *tstPacker) Write(d []byte) (int, error) {
|
|
|
|
n, err := p.rb.Write(d)
|
|
|
|
p.rb.Flush()
|
|
|
|
return n, err
|
2019-02-16 09:03:39 +03:00
|
|
|
}
|
2019-02-15 18:10:35 +03:00
|
|
|
|
|
|
|
func TestSegment(t *testing.T) {
|
2019-02-16 16:22:40 +03:00
|
|
|
mts.Meta = meta.New()
|
2019-02-16 09:03:39 +03:00
|
|
|
// Create ringbuffer tst sender, loadsender and the mpegts encoder
|
|
|
|
rb := ring.NewBuffer(rbSize, rbElementSize, wTimeout)
|
2019-03-01 02:46:54 +03:00
|
|
|
tstSender := &sender{}
|
2019-02-16 09:03:39 +03:00
|
|
|
loadSender := newMtsSender(tstSender, log)
|
2019-02-16 20:05:59 +03:00
|
|
|
packer := &tstPacker{rb: rb}
|
|
|
|
encoder := mts.NewEncoder(packer, 25)
|
2019-02-16 09:03:39 +03:00
|
|
|
|
|
|
|
// Turn time based psi writing off for encoder
|
|
|
|
const psiSendCount = 10
|
|
|
|
encoder.TimeBasedPsi(false, psiSendCount)
|
|
|
|
|
|
|
|
const noOfPacketsToWrite = 100
|
|
|
|
for i := 0; i < noOfPacketsToWrite; i++ {
|
|
|
|
// Our payload will just be packet no
|
|
|
|
encoder.Encode([]byte{byte(i)})
|
2019-02-16 16:22:40 +03:00
|
|
|
rb.Flush()
|
2019-02-16 09:03:39 +03:00
|
|
|
|
2019-02-16 20:05:59 +03:00
|
|
|
for {
|
|
|
|
next, err := rb.Next(rTimeout)
|
|
|
|
if err != nil {
|
|
|
|
break
|
|
|
|
}
|
2019-02-16 09:03:39 +03:00
|
|
|
|
2019-02-16 20:05:59 +03:00
|
|
|
err = loadSender.load(next)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Unexpected err: %v\n", err)
|
|
|
|
}
|
2019-02-16 09:03:39 +03:00
|
|
|
|
2019-02-16 20:05:59 +03:00
|
|
|
err = loadSender.send()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Unexpected err: %v\n", err)
|
|
|
|
}
|
|
|
|
loadSender.release()
|
|
|
|
}
|
2019-02-16 09:03:39 +03:00
|
|
|
}
|
|
|
|
|
2019-03-01 03:41:20 +03:00
|
|
|
result := tstSender.buf
|
2019-02-16 20:05:59 +03:00
|
|
|
expectData := 0
|
2019-02-16 09:03:39 +03:00
|
|
|
for clipNo, clip := range result {
|
2019-02-16 22:02:44 +03:00
|
|
|
t.Logf("Checking clip: %v\n", clipNo)
|
2019-02-16 09:03:39 +03:00
|
|
|
// Check that the clip is the right length
|
|
|
|
clipLen := len(clip)
|
2019-02-16 20:05:59 +03:00
|
|
|
if clipLen != psiSendCount*mts.PacketSize {
|
2019-02-16 16:22:40 +03:00
|
|
|
t.Fatalf("Clip %v is not correct length. Got: %v Want: %v\n Clip: %v\n", clipNo, clipLen, psiSendCount*mts.PacketSize, clip)
|
2019-02-16 09:03:39 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// Also check that the first packet is a PAT
|
|
|
|
firstPkt := clip[:mts.PacketSize]
|
|
|
|
var pkt [mts.PacketSize]byte
|
|
|
|
copy(pkt[:], firstPkt)
|
|
|
|
pid := (*packet.Packet)(&pkt).PID()
|
|
|
|
if pid != mts.PatPid {
|
2019-02-16 17:01:30 +03:00
|
|
|
t.Fatalf("First packet of clip %v is not pat, but rather: %v\n", clipNo, pid)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check that the clip data is okay
|
|
|
|
for i := 0; i < len(clip); i += mts.PacketSize {
|
2019-02-16 20:05:59 +03:00
|
|
|
firstPkt := clip[i : i+mts.PacketSize]
|
2019-02-16 17:01:30 +03:00
|
|
|
copy(pkt[:], firstPkt)
|
|
|
|
p := (*packet.Packet)(&pkt)
|
|
|
|
pid := p.PID()
|
|
|
|
if pid == mts.VideoPid {
|
|
|
|
// Mts payload
|
|
|
|
payload, err := p.Payload()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Unexpected err: %v\n", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parse pes from the mts payload
|
|
|
|
pes, err := pes.NewPESHeader(payload)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Unexpected err: %v\n", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the data from the pes packet and convert to int
|
2019-02-16 20:05:59 +03:00
|
|
|
data := int8(pes.Data()[0])
|
2019-02-16 17:01:30 +03:00
|
|
|
|
|
|
|
// Calc expected data in the pes and then check
|
2019-02-16 20:05:59 +03:00
|
|
|
if data != int8(expectData) {
|
|
|
|
t.Errorf("Did not get expected pkt data. ClipNo: %v, pktNoInClip: %v, Got: %v, want: %v\n", clipNo, i/mts.PacketSize, data, expectData)
|
2019-02-16 17:01:30 +03:00
|
|
|
}
|
2019-02-16 20:05:59 +03:00
|
|
|
expectData++
|
2019-02-16 17:01:30 +03:00
|
|
|
}
|
2019-02-16 09:03:39 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-02-15 18:10:35 +03:00
|
|
|
|
2019-02-16 17:01:30 +03:00
|
|
|
func TestSendFailDiscontinuity(t *testing.T) {
|
|
|
|
mts.Meta = meta.New()
|
|
|
|
// Create ringbuffer tst sender, loadsender and the mpegts encoder
|
|
|
|
rb := ring.NewBuffer(rbSize, rbElementSize, wTimeout)
|
|
|
|
const disconClipNo = 3
|
2019-03-01 03:47:40 +03:00
|
|
|
tstSender := &sender{testDiscontinuities: true, discontinuityAt: disconClipNo}
|
2019-02-16 17:01:30 +03:00
|
|
|
loadSender := newMtsSender(tstSender, log)
|
|
|
|
packer := tstPacker{rb: rb}
|
|
|
|
encoder := mts.NewEncoder(&packer, 25)
|
|
|
|
|
|
|
|
// Turn time based psi writing off for encoder
|
|
|
|
const psiSendCount = 10
|
|
|
|
encoder.TimeBasedPsi(false, psiSendCount)
|
|
|
|
|
|
|
|
const noOfPacketsToWrite = 100
|
|
|
|
for i := 0; i < noOfPacketsToWrite; i++ {
|
|
|
|
// Our payload will just be packet no
|
|
|
|
encoder.Encode([]byte{byte(i)})
|
|
|
|
rb.Flush()
|
|
|
|
|
2019-02-16 22:02:44 +03:00
|
|
|
for {
|
|
|
|
next, err := rb.Next(rTimeout)
|
|
|
|
if err != nil {
|
|
|
|
break
|
|
|
|
}
|
2019-02-16 17:01:30 +03:00
|
|
|
|
2019-02-16 22:02:44 +03:00
|
|
|
err = loadSender.load(next)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Unexpected err: %v\n", err)
|
|
|
|
}
|
2019-02-16 17:01:30 +03:00
|
|
|
|
2019-02-16 22:02:44 +03:00
|
|
|
_ = loadSender.send()
|
2019-02-15 18:10:35 +03:00
|
|
|
|
2019-02-16 22:02:44 +03:00
|
|
|
loadSender.release()
|
|
|
|
}
|
2019-02-16 17:01:30 +03:00
|
|
|
}
|
|
|
|
|
2019-03-01 03:41:20 +03:00
|
|
|
result := tstSender.buf
|
2019-02-16 17:01:30 +03:00
|
|
|
|
|
|
|
// First check that we have less clips
|
2019-02-16 22:02:44 +03:00
|
|
|
expectedLen := (((noOfPacketsToWrite/psiSendCount)*2 + noOfPacketsToWrite) / psiSendCount) - 1
|
2019-02-16 17:01:30 +03:00
|
|
|
gotLen := len(result)
|
|
|
|
if gotLen != expectedLen {
|
2019-02-16 20:05:59 +03:00
|
|
|
t.Errorf("We don't have one less clip as we should. Got: %v, want: %v\n", gotLen, expectedLen)
|
2019-02-16 17:01:30 +03:00
|
|
|
}
|
|
|
|
// Now check that the discontonuity indicator is set at the disconClip pat
|
|
|
|
disconClip := result[disconClipNo]
|
|
|
|
firstPkt := disconClip[:mts.PacketSize]
|
|
|
|
var pkt [mts.PacketSize]byte
|
|
|
|
copy(pkt[:], firstPkt)
|
|
|
|
discon, err := (*packet.AdaptationField)((*packet.Packet)(&pkt)).Discontinuity()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Unexpected err: %v\n", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if !discon {
|
|
|
|
t.Fatalf("Did not get discontinuity indicator for PAT")
|
|
|
|
}
|
2019-02-16 20:05:59 +03:00
|
|
|
|
2019-02-15 18:10:35 +03:00
|
|
|
}
|