golanggohlsrtmpwebrtcmedia-serverobs-studiortcprtmp-proxyrtmp-serverrtprtsprtsp-proxyrtsp-relayrtsp-serversrtstreamingwebrtc-proxy
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
268 lines
5.9 KiB
268 lines
5.9 KiB
package srt |
|
|
|
import ( |
|
"bufio" |
|
"testing" |
|
"time" |
|
|
|
"github.com/bluenviron/gortsplib/v4/pkg/description" |
|
"github.com/bluenviron/mediacommon/pkg/formats/mpegts" |
|
"github.com/bluenviron/mediamtx/internal/asyncwriter" |
|
"github.com/bluenviron/mediamtx/internal/auth" |
|
"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(req defs.PathAddPublisherReq) (defs.Path, error) { |
|
if req.AccessRequest.User != "myuser" || req.AccessRequest.Pass != "mypass" { |
|
return nil, auth.Error{} |
|
} |
|
return pm.path, nil |
|
} |
|
|
|
func (pm *dummyPathManager) AddReader(req defs.PathAddReaderReq) (defs.Path, *stream.Stream, error) { |
|
if req.AccessRequest.User != "myuser" || req.AccessRequest.Pass != "mypass" { |
|
return nil, nil, auth.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:myuser:mypass" |
|
|
|
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() |
|
|
|
desc := &description.Session{Medias: []*description.Media{test.MediaH264}} |
|
|
|
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:myuser:mypass" |
|
|
|
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 |
|
} |
|
} |
|
}
|
|
|