mirror of
https://github.com/aler9/rtsp-simple-server
synced 2025-09-27 03:56:15 +08:00
@@ -39,8 +39,6 @@ import (
|
|||||||
//go:embed VERSION
|
//go:embed VERSION
|
||||||
var version []byte
|
var version []byte
|
||||||
|
|
||||||
var timeNow = time.Now
|
|
||||||
|
|
||||||
var defaultConfPaths = []string{
|
var defaultConfPaths = []string{
|
||||||
"rtsp-simple-server.yml",
|
"rtsp-simple-server.yml",
|
||||||
"mediamtx.yml",
|
"mediamtx.yml",
|
||||||
@@ -464,7 +462,6 @@ func (p *Core) createResources(initial bool) error {
|
|||||||
RunOnConnectRestart: p.conf.RunOnConnectRestart,
|
RunOnConnectRestart: p.conf.RunOnConnectRestart,
|
||||||
RunOnDisconnect: p.conf.RunOnDisconnect,
|
RunOnDisconnect: p.conf.RunOnDisconnect,
|
||||||
ExternalCmdPool: p.externalCmdPool,
|
ExternalCmdPool: p.externalCmdPool,
|
||||||
TimeNow: timeNow,
|
|
||||||
Metrics: p.metrics,
|
Metrics: p.metrics,
|
||||||
PathManager: p.pathManager,
|
PathManager: p.pathManager,
|
||||||
Parent: p,
|
Parent: p,
|
||||||
@@ -492,7 +489,6 @@ func (p *Core) createResources(initial bool) error {
|
|||||||
RunOnConnectRestart: p.conf.RunOnConnectRestart,
|
RunOnConnectRestart: p.conf.RunOnConnectRestart,
|
||||||
RunOnDisconnect: p.conf.RunOnDisconnect,
|
RunOnDisconnect: p.conf.RunOnDisconnect,
|
||||||
ExternalCmdPool: p.externalCmdPool,
|
ExternalCmdPool: p.externalCmdPool,
|
||||||
TimeNow: timeNow,
|
|
||||||
Metrics: p.metrics,
|
Metrics: p.metrics,
|
||||||
PathManager: p.pathManager,
|
PathManager: p.pathManager,
|
||||||
Parent: p,
|
Parent: p,
|
||||||
|
@@ -42,45 +42,35 @@ func httpPullFile(t *testing.T, hc *http.Client, u string) []byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestMetrics(t *testing.T) {
|
func TestMetrics(t *testing.T) {
|
||||||
|
serverCertFpath, err := test.CreateTempFile(test.TLSCertPub)
|
||||||
|
require.NoError(t, err)
|
||||||
|
defer os.Remove(serverCertFpath)
|
||||||
|
|
||||||
|
serverKeyFpath, err := test.CreateTempFile(test.TLSCertKey)
|
||||||
|
require.NoError(t, err)
|
||||||
|
defer os.Remove(serverKeyFpath)
|
||||||
|
|
||||||
|
p, ok := newInstance("api: yes\n" +
|
||||||
|
"hlsAlwaysRemux: yes\n" +
|
||||||
|
"metrics: yes\n" +
|
||||||
|
"webrtcServerCert: " + serverCertFpath + "\n" +
|
||||||
|
"webrtcServerKey: " + serverKeyFpath + "\n" +
|
||||||
|
"rtspEncryption: optional\n" +
|
||||||
|
"rtspServerCert: " + serverCertFpath + "\n" +
|
||||||
|
"rtspServerKey: " + serverKeyFpath + "\n" +
|
||||||
|
"rtmpEncryption: optional\n" +
|
||||||
|
"rtmpServerCert: " + serverCertFpath + "\n" +
|
||||||
|
"rtmpServerKey: " + serverKeyFpath + "\n" +
|
||||||
|
"paths:\n" +
|
||||||
|
" all_others:\n")
|
||||||
|
require.Equal(t, true, ok)
|
||||||
|
defer p.Close()
|
||||||
|
|
||||||
|
tr := &http.Transport{}
|
||||||
|
defer tr.CloseIdleConnections()
|
||||||
|
hc := &http.Client{Transport: tr}
|
||||||
|
|
||||||
t.Run("initial", func(t *testing.T) {
|
t.Run("initial", func(t *testing.T) {
|
||||||
serverCertFpath, err := test.CreateTempFile(test.TLSCertPub)
|
|
||||||
require.NoError(t, err)
|
|
||||||
defer os.Remove(serverCertFpath)
|
|
||||||
|
|
||||||
serverKeyFpath, err := test.CreateTempFile(test.TLSCertKey)
|
|
||||||
require.NoError(t, err)
|
|
||||||
defer os.Remove(serverKeyFpath)
|
|
||||||
|
|
||||||
n := 0
|
|
||||||
timeNow = func() time.Time {
|
|
||||||
d := time.Date(2009, 5, 20, 22, 15, 25, 427000, time.Local).Add(time.Duration(n) * 2 * time.Second)
|
|
||||||
n++
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
timeNow = time.Now
|
|
||||||
}()
|
|
||||||
|
|
||||||
p, ok := newInstance("api: yes\n" +
|
|
||||||
"hlsAlwaysRemux: yes\n" +
|
|
||||||
"metrics: yes\n" +
|
|
||||||
"webrtcServerCert: " + serverCertFpath + "\n" +
|
|
||||||
"webrtcServerKey: " + serverKeyFpath + "\n" +
|
|
||||||
"rtspEncryption: optional\n" +
|
|
||||||
"rtspServerCert: " + serverCertFpath + "\n" +
|
|
||||||
"rtspServerKey: " + serverKeyFpath + "\n" +
|
|
||||||
"rtmpEncryption: optional\n" +
|
|
||||||
"rtmpServerCert: " + serverCertFpath + "\n" +
|
|
||||||
"rtmpServerKey: " + serverKeyFpath + "\n" +
|
|
||||||
"paths:\n" +
|
|
||||||
" all_others:\n")
|
|
||||||
require.Equal(t, true, ok)
|
|
||||||
defer p.Close()
|
|
||||||
|
|
||||||
tr := &http.Transport{}
|
|
||||||
defer tr.CloseIdleConnections()
|
|
||||||
hc := &http.Client{Transport: tr}
|
|
||||||
|
|
||||||
bo := httpPullFile(t, hc, "http://localhost:9998/metrics")
|
bo := httpPullFile(t, hc, "http://localhost:9998/metrics")
|
||||||
|
|
||||||
require.Equal(t, `paths 0
|
require.Equal(t, `paths 0
|
||||||
@@ -179,44 +169,6 @@ webrtc_sessions_bytes_sent 0
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("with data", func(t *testing.T) {
|
t.Run("with data", func(t *testing.T) {
|
||||||
serverCertFpath, err := test.CreateTempFile(test.TLSCertPub)
|
|
||||||
require.NoError(t, err)
|
|
||||||
defer os.Remove(serverCertFpath)
|
|
||||||
|
|
||||||
serverKeyFpath, err := test.CreateTempFile(test.TLSCertKey)
|
|
||||||
require.NoError(t, err)
|
|
||||||
defer os.Remove(serverKeyFpath)
|
|
||||||
|
|
||||||
n := 0
|
|
||||||
timeNow = func() time.Time {
|
|
||||||
d := time.Date(2009, 5, 20, 22, 15, 25, 427000, time.Local).Add(time.Duration(n) * 2 * time.Second)
|
|
||||||
n++
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
timeNow = time.Now
|
|
||||||
}()
|
|
||||||
|
|
||||||
p, ok := newInstance("api: yes\n" +
|
|
||||||
"hlsAlwaysRemux: yes\n" +
|
|
||||||
"metrics: yes\n" +
|
|
||||||
"webrtcServerCert: " + serverCertFpath + "\n" +
|
|
||||||
"webrtcServerKey: " + serverKeyFpath + "\n" +
|
|
||||||
"rtspEncryption: optional\n" +
|
|
||||||
"rtspServerCert: " + serverCertFpath + "\n" +
|
|
||||||
"rtspServerKey: " + serverKeyFpath + "\n" +
|
|
||||||
"rtmpEncryption: optional\n" +
|
|
||||||
"rtmpServerCert: " + serverCertFpath + "\n" +
|
|
||||||
"rtmpServerKey: " + serverKeyFpath + "\n" +
|
|
||||||
"paths:\n" +
|
|
||||||
" all_others:\n")
|
|
||||||
require.Equal(t, true, ok)
|
|
||||||
defer p.Close()
|
|
||||||
|
|
||||||
tr := &http.Transport{}
|
|
||||||
defer tr.CloseIdleConnections()
|
|
||||||
hc := &http.Client{Transport: tr}
|
|
||||||
|
|
||||||
terminate := make(chan struct{})
|
terminate := make(chan struct{})
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
wg.Add(6)
|
wg.Add(6)
|
||||||
@@ -241,8 +193,6 @@ webrtc_sessions_bytes_sent 0
|
|||||||
<-terminate
|
<-terminate
|
||||||
}()
|
}()
|
||||||
|
|
||||||
rtmpDone := make(chan struct{})
|
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
|
|
||||||
@@ -267,16 +217,12 @@ webrtc_sessions_bytes_sent 0
|
|||||||
err = w.WriteH264(2*time.Second, 2*time.Second, [][]byte{{5, 2, 3, 4}})
|
err = w.WriteH264(2*time.Second, 2*time.Second, [][]byte{{5, 2, 3, 4}})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
close(rtmpDone)
|
|
||||||
|
|
||||||
<-terminate
|
<-terminate
|
||||||
}()
|
}()
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
|
|
||||||
<-rtmpDone
|
|
||||||
|
|
||||||
u, err := url.Parse("rtmps://localhost:1936/rtmps_path")
|
u, err := url.Parse("rtmps://localhost:1936/rtmps_path")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
@@ -302,8 +248,6 @@ webrtc_sessions_bytes_sent 0
|
|||||||
<-terminate
|
<-terminate
|
||||||
}()
|
}()
|
||||||
|
|
||||||
webrtcReady := make(chan struct{})
|
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
|
|
||||||
@@ -314,7 +258,7 @@ webrtc_sessions_bytes_sent 0
|
|||||||
defer tr.CloseIdleConnections()
|
defer tr.CloseIdleConnections()
|
||||||
hc2 := &http.Client{Transport: tr}
|
hc2 := &http.Client{Transport: tr}
|
||||||
|
|
||||||
track1 := &webrtc.OutgoingTrack{
|
track := &webrtc.OutgoingTrack{
|
||||||
Caps: pwebrtc.RTPCodecCapability{
|
Caps: pwebrtc.RTPCodecCapability{
|
||||||
MimeType: pwebrtc.MimeTypeH264,
|
MimeType: pwebrtc.MimeTypeH264,
|
||||||
ClockRate: 90000,
|
ClockRate: 90000,
|
||||||
@@ -322,44 +266,30 @@ webrtc_sessions_bytes_sent 0
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
track2 := &webrtc.OutgoingTrack{
|
|
||||||
Caps: pwebrtc.RTPCodecCapability{
|
|
||||||
MimeType: pwebrtc.MimeTypeOpus,
|
|
||||||
ClockRate: 48000,
|
|
||||||
Channels: 2,
|
|
||||||
SDPFmtpLine: "minptime=10;useinbandfec=1;stereo=1;sprop-stereo=1",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
s := &whip.Client{
|
s := &whip.Client{
|
||||||
HTTPClient: hc2,
|
HTTPClient: hc2,
|
||||||
URL: su,
|
URL: su,
|
||||||
Log: test.NilLogger,
|
Log: test.NilLogger,
|
||||||
Publish: true,
|
Publish: true,
|
||||||
OutgoingTracks: []*webrtc.OutgoingTrack{track1, track2},
|
OutgoingTracks: []*webrtc.OutgoingTrack{track},
|
||||||
}
|
}
|
||||||
|
|
||||||
err = s.Initialize(context.Background())
|
err = s.Initialize(context.Background())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
defer checkClose(t, s.Close)
|
defer checkClose(t, s.Close)
|
||||||
|
|
||||||
for _, track := range s.OutgoingTracks {
|
err = track.WriteRTP(&rtp.Packet{
|
||||||
err = track.WriteRTP(&rtp.Packet{
|
Header: rtp.Header{
|
||||||
Header: rtp.Header{
|
Version: 2,
|
||||||
Version: 2,
|
Marker: true,
|
||||||
Marker: true,
|
PayloadType: 96,
|
||||||
PayloadType: 96,
|
SequenceNumber: 123,
|
||||||
SequenceNumber: 123,
|
Timestamp: 45343,
|
||||||
Timestamp: 45343,
|
SSRC: 563423,
|
||||||
SSRC: 563423,
|
},
|
||||||
},
|
Payload: []byte{1},
|
||||||
Payload: []byte{1},
|
})
|
||||||
})
|
require.NoError(t, err)
|
||||||
require.NoError(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
close(webrtcReady)
|
|
||||||
|
|
||||||
<-terminate
|
<-terminate
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@@ -398,8 +328,7 @@ webrtc_sessions_bytes_sent 0
|
|||||||
<-terminate
|
<-terminate
|
||||||
}()
|
}()
|
||||||
|
|
||||||
<-webrtcReady
|
time.Sleep(500*time.Millisecond + 2*time.Second)
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
|
|
||||||
bo := httpPullFile(t, hc, "http://localhost:9998/metrics")
|
bo := httpPullFile(t, hc, "http://localhost:9998/metrics")
|
||||||
|
|
||||||
@@ -497,12 +426,12 @@ webrtc_sessions_bytes_sent 0
|
|||||||
`srt_conns_bytes_send_drop\{id=".*?",state="publish"\} [0-9]+`+"\n"+
|
`srt_conns_bytes_send_drop\{id=".*?",state="publish"\} [0-9]+`+"\n"+
|
||||||
`srt_conns_bytes_received_drop\{id=".*?",state="publish"\} [0-9]+`+"\n"+
|
`srt_conns_bytes_received_drop\{id=".*?",state="publish"\} [0-9]+`+"\n"+
|
||||||
`srt_conns_bytes_received_undecrypt\{id=".*?",state="publish"\} [0-9]+`+"\n"+
|
`srt_conns_bytes_received_undecrypt\{id=".*?",state="publish"\} [0-9]+`+"\n"+
|
||||||
`srt_conns_us_packets_send_period\{id=".*?",state="publish"\} \d+(\.\d+)?`+"\n"+
|
`srt_conns_us_packets_send_period\{id=".*?",state="publish"\} \d+\.\d+`+"\n"+
|
||||||
`srt_conns_packets_flow_window\{id=".*?",state="publish"\} [0-9]+`+"\n"+
|
`srt_conns_packets_flow_window\{id=".*?",state="publish"\} [0-9]+`+"\n"+
|
||||||
`srt_conns_packets_flight_size\{id=".*?",state="publish"\} [0-9]+`+"\n"+
|
`srt_conns_packets_flight_size\{id=".*?",state="publish"\} [0-9]+`+"\n"+
|
||||||
`srt_conns_ms_rtt\{id=".*?",state="publish"\} \d+(\.\d+)?`+"\n"+
|
`srt_conns_ms_rtt\{id=".*?",state="publish"\} \d+\.\d+`+"\n"+
|
||||||
`srt_conns_mbps_send_rate\{id=".*?",state="publish"\} [0-9]+`+"\n"+
|
`srt_conns_mbps_send_rate\{id=".*?",state="publish"\} [0-9]+`+"\n"+
|
||||||
`srt_conns_mbps_receive_rate\{id=".*?",state="publish"\} \d+(\.\d+)?`+"\n"+
|
`srt_conns_mbps_receive_rate\{id=".*?",state="publish"\} [0-9]+`+"\n"+
|
||||||
`srt_conns_mbps_link_capacity\{id=".*?",state="publish"\} [0-9]+`+"\n"+
|
`srt_conns_mbps_link_capacity\{id=".*?",state="publish"\} [0-9]+`+"\n"+
|
||||||
`srt_conns_bytes_avail_send_buf\{id=".*?",state="publish"\} [0-9]+`+"\n"+
|
`srt_conns_bytes_avail_send_buf\{id=".*?",state="publish"\} [0-9]+`+"\n"+
|
||||||
`srt_conns_bytes_avail_receive_buf\{id=".*?",state="publish"\} [0-9]+`+"\n"+
|
`srt_conns_bytes_avail_receive_buf\{id=".*?",state="publish"\} [0-9]+`+"\n"+
|
||||||
@@ -531,44 +460,6 @@ webrtc_sessions_bytes_sent 0
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("servers disabled", func(t *testing.T) {
|
t.Run("servers disabled", func(t *testing.T) {
|
||||||
serverCertFpath, err := test.CreateTempFile(test.TLSCertPub)
|
|
||||||
require.NoError(t, err)
|
|
||||||
defer os.Remove(serverCertFpath)
|
|
||||||
|
|
||||||
serverKeyFpath, err := test.CreateTempFile(test.TLSCertKey)
|
|
||||||
require.NoError(t, err)
|
|
||||||
defer os.Remove(serverKeyFpath)
|
|
||||||
|
|
||||||
n := 0
|
|
||||||
timeNow = func() time.Time {
|
|
||||||
d := time.Date(2009, 5, 20, 22, 15, 25, 427000, time.Local).Add(time.Duration(n) * 2 * time.Second)
|
|
||||||
n++
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
timeNow = time.Now
|
|
||||||
}()
|
|
||||||
|
|
||||||
p, ok := newInstance("api: yes\n" +
|
|
||||||
"hlsAlwaysRemux: yes\n" +
|
|
||||||
"metrics: yes\n" +
|
|
||||||
"webrtcServerCert: " + serverCertFpath + "\n" +
|
|
||||||
"webrtcServerKey: " + serverKeyFpath + "\n" +
|
|
||||||
"rtspEncryption: optional\n" +
|
|
||||||
"rtspServerCert: " + serverCertFpath + "\n" +
|
|
||||||
"rtspServerKey: " + serverKeyFpath + "\n" +
|
|
||||||
"rtmpEncryption: optional\n" +
|
|
||||||
"rtmpServerCert: " + serverCertFpath + "\n" +
|
|
||||||
"rtmpServerKey: " + serverKeyFpath + "\n" +
|
|
||||||
"paths:\n" +
|
|
||||||
" all_others:\n")
|
|
||||||
require.Equal(t, true, ok)
|
|
||||||
defer p.Close()
|
|
||||||
|
|
||||||
tr := &http.Transport{}
|
|
||||||
defer tr.CloseIdleConnections()
|
|
||||||
hc := &http.Client{Transport: tr}
|
|
||||||
|
|
||||||
httpRequest(t, hc, http.MethodPatch, "http://localhost:9997/v3/config/global/patch", map[string]interface{}{
|
httpRequest(t, hc, http.MethodPatch, "http://localhost:9997/v3/config/global/patch", map[string]interface{}{
|
||||||
"rtsp": false,
|
"rtsp": false,
|
||||||
"rtmp": false,
|
"rtmp": false,
|
||||||
|
@@ -447,16 +447,8 @@ func TestPathRunOnRead(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
n := 0
|
|
||||||
timeNow := func() time.Time {
|
|
||||||
d := time.Date(2009, 5, 20, 22, 15, 25, 427000, time.Local).Add(time.Duration(n) * 2 * time.Second)
|
|
||||||
n++
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
r := &rtmp.Reader{
|
r := &rtmp.Reader{
|
||||||
Conn: conn,
|
Conn: conn,
|
||||||
TimeNow: timeNow,
|
|
||||||
}
|
}
|
||||||
err = r.Initialize()
|
err = r.Initialize()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@@ -491,16 +483,8 @@ func TestPathRunOnRead(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
n := 0
|
|
||||||
timeNow := func() time.Time {
|
|
||||||
d := time.Date(2009, 5, 20, 22, 15, 25, 427000, time.Local).Add(time.Duration(n) * 2 * time.Second)
|
|
||||||
n++
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
r := &rtmp.Reader{
|
r := &rtmp.Reader{
|
||||||
Conn: conn,
|
Conn: conn,
|
||||||
TimeNow: timeNow,
|
|
||||||
}
|
}
|
||||||
err = r.Initialize()
|
err = r.Initialize()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@@ -272,8 +272,7 @@ func sortedKeys(m map[uint8]format.Format) []int {
|
|||||||
|
|
||||||
// Reader provides functions to read incoming data.
|
// Reader provides functions to read incoming data.
|
||||||
type Reader struct {
|
type Reader struct {
|
||||||
Conn Conn
|
Conn Conn
|
||||||
TimeNow func() time.Time
|
|
||||||
|
|
||||||
videoTracks map[uint8]format.Format
|
videoTracks map[uint8]format.Format
|
||||||
audioTracks map[uint8]format.Format
|
audioTracks map[uint8]format.Format
|
||||||
@@ -283,10 +282,6 @@ type Reader struct {
|
|||||||
|
|
||||||
// Initialize initializes Reader.
|
// Initialize initializes Reader.
|
||||||
func (r *Reader) Initialize() error {
|
func (r *Reader) Initialize() error {
|
||||||
if r.TimeNow == nil {
|
|
||||||
r.TimeNow = time.Now
|
|
||||||
}
|
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
r.videoTracks, r.audioTracks, err = r.readTracks()
|
r.videoTracks, r.audioTracks, err = r.readTracks()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -301,8 +296,8 @@ func (r *Reader) Initialize() error {
|
|||||||
|
|
||||||
func (r *Reader) readTracks() (map[uint8]format.Format, map[uint8]format.Format, error) {
|
func (r *Reader) readTracks() (map[uint8]format.Format, map[uint8]format.Format, error) {
|
||||||
firstReceived := false
|
firstReceived := false
|
||||||
var startTime time.Time
|
var startTime time.Duration
|
||||||
var curTime time.Time
|
var curTime time.Duration
|
||||||
|
|
||||||
videoTracks := make(map[uint8]format.Format)
|
videoTracks := make(map[uint8]format.Format)
|
||||||
audioTracks := make(map[uint8]format.Format)
|
audioTracks := make(map[uint8]format.Format)
|
||||||
@@ -321,23 +316,21 @@ func (r *Reader) readTracks() (map[uint8]format.Format, map[uint8]format.Format,
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
handleVideoExCodedFrames := func(_ uint8, _ *message.VideoExCodedFrames) error {
|
handleVideoExCodedFrames := func(_ uint8, msg *message.VideoExCodedFrames) error {
|
||||||
now := r.TimeNow()
|
|
||||||
if !firstReceived {
|
if !firstReceived {
|
||||||
firstReceived = true
|
firstReceived = true
|
||||||
startTime = now
|
startTime = msg.DTS
|
||||||
}
|
}
|
||||||
curTime = now
|
curTime = msg.DTS
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
handleVideoExFramesX := func(_ uint8, _ *message.VideoExFramesX) error {
|
handleVideoExFramesX := func(_ uint8, msg *message.VideoExFramesX) error {
|
||||||
now := r.TimeNow()
|
|
||||||
if !firstReceived {
|
if !firstReceived {
|
||||||
firstReceived = true
|
firstReceived = true
|
||||||
startTime = now
|
startTime = msg.DTS
|
||||||
}
|
}
|
||||||
curTime = now
|
curTime = msg.DTS
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -353,12 +346,11 @@ func (r *Reader) readTracks() (map[uint8]format.Format, map[uint8]format.Format,
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleAudioCodedFrames := func(trackID uint8, msg *message.AudioExCodedFrames) error {
|
handleAudioCodedFrames := func(trackID uint8, msg *message.AudioExCodedFrames) error {
|
||||||
now := r.TimeNow()
|
|
||||||
if !firstReceived {
|
if !firstReceived {
|
||||||
firstReceived = true
|
firstReceived = true
|
||||||
startTime = now
|
startTime = msg.DTS
|
||||||
}
|
}
|
||||||
curTime = now
|
curTime = msg.DTS
|
||||||
|
|
||||||
if audioTracks[trackID] != nil {
|
if audioTracks[trackID] != nil {
|
||||||
return nil
|
return nil
|
||||||
@@ -381,12 +373,11 @@ func (r *Reader) readTracks() (map[uint8]format.Format, map[uint8]format.Format,
|
|||||||
|
|
||||||
switch msg := msg.(type) {
|
switch msg := msg.(type) {
|
||||||
case *message.Video:
|
case *message.Video:
|
||||||
now := r.TimeNow()
|
|
||||||
if !firstReceived {
|
if !firstReceived {
|
||||||
firstReceived = true
|
firstReceived = true
|
||||||
startTime = now
|
startTime = msg.DTS
|
||||||
}
|
}
|
||||||
curTime = now
|
curTime = msg.DTS
|
||||||
|
|
||||||
if msg.Type == message.VideoTypeConfig && videoTracks[0] == nil {
|
if msg.Type == message.VideoTypeConfig && videoTracks[0] == nil {
|
||||||
videoTracks[0], err = h264TrackFromConfig(msg.Payload)
|
videoTracks[0], err = h264TrackFromConfig(msg.Payload)
|
||||||
@@ -439,12 +430,11 @@ func (r *Reader) readTracks() (map[uint8]format.Format, map[uint8]format.Format,
|
|||||||
}
|
}
|
||||||
|
|
||||||
case *message.Audio:
|
case *message.Audio:
|
||||||
now := r.TimeNow()
|
|
||||||
if !firstReceived {
|
if !firstReceived {
|
||||||
firstReceived = true
|
firstReceived = true
|
||||||
startTime = now
|
startTime = msg.DTS
|
||||||
}
|
}
|
||||||
curTime = now
|
curTime = msg.DTS
|
||||||
|
|
||||||
if audioTracks[0] == nil && len(msg.Payload) != 0 {
|
if audioTracks[0] == nil && len(msg.Payload) != 0 {
|
||||||
if msg.Codec == message.CodecMPEG4Audio {
|
if msg.Codec == message.CodecMPEG4Audio {
|
||||||
@@ -494,7 +484,7 @@ func (r *Reader) readTracks() (map[uint8]format.Format, map[uint8]format.Format,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if curTime.Sub(startTime) >= analyzePeriod {
|
if (curTime - startTime) >= analyzePeriod {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1635,52 +1635,8 @@ func TestReadTracks(t *testing.T) {
|
|||||||
}
|
}
|
||||||
c.initialize()
|
c.initialize()
|
||||||
|
|
||||||
n := time.Duration(0)
|
|
||||||
|
|
||||||
TimeNow := func() time.Time {
|
|
||||||
var d time.Time
|
|
||||||
|
|
||||||
outer:
|
|
||||||
for {
|
|
||||||
msg := ca.messages[n]
|
|
||||||
n++
|
|
||||||
|
|
||||||
switch msg := msg.(type) {
|
|
||||||
case *message.Video:
|
|
||||||
d = time.Date(2008, 10, 28, 13, 11, 12, 0, time.UTC).Add(msg.DTS)
|
|
||||||
break outer
|
|
||||||
case *message.VideoExCodedFrames:
|
|
||||||
d = time.Date(2008, 10, 28, 13, 11, 12, 0, time.UTC).Add(msg.DTS)
|
|
||||||
break outer
|
|
||||||
case *message.VideoExMultitrack:
|
|
||||||
msg2 := msg.Wrapped
|
|
||||||
switch msg2 := msg2.(type) {
|
|
||||||
case *message.VideoExCodedFrames:
|
|
||||||
d = time.Date(2008, 10, 28, 13, 11, 12, 0, time.UTC).Add(msg2.DTS)
|
|
||||||
break outer
|
|
||||||
}
|
|
||||||
case *message.Audio:
|
|
||||||
d = time.Date(2008, 10, 28, 13, 11, 12, 0, time.UTC).Add(msg.DTS)
|
|
||||||
break outer
|
|
||||||
case *message.AudioExCodedFrames:
|
|
||||||
d = time.Date(2008, 10, 28, 13, 11, 12, 0, time.UTC).Add(msg.DTS)
|
|
||||||
break outer
|
|
||||||
case *message.AudioExMultitrack:
|
|
||||||
msg2 := msg.Wrapped
|
|
||||||
switch msg2 := msg2.(type) {
|
|
||||||
case *message.AudioExCodedFrames:
|
|
||||||
d = time.Date(2008, 10, 28, 13, 11, 12, 0, time.UTC).Add(msg2.DTS)
|
|
||||||
break outer
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
r := &Reader{
|
r := &Reader{
|
||||||
Conn: c,
|
Conn: c,
|
||||||
TimeNow: TimeNow,
|
|
||||||
}
|
}
|
||||||
err = r.Initialize()
|
err = r.Initialize()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@@ -41,7 +41,6 @@ type conn struct {
|
|||||||
wg *sync.WaitGroup
|
wg *sync.WaitGroup
|
||||||
nconn net.Conn
|
nconn net.Conn
|
||||||
externalCmdPool *externalcmd.Pool
|
externalCmdPool *externalcmd.Pool
|
||||||
timeNow func() time.Time
|
|
||||||
pathManager serverPathManager
|
pathManager serverPathManager
|
||||||
parent *Server
|
parent *Server
|
||||||
|
|
||||||
@@ -260,8 +259,7 @@ func (c *conn) runPublish() error {
|
|||||||
c.mutex.Unlock()
|
c.mutex.Unlock()
|
||||||
|
|
||||||
r := &rtmp.Reader{
|
r := &rtmp.Reader{
|
||||||
Conn: c.rconn,
|
Conn: c.rconn,
|
||||||
TimeNow: c.timeNow,
|
|
||||||
}
|
}
|
||||||
err = r.Initialize()
|
err = r.Initialize()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@@ -10,7 +10,6 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"sort"
|
"sort"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
|
||||||
@@ -85,7 +84,6 @@ type Server struct {
|
|||||||
RunOnConnectRestart bool
|
RunOnConnectRestart bool
|
||||||
RunOnDisconnect string
|
RunOnDisconnect string
|
||||||
ExternalCmdPool *externalcmd.Pool
|
ExternalCmdPool *externalcmd.Pool
|
||||||
TimeNow func() time.Time
|
|
||||||
Metrics serverMetrics
|
Metrics serverMetrics
|
||||||
PathManager serverPathManager
|
PathManager serverPathManager
|
||||||
Parent serverParent
|
Parent serverParent
|
||||||
@@ -218,7 +216,6 @@ outer:
|
|||||||
wg: &s.wg,
|
wg: &s.wg,
|
||||||
nconn: nconn,
|
nconn: nconn,
|
||||||
externalCmdPool: s.ExternalCmdPool,
|
externalCmdPool: s.ExternalCmdPool,
|
||||||
timeNow: s.TimeNow,
|
|
||||||
pathManager: s.PathManager,
|
pathManager: s.PathManager,
|
||||||
parent: s,
|
parent: s,
|
||||||
}
|
}
|
||||||
|
@@ -97,13 +97,6 @@ func TestServerPublish(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
n := 0
|
|
||||||
timeNow := func() time.Time {
|
|
||||||
d := time.Date(2009, 5, 20, 22, 15, 25, 427000, time.Local).Add(time.Duration(n) * 2 * time.Second)
|
|
||||||
n++
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
s := &Server{
|
s := &Server{
|
||||||
Address: "127.0.0.1:1935",
|
Address: "127.0.0.1:1935",
|
||||||
ReadTimeout: conf.Duration(10 * time.Second),
|
ReadTimeout: conf.Duration(10 * time.Second),
|
||||||
@@ -116,7 +109,6 @@ func TestServerPublish(t *testing.T) {
|
|||||||
RunOnConnectRestart: false,
|
RunOnConnectRestart: false,
|
||||||
RunOnDisconnect: "",
|
RunOnDisconnect: "",
|
||||||
ExternalCmdPool: nil,
|
ExternalCmdPool: nil,
|
||||||
TimeNow: timeNow,
|
|
||||||
PathManager: pathManager,
|
PathManager: pathManager,
|
||||||
Parent: test.NilLogger,
|
Parent: test.NilLogger,
|
||||||
}
|
}
|
||||||
@@ -154,6 +146,12 @@ func TestServerPublish(t *testing.T) {
|
|||||||
err = w.Initialize()
|
err = w.Initialize()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
err = w.WriteH264(
|
||||||
|
2*time.Second, 2*time.Second, [][]byte{
|
||||||
|
{5, 2, 3, 4},
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
<-path.streamCreated
|
<-path.streamCreated
|
||||||
|
|
||||||
recv := make(chan struct{})
|
recv := make(chan struct{})
|
||||||
@@ -168,7 +166,7 @@ func TestServerPublish(t *testing.T) {
|
|||||||
require.Equal(t, [][]byte{
|
require.Equal(t, [][]byte{
|
||||||
test.FormatH264.SPS,
|
test.FormatH264.SPS,
|
||||||
test.FormatH264.PPS,
|
test.FormatH264.PPS,
|
||||||
{5, 6, 7, 8},
|
{5, 2, 3, 4},
|
||||||
}, u.(*unit.H264).AU)
|
}, u.(*unit.H264).AU)
|
||||||
close(recv)
|
close(recv)
|
||||||
return nil
|
return nil
|
||||||
@@ -179,7 +177,7 @@ func TestServerPublish(t *testing.T) {
|
|||||||
|
|
||||||
err = w.WriteH264(
|
err = w.WriteH264(
|
||||||
3*time.Second, 3*time.Second, [][]byte{
|
3*time.Second, 3*time.Second, [][]byte{
|
||||||
{5, 6, 7, 8},
|
{5, 2, 3, 4},
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
@@ -305,16 +303,8 @@ func TestServerRead(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}()
|
}()
|
||||||
|
|
||||||
n := 0
|
|
||||||
timeNow := func() time.Time {
|
|
||||||
d := time.Date(2009, 5, 20, 22, 15, 25, 427000, time.Local).Add(time.Duration(n) * 2 * time.Second)
|
|
||||||
n++
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
r := &rtmp.Reader{
|
r := &rtmp.Reader{
|
||||||
Conn: conn,
|
Conn: conn,
|
||||||
TimeNow: timeNow,
|
|
||||||
}
|
}
|
||||||
err = r.Initialize()
|
err = r.Initialize()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@@ -18,8 +18,6 @@ import (
|
|||||||
"github.com/bluenviron/mediamtx/internal/stream"
|
"github.com/bluenviron/mediamtx/internal/stream"
|
||||||
)
|
)
|
||||||
|
|
||||||
var timeNow = time.Now
|
|
||||||
|
|
||||||
// Source is a RTMP static source.
|
// Source is a RTMP static source.
|
||||||
type Source struct {
|
type Source struct {
|
||||||
ReadTimeout conf.Duration
|
ReadTimeout conf.Duration
|
||||||
@@ -88,8 +86,7 @@ func (s *Source) runReader(ctx context.Context, u *url.URL, fingerprint string)
|
|||||||
}
|
}
|
||||||
|
|
||||||
r := &rtmp.Reader{
|
r := &rtmp.Reader{
|
||||||
Conn: conn,
|
Conn: conn,
|
||||||
TimeNow: timeNow,
|
|
||||||
}
|
}
|
||||||
err = r.Initialize()
|
err = r.Initialize()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@@ -83,6 +83,9 @@ func TestSource(t *testing.T) {
|
|||||||
err = w.WriteH264(2*time.Second, 2*time.Second, [][]byte{{5, 2, 3, 4}})
|
err = w.WriteH264(2*time.Second, 2*time.Second, [][]byte{{5, 2, 3, 4}})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
err = w.WriteH264(3*time.Second, 3*time.Second, [][]byte{{5, 2, 3, 4}})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
@@ -101,16 +104,6 @@ func TestSource(t *testing.T) {
|
|||||||
|
|
||||||
source += "localhost/teststream"
|
source += "localhost/teststream"
|
||||||
|
|
||||||
n := 0
|
|
||||||
timeNow = func() time.Time {
|
|
||||||
d := time.Date(2009, 5, 20, 22, 15, 25, 427000, time.Local).Add(time.Duration(n) * 2 * time.Second)
|
|
||||||
n++
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
timeNow = time.Now
|
|
||||||
}()
|
|
||||||
|
|
||||||
te := test.NewSourceTester(
|
te := test.NewSourceTester(
|
||||||
func(p defs.StaticSourceParent) defs.StaticSource {
|
func(p defs.StaticSourceParent) defs.StaticSource {
|
||||||
return &Source{
|
return &Source{
|
||||||
|
Reference in New Issue
Block a user