16 changed files with 336 additions and 276 deletions
@ -1,129 +0,0 @@
@@ -1,129 +0,0 @@
|
||||
package core |
||||
|
||||
import ( |
||||
"bufio" |
||||
"testing" |
||||
"time" |
||||
|
||||
"github.com/bluenviron/mediacommon/pkg/formats/mpegts" |
||||
"github.com/bluenviron/mediamtx/internal/test" |
||||
srt "github.com/datarhei/gosrt" |
||||
"github.com/stretchr/testify/require" |
||||
) |
||||
|
||||
func TestSRTServer(t *testing.T) { |
||||
for _, ca := range []string{ |
||||
"no passphrase", |
||||
"publish passphrase", |
||||
"read passphrase", |
||||
} { |
||||
t.Run(ca, func(t *testing.T) { |
||||
conf := "paths:\n" + |
||||
" all_others:\n" |
||||
|
||||
switch ca { |
||||
case "publish passphrase": |
||||
conf += " srtPublishPassphrase: 123456789abcde" |
||||
|
||||
case "read passphrase": |
||||
conf += " srtReadPassphrase: 123456789abcde" |
||||
} |
||||
|
||||
p, ok := newInstance(conf) |
||||
require.Equal(t, true, ok) |
||||
defer p.Close() |
||||
|
||||
u := "srt://localhost:8890?streamid=publish:mypath" |
||||
if ca == "publish passphrase" { |
||||
u += "&passphrase=123456789abcde" |
||||
} |
||||
|
||||
srtConf := srt.DefaultConfig() |
||||
address, err := srtConf.UnmarshalURL(u) |
||||
require.NoError(t, err) |
||||
|
||||
err = srtConf.Validate() |
||||
require.NoError(t, err) |
||||
|
||||
publisher, err := srt.Dial("srt", address, srtConf) |
||||
require.NoError(t, err) |
||||
defer publisher.Close() |
||||
|
||||
track := &mpegts.Track{ |
||||
Codec: &mpegts.CodecH264{}, |
||||
} |
||||
|
||||
bw := bufio.NewWriter(publisher) |
||||
w := mpegts.NewWriter(bw, []*mpegts.Track{track}) |
||||
require.NoError(t, err) |
||||
|
||||
err = w.WriteH26x(track, 0, 0, true, [][]byte{ |
||||
test.FormatH264.SPS, |
||||
test.FormatH264.PPS, |
||||
{0x05, 1}, // IDR
|
||||
}) |
||||
require.NoError(t, err) |
||||
|
||||
err = bw.Flush() |
||||
require.NoError(t, err) |
||||
|
||||
time.Sleep(500 * time.Millisecond) |
||||
|
||||
u = "srt://localhost:8890?streamid=read:mypath" |
||||
if ca == "read passphrase" { |
||||
u += "&passphrase=123456789abcde" |
||||
} |
||||
|
||||
srtConf = srt.DefaultConfig() |
||||
address, err = srtConf.UnmarshalURL(u) |
||||
require.NoError(t, err) |
||||
|
||||
err = srtConf.Validate() |
||||
require.NoError(t, err) |
||||
|
||||
reader, err := srt.Dial("srt", address, srtConf) |
||||
require.NoError(t, err) |
||||
defer reader.Close() |
||||
|
||||
err = w.WriteH26x(track, 2*90000, 1*90000, true, [][]byte{ |
||||
{ // IDR
|
||||
0x05, 2, |
||||
}, |
||||
}) |
||||
require.NoError(t, err) |
||||
|
||||
err = bw.Flush() |
||||
require.NoError(t, err) |
||||
|
||||
r, err := mpegts.NewReader(reader) |
||||
require.NoError(t, err) |
||||
|
||||
require.Equal(t, []*mpegts.Track{{ |
||||
PID: 256, |
||||
Codec: &mpegts.CodecH264{}, |
||||
}}, r.Tracks()) |
||||
|
||||
received := false |
||||
|
||||
r.OnDataH26x(r.Tracks()[0], func(pts int64, dts int64, au [][]byte) error { |
||||
require.Equal(t, int64(0), pts) |
||||
require.Equal(t, int64(0), dts) |
||||
require.Equal(t, [][]byte{ |
||||
test.FormatH264.SPS, |
||||
test.FormatH264.PPS, |
||||
{0x05, 1}, |
||||
}, au) // IDR
|
||||
received = true |
||||
return nil |
||||
}) |
||||
|
||||
for { |
||||
err = r.Read() |
||||
require.NoError(t, err) |
||||
if received { |
||||
break |
||||
} |
||||
} |
||||
}) |
||||
} |
||||
} |
@ -0,0 +1,267 @@
@@ -0,0 +1,267 @@
|
||||
package srt |
||||
|
||||
import ( |
||||
"bufio" |
||||
"testing" |
||||
"time" |
||||
|
||||
"github.com/bluenviron/gortsplib/v4/pkg/description" |
||||
"github.com/bluenviron/gortsplib/v4/pkg/format" |
||||
"github.com/bluenviron/mediacommon/pkg/formats/mpegts" |
||||
"github.com/bluenviron/mediamtx/internal/asyncwriter" |
||||
"github.com/bluenviron/mediamtx/internal/conf" |
||||
"github.com/bluenviron/mediamtx/internal/defs" |
||||
"github.com/bluenviron/mediamtx/internal/externalcmd" |
||||
"github.com/bluenviron/mediamtx/internal/stream" |
||||
"github.com/bluenviron/mediamtx/internal/test" |
||||
"github.com/bluenviron/mediamtx/internal/unit" |
||||
srt "github.com/datarhei/gosrt" |
||||
"github.com/stretchr/testify/require" |
||||
) |
||||
|
||||
type dummyPath struct { |
||||
stream *stream.Stream |
||||
streamCreated chan struct{} |
||||
} |
||||
|
||||
func (p *dummyPath) Name() string { |
||||
return "teststream" |
||||
} |
||||
|
||||
func (p *dummyPath) SafeConf() *conf.Path { |
||||
return &conf.Path{} |
||||
} |
||||
|
||||
func (p *dummyPath) ExternalCmdEnv() externalcmd.Environment { |
||||
return externalcmd.Environment{} |
||||
} |
||||
|
||||
func (p *dummyPath) StartPublisher(req defs.PathStartPublisherReq) (*stream.Stream, error) { |
||||
var err error |
||||
p.stream, err = stream.New( |
||||
1460, |
||||
req.Desc, |
||||
true, |
||||
test.NilLogger{}, |
||||
) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
close(p.streamCreated) |
||||
return p.stream, nil |
||||
} |
||||
|
||||
func (p *dummyPath) StopPublisher(_ defs.PathStopPublisherReq) { |
||||
} |
||||
|
||||
func (p *dummyPath) RemovePublisher(_ defs.PathRemovePublisherReq) { |
||||
} |
||||
|
||||
func (p *dummyPath) RemoveReader(_ defs.PathRemoveReaderReq) { |
||||
} |
||||
|
||||
type dummyPathManager struct { |
||||
path *dummyPath |
||||
} |
||||
|
||||
func (pm *dummyPathManager) AddPublisher(_ defs.PathAddPublisherReq) (defs.Path, error) { |
||||
return pm.path, nil |
||||
} |
||||
|
||||
func (pm *dummyPathManager) AddReader(_ defs.PathAddReaderReq) (defs.Path, *stream.Stream, error) { |
||||
return pm.path, pm.path.stream, nil |
||||
} |
||||
|
||||
func TestServerPublish(t *testing.T) { |
||||
externalCmdPool := externalcmd.NewPool() |
||||
defer externalCmdPool.Close() |
||||
|
||||
path := &dummyPath{ |
||||
streamCreated: make(chan struct{}), |
||||
} |
||||
|
||||
pathManager := &dummyPathManager{path: path} |
||||
|
||||
s := &Server{ |
||||
Address: "127.0.0.1:8890", |
||||
RTSPAddress: "", |
||||
ReadTimeout: conf.StringDuration(10 * time.Second), |
||||
WriteTimeout: conf.StringDuration(10 * time.Second), |
||||
WriteQueueSize: 512, |
||||
UDPMaxPayloadSize: 1472, |
||||
RunOnConnect: "", |
||||
RunOnConnectRestart: false, |
||||
RunOnDisconnect: "string", |
||||
ExternalCmdPool: externalCmdPool, |
||||
PathManager: pathManager, |
||||
Parent: &test.NilLogger{}, |
||||
} |
||||
err := s.Initialize() |
||||
require.NoError(t, err) |
||||
defer s.Close() |
||||
|
||||
u := "srt://localhost:8890?streamid=publish:mypath" |
||||
|
||||
srtConf := srt.DefaultConfig() |
||||
address, err := srtConf.UnmarshalURL(u) |
||||
require.NoError(t, err) |
||||
|
||||
err = srtConf.Validate() |
||||
require.NoError(t, err) |
||||
|
||||
publisher, err := srt.Dial("srt", address, srtConf) |
||||
require.NoError(t, err) |
||||
defer publisher.Close() |
||||
|
||||
track := &mpegts.Track{ |
||||
Codec: &mpegts.CodecH264{}, |
||||
} |
||||
|
||||
bw := bufio.NewWriter(publisher) |
||||
w := mpegts.NewWriter(bw, []*mpegts.Track{track}) |
||||
require.NoError(t, err) |
||||
|
||||
err = w.WriteH26x(track, 0, 0, true, [][]byte{ |
||||
test.FormatH264.SPS, |
||||
test.FormatH264.PPS, |
||||
{0x05, 1}, // IDR
|
||||
}) |
||||
require.NoError(t, err) |
||||
|
||||
err = bw.Flush() |
||||
require.NoError(t, err) |
||||
|
||||
<-path.streamCreated |
||||
|
||||
aw := asyncwriter.New(512, &test.NilLogger{}) |
||||
|
||||
recv := make(chan struct{}) |
||||
|
||||
path.stream.AddReader(aw, |
||||
path.stream.Desc().Medias[0], |
||||
path.stream.Desc().Medias[0].Formats[0], |
||||
func(u unit.Unit) error { |
||||
require.Equal(t, [][]byte{ |
||||
test.FormatH264.SPS, |
||||
test.FormatH264.PPS, |
||||
{0x05, 1}, // IDR
|
||||
}, u.(*unit.H264).AU) |
||||
close(recv) |
||||
return nil |
||||
}) |
||||
|
||||
err = w.WriteH26x(track, 0, 0, true, [][]byte{ |
||||
{5, 2}, |
||||
}) |
||||
require.NoError(t, err) |
||||
|
||||
err = bw.Flush() |
||||
require.NoError(t, err) |
||||
|
||||
aw.Start() |
||||
<-recv |
||||
aw.Stop() |
||||
} |
||||
|
||||
func TestServerRead(t *testing.T) { |
||||
externalCmdPool := externalcmd.NewPool() |
||||
defer externalCmdPool.Close() |
||||
|
||||
testMediaH264 := &description.Media{ |
||||
Type: description.MediaTypeVideo, |
||||
Formats: []format.Format{test.FormatH264}, |
||||
} |
||||
|
||||
desc := &description.Session{Medias: []*description.Media{testMediaH264}} |
||||
|
||||
stream, err := stream.New( |
||||
1460, |
||||
desc, |
||||
true, |
||||
test.NilLogger{}, |
||||
) |
||||
require.NoError(t, err) |
||||
|
||||
path := &dummyPath{stream: stream} |
||||
|
||||
pathManager := &dummyPathManager{path: path} |
||||
|
||||
s := &Server{ |
||||
Address: "127.0.0.1:8890", |
||||
RTSPAddress: "", |
||||
ReadTimeout: conf.StringDuration(10 * time.Second), |
||||
WriteTimeout: conf.StringDuration(10 * time.Second), |
||||
WriteQueueSize: 512, |
||||
UDPMaxPayloadSize: 1472, |
||||
RunOnConnect: "", |
||||
RunOnConnectRestart: false, |
||||
RunOnDisconnect: "string", |
||||
ExternalCmdPool: externalCmdPool, |
||||
PathManager: pathManager, |
||||
Parent: &test.NilLogger{}, |
||||
} |
||||
err = s.Initialize() |
||||
require.NoError(t, err) |
||||
defer s.Close() |
||||
|
||||
u := "srt://localhost:8890?streamid=read:mypath" |
||||
|
||||
srtConf := srt.DefaultConfig() |
||||
address, err := srtConf.UnmarshalURL(u) |
||||
require.NoError(t, err) |
||||
|
||||
err = srtConf.Validate() |
||||
require.NoError(t, err) |
||||
|
||||
reader, err := srt.Dial("srt", address, srtConf) |
||||
require.NoError(t, err) |
||||
defer reader.Close() |
||||
|
||||
stream.WriteUnit(desc.Medias[0], desc.Medias[0].Formats[0], &unit.H264{ |
||||
Base: unit.Base{ |
||||
NTP: time.Time{}, |
||||
}, |
||||
AU: [][]byte{ |
||||
{5, 1}, // IDR
|
||||
}, |
||||
}) |
||||
|
||||
r, err := mpegts.NewReader(reader) |
||||
require.NoError(t, err) |
||||
|
||||
require.Equal(t, []*mpegts.Track{{ |
||||
PID: 256, |
||||
Codec: &mpegts.CodecH264{}, |
||||
}}, r.Tracks()) |
||||
|
||||
received := false |
||||
|
||||
r.OnDataH26x(r.Tracks()[0], func(pts int64, dts int64, au [][]byte) error { |
||||
require.Equal(t, int64(0), pts) |
||||
require.Equal(t, int64(0), dts) |
||||
require.Equal(t, [][]byte{ |
||||
test.FormatH264.SPS, |
||||
test.FormatH264.PPS, |
||||
{0x05, 1}, |
||||
}, au) |
||||
received = true |
||||
return nil |
||||
}) |
||||
|
||||
stream.WriteUnit(desc.Medias[0], desc.Medias[0].Formats[0], &unit.H264{ |
||||
Base: unit.Base{ |
||||
NTP: time.Time{}, |
||||
}, |
||||
AU: [][]byte{ |
||||
{5, 2}, |
||||
}, |
||||
}) |
||||
|
||||
for { |
||||
err = r.Read() |
||||
require.NoError(t, err) |
||||
if received { |
||||
break |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,19 @@
@@ -0,0 +1,19 @@
|
||||
package test |
||||
|
||||
import "os" |
||||
|
||||
// CreateTempFile creates a temporary file with given content.
|
||||
func CreateTempFile(byts []byte) (string, error) { |
||||
tmpf, err := os.CreateTemp(os.TempDir(), "rtsp-") |
||||
if err != nil { |
||||
return "", err |
||||
} |
||||
defer tmpf.Close() |
||||
|
||||
_, err = tmpf.Write(byts) |
||||
if err != nil { |
||||
return "", err |
||||
} |
||||
|
||||
return tmpf.Name(), nil |
||||
} |
Loading…
Reference in new issue