mirror of
https://github.com/aler9/rtsp-simple-server
synced 2025-10-14 19:57:31 +08:00
hls: fix toggling hlsAlwaysRemux after server is started (#4503)
When hlsAlwaysRemux was switched from false to true, through API or hot reloading, muxers of existing paths were not created. This fixes the issue.
This commit is contained in:
@@ -77,48 +77,6 @@ func recordingsOfPath(
|
|||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
// PathManager contains methods used by the API and Metrics server.
|
|
||||||
type PathManager interface {
|
|
||||||
APIPathsList() (*defs.APIPathList, error)
|
|
||||||
APIPathsGet(string) (*defs.APIPath, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// HLSServer contains methods used by the API and Metrics server.
|
|
||||||
type HLSServer interface {
|
|
||||||
APIMuxersList() (*defs.APIHLSMuxerList, error)
|
|
||||||
APIMuxersGet(string) (*defs.APIHLSMuxer, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RTSPServer contains methods used by the API and Metrics server.
|
|
||||||
type RTSPServer interface {
|
|
||||||
APIConnsList() (*defs.APIRTSPConnsList, error)
|
|
||||||
APIConnsGet(uuid.UUID) (*defs.APIRTSPConn, error)
|
|
||||||
APISessionsList() (*defs.APIRTSPSessionList, error)
|
|
||||||
APISessionsGet(uuid.UUID) (*defs.APIRTSPSession, error)
|
|
||||||
APISessionsKick(uuid.UUID) error
|
|
||||||
}
|
|
||||||
|
|
||||||
// RTMPServer contains methods used by the API and Metrics server.
|
|
||||||
type RTMPServer interface {
|
|
||||||
APIConnsList() (*defs.APIRTMPConnList, error)
|
|
||||||
APIConnsGet(uuid.UUID) (*defs.APIRTMPConn, error)
|
|
||||||
APIConnsKick(uuid.UUID) error
|
|
||||||
}
|
|
||||||
|
|
||||||
// SRTServer contains methods used by the API and Metrics server.
|
|
||||||
type SRTServer interface {
|
|
||||||
APIConnsList() (*defs.APISRTConnList, error)
|
|
||||||
APIConnsGet(uuid.UUID) (*defs.APISRTConn, error)
|
|
||||||
APIConnsKick(uuid.UUID) error
|
|
||||||
}
|
|
||||||
|
|
||||||
// WebRTCServer contains methods used by the API and Metrics server.
|
|
||||||
type WebRTCServer interface {
|
|
||||||
APISessionsList() (*defs.APIWebRTCSessionList, error)
|
|
||||||
APISessionsGet(uuid.UUID) (*defs.APIWebRTCSession, error)
|
|
||||||
APISessionsKick(uuid.UUID) error
|
|
||||||
}
|
|
||||||
|
|
||||||
type apiAuthManager interface {
|
type apiAuthManager interface {
|
||||||
Authenticate(req *auth.Request) error
|
Authenticate(req *auth.Request) error
|
||||||
}
|
}
|
||||||
@@ -139,14 +97,14 @@ type API struct {
|
|||||||
ReadTimeout conf.Duration
|
ReadTimeout conf.Duration
|
||||||
Conf *conf.Conf
|
Conf *conf.Conf
|
||||||
AuthManager apiAuthManager
|
AuthManager apiAuthManager
|
||||||
PathManager PathManager
|
PathManager defs.APIPathManager
|
||||||
RTSPServer RTSPServer
|
RTSPServer defs.APIRTSPServer
|
||||||
RTSPSServer RTSPServer
|
RTSPSServer defs.APIRTSPServer
|
||||||
RTMPServer RTMPServer
|
RTMPServer defs.APIRTMPServer
|
||||||
RTMPSServer RTMPServer
|
RTMPSServer defs.APIRTMPServer
|
||||||
HLSServer HLSServer
|
HLSServer defs.APIHLSServer
|
||||||
WebRTCServer WebRTCServer
|
WebRTCServer defs.APIWebRTCServer
|
||||||
SRTServer SRTServer
|
SRTServer defs.APISRTServer
|
||||||
Parent apiParent
|
Parent apiParent
|
||||||
|
|
||||||
httpServer *httpp.Server
|
httpServer *httpp.Server
|
||||||
|
@@ -361,13 +361,10 @@ func (p *Core) createResources(initial bool) error {
|
|||||||
udpMaxPayloadSize: p.conf.UDPMaxPayloadSize,
|
udpMaxPayloadSize: p.conf.UDPMaxPayloadSize,
|
||||||
pathConfs: p.conf.Paths,
|
pathConfs: p.conf.Paths,
|
||||||
externalCmdPool: p.externalCmdPool,
|
externalCmdPool: p.externalCmdPool,
|
||||||
|
metrics: p.metrics,
|
||||||
parent: p,
|
parent: p,
|
||||||
}
|
}
|
||||||
p.pathManager.initialize()
|
p.pathManager.initialize()
|
||||||
|
|
||||||
if p.metrics != nil {
|
|
||||||
p.metrics.SetPathManager(p.pathManager)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.conf.RTSP &&
|
if p.conf.RTSP &&
|
||||||
@@ -399,6 +396,7 @@ 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,
|
||||||
|
Metrics: p.metrics,
|
||||||
PathManager: p.pathManager,
|
PathManager: p.pathManager,
|
||||||
Parent: p,
|
Parent: p,
|
||||||
}
|
}
|
||||||
@@ -407,10 +405,6 @@ func (p *Core) createResources(initial bool) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
p.rtspServer = i
|
p.rtspServer = i
|
||||||
|
|
||||||
if p.metrics != nil {
|
|
||||||
p.metrics.SetRTSPServer(p.rtspServer)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.conf.RTSP &&
|
if p.conf.RTSP &&
|
||||||
@@ -439,6 +433,7 @@ 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,
|
||||||
|
Metrics: p.metrics,
|
||||||
PathManager: p.pathManager,
|
PathManager: p.pathManager,
|
||||||
Parent: p,
|
Parent: p,
|
||||||
}
|
}
|
||||||
@@ -447,10 +442,6 @@ func (p *Core) createResources(initial bool) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
p.rtspsServer = i
|
p.rtspsServer = i
|
||||||
|
|
||||||
if p.metrics != nil {
|
|
||||||
p.metrics.SetRTSPSServer(p.rtspsServer)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.conf.RTMP &&
|
if p.conf.RTMP &&
|
||||||
@@ -469,6 +460,7 @@ 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,
|
||||||
|
Metrics: p.metrics,
|
||||||
PathManager: p.pathManager,
|
PathManager: p.pathManager,
|
||||||
Parent: p,
|
Parent: p,
|
||||||
}
|
}
|
||||||
@@ -477,10 +469,6 @@ func (p *Core) createResources(initial bool) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
p.rtmpServer = i
|
p.rtmpServer = i
|
||||||
|
|
||||||
if p.metrics != nil {
|
|
||||||
p.metrics.SetRTMPServer(p.rtmpServer)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.conf.RTMP &&
|
if p.conf.RTMP &&
|
||||||
@@ -499,6 +487,7 @@ 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,
|
||||||
|
Metrics: p.metrics,
|
||||||
PathManager: p.pathManager,
|
PathManager: p.pathManager,
|
||||||
Parent: p,
|
Parent: p,
|
||||||
}
|
}
|
||||||
@@ -507,10 +496,6 @@ func (p *Core) createResources(initial bool) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
p.rtmpsServer = i
|
p.rtmpsServer = i
|
||||||
|
|
||||||
if p.metrics != nil {
|
|
||||||
p.metrics.SetRTMPSServer(p.rtmpsServer)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.conf.HLS &&
|
if p.conf.HLS &&
|
||||||
@@ -531,6 +516,7 @@ func (p *Core) createResources(initial bool) error {
|
|||||||
Directory: p.conf.HLSDirectory,
|
Directory: p.conf.HLSDirectory,
|
||||||
ReadTimeout: p.conf.ReadTimeout,
|
ReadTimeout: p.conf.ReadTimeout,
|
||||||
MuxerCloseAfter: p.conf.HLSMuxerCloseAfter,
|
MuxerCloseAfter: p.conf.HLSMuxerCloseAfter,
|
||||||
|
Metrics: p.metrics,
|
||||||
PathManager: p.pathManager,
|
PathManager: p.pathManager,
|
||||||
Parent: p,
|
Parent: p,
|
||||||
}
|
}
|
||||||
@@ -539,12 +525,6 @@ func (p *Core) createResources(initial bool) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
p.hlsServer = i
|
p.hlsServer = i
|
||||||
|
|
||||||
p.pathManager.setHLSServer(p.hlsServer)
|
|
||||||
|
|
||||||
if p.metrics != nil {
|
|
||||||
p.metrics.SetHLSServer(p.hlsServer)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.conf.WebRTC &&
|
if p.conf.WebRTC &&
|
||||||
@@ -567,6 +547,7 @@ func (p *Core) createResources(initial bool) error {
|
|||||||
STUNGatherTimeout: p.conf.WebRTCSTUNGatherTimeout,
|
STUNGatherTimeout: p.conf.WebRTCSTUNGatherTimeout,
|
||||||
TrackGatherTimeout: p.conf.WebRTCTrackGatherTimeout,
|
TrackGatherTimeout: p.conf.WebRTCTrackGatherTimeout,
|
||||||
ExternalCmdPool: p.externalCmdPool,
|
ExternalCmdPool: p.externalCmdPool,
|
||||||
|
Metrics: p.metrics,
|
||||||
PathManager: p.pathManager,
|
PathManager: p.pathManager,
|
||||||
Parent: p,
|
Parent: p,
|
||||||
}
|
}
|
||||||
@@ -575,10 +556,6 @@ func (p *Core) createResources(initial bool) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
p.webRTCServer = i
|
p.webRTCServer = i
|
||||||
|
|
||||||
if p.metrics != nil {
|
|
||||||
p.metrics.SetWebRTCServer(p.webRTCServer)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.conf.SRT &&
|
if p.conf.SRT &&
|
||||||
@@ -593,6 +570,7 @@ 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,
|
||||||
|
Metrics: p.metrics,
|
||||||
PathManager: p.pathManager,
|
PathManager: p.pathManager,
|
||||||
Parent: p,
|
Parent: p,
|
||||||
}
|
}
|
||||||
@@ -601,10 +579,6 @@ func (p *Core) createResources(initial bool) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
p.srtServer = i
|
p.srtServer = i
|
||||||
|
|
||||||
if p.metrics != nil {
|
|
||||||
p.metrics.SetSRTServer(p.srtServer)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.conf.API &&
|
if p.conf.API &&
|
||||||
@@ -887,75 +861,41 @@ func (p *Core) closeResources(newConf *conf.Conf, calledByAPI bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if closeSRTServer && p.srtServer != nil {
|
if closeSRTServer && p.srtServer != nil {
|
||||||
if p.metrics != nil {
|
|
||||||
p.metrics.SetSRTServer(nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
p.srtServer.Close()
|
p.srtServer.Close()
|
||||||
p.srtServer = nil
|
p.srtServer = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if closeWebRTCServer && p.webRTCServer != nil {
|
if closeWebRTCServer && p.webRTCServer != nil {
|
||||||
if p.metrics != nil {
|
|
||||||
p.metrics.SetWebRTCServer(nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
p.webRTCServer.Close()
|
p.webRTCServer.Close()
|
||||||
p.webRTCServer = nil
|
p.webRTCServer = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if closeHLSServer && p.hlsServer != nil {
|
if closeHLSServer && p.hlsServer != nil {
|
||||||
if p.metrics != nil {
|
|
||||||
p.metrics.SetHLSServer(nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
p.pathManager.setHLSServer(nil)
|
|
||||||
|
|
||||||
p.hlsServer.Close()
|
p.hlsServer.Close()
|
||||||
p.hlsServer = nil
|
p.hlsServer = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if closeRTMPSServer && p.rtmpsServer != nil {
|
if closeRTMPSServer && p.rtmpsServer != nil {
|
||||||
if p.metrics != nil {
|
|
||||||
p.metrics.SetRTMPSServer(nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
p.rtmpsServer.Close()
|
p.rtmpsServer.Close()
|
||||||
p.rtmpsServer = nil
|
p.rtmpsServer = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if closeRTMPServer && p.rtmpServer != nil {
|
if closeRTMPServer && p.rtmpServer != nil {
|
||||||
if p.metrics != nil {
|
|
||||||
p.metrics.SetRTMPServer(nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
p.rtmpServer.Close()
|
p.rtmpServer.Close()
|
||||||
p.rtmpServer = nil
|
p.rtmpServer = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if closeRTSPSServer && p.rtspsServer != nil {
|
if closeRTSPSServer && p.rtspsServer != nil {
|
||||||
if p.metrics != nil {
|
|
||||||
p.metrics.SetRTSPSServer(nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
p.rtspsServer.Close()
|
p.rtspsServer.Close()
|
||||||
p.rtspsServer = nil
|
p.rtspsServer = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if closeRTSPServer && p.rtspServer != nil {
|
if closeRTSPServer && p.rtspServer != nil {
|
||||||
if p.metrics != nil {
|
|
||||||
p.metrics.SetRTSPServer(nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
p.rtspServer.Close()
|
p.rtspServer.Close()
|
||||||
p.rtspServer = nil
|
p.rtspServer = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if closePathManager && p.pathManager != nil {
|
if closePathManager && p.pathManager != nil {
|
||||||
if p.metrics != nil {
|
|
||||||
p.metrics.SetPathManager(nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
p.pathManager.close()
|
p.pathManager.close()
|
||||||
p.pathManager = nil
|
p.pathManager = nil
|
||||||
}
|
}
|
||||||
|
@@ -161,6 +161,10 @@ func (pa *path) Name() string {
|
|||||||
return pa.name
|
return pa.name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (pa *path) isReady() bool {
|
||||||
|
return pa.stream != nil
|
||||||
|
}
|
||||||
|
|
||||||
func (pa *path) run() {
|
func (pa *path) run() {
|
||||||
defer close(pa.done)
|
defer close(pa.done)
|
||||||
defer pa.wg.Done()
|
defer pa.wg.Done()
|
||||||
@@ -568,28 +572,28 @@ func (pa *path) doAPIPathsGet(req pathAPIPathsGetReq) {
|
|||||||
v := pa.source.APISourceDescribe()
|
v := pa.source.APISourceDescribe()
|
||||||
return &v
|
return &v
|
||||||
}(),
|
}(),
|
||||||
Ready: pa.stream != nil,
|
Ready: pa.isReady(),
|
||||||
ReadyTime: func() *time.Time {
|
ReadyTime: func() *time.Time {
|
||||||
if pa.stream == nil {
|
if !pa.isReady() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
v := pa.readyTime
|
v := pa.readyTime
|
||||||
return &v
|
return &v
|
||||||
}(),
|
}(),
|
||||||
Tracks: func() []string {
|
Tracks: func() []string {
|
||||||
if pa.stream == nil {
|
if !pa.isReady() {
|
||||||
return []string{}
|
return []string{}
|
||||||
}
|
}
|
||||||
return defs.MediasToCodecs(pa.stream.Desc.Medias)
|
return defs.MediasToCodecs(pa.stream.Desc.Medias)
|
||||||
}(),
|
}(),
|
||||||
BytesReceived: func() uint64 {
|
BytesReceived: func() uint64 {
|
||||||
if pa.stream == nil {
|
if !pa.isReady() {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
return pa.stream.BytesReceived()
|
return pa.stream.BytesReceived()
|
||||||
}(),
|
}(),
|
||||||
BytesSent: func() uint64 {
|
BytesSent: func() uint64 {
|
||||||
if pa.stream == nil {
|
if !pa.isReady() {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
return pa.stream.BytesSent()
|
return pa.stream.BytesSent()
|
||||||
|
@@ -11,6 +11,8 @@ import (
|
|||||||
"github.com/bluenviron/mediamtx/internal/defs"
|
"github.com/bluenviron/mediamtx/internal/defs"
|
||||||
"github.com/bluenviron/mediamtx/internal/externalcmd"
|
"github.com/bluenviron/mediamtx/internal/externalcmd"
|
||||||
"github.com/bluenviron/mediamtx/internal/logger"
|
"github.com/bluenviron/mediamtx/internal/logger"
|
||||||
|
"github.com/bluenviron/mediamtx/internal/metrics"
|
||||||
|
"github.com/bluenviron/mediamtx/internal/servers/hls"
|
||||||
"github.com/bluenviron/mediamtx/internal/stream"
|
"github.com/bluenviron/mediamtx/internal/stream"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -39,9 +41,18 @@ func pathConfCanBeUpdated(oldPathConf *conf.Path, newPathConf *conf.Path) bool {
|
|||||||
return newPathConf.Equal(clone)
|
return newPathConf.Equal(clone)
|
||||||
}
|
}
|
||||||
|
|
||||||
type pathManagerHLSServer interface {
|
type pathSetHLSServerRes struct {
|
||||||
PathReady(defs.Path)
|
readyPaths []defs.Path
|
||||||
PathNotReady(defs.Path)
|
}
|
||||||
|
|
||||||
|
type pathSetHLSServerReq struct {
|
||||||
|
s *hls.Server
|
||||||
|
res chan pathSetHLSServerRes
|
||||||
|
}
|
||||||
|
|
||||||
|
type pathData struct {
|
||||||
|
path *path
|
||||||
|
ready bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type pathManagerParent interface {
|
type pathManagerParent interface {
|
||||||
@@ -58,18 +69,19 @@ type pathManager struct {
|
|||||||
udpMaxPayloadSize int
|
udpMaxPayloadSize int
|
||||||
pathConfs map[string]*conf.Path
|
pathConfs map[string]*conf.Path
|
||||||
externalCmdPool *externalcmd.Pool
|
externalCmdPool *externalcmd.Pool
|
||||||
|
metrics *metrics.Metrics
|
||||||
parent pathManagerParent
|
parent pathManagerParent
|
||||||
|
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
ctxCancel func()
|
ctxCancel func()
|
||||||
wg sync.WaitGroup
|
wg sync.WaitGroup
|
||||||
hlsManager pathManagerHLSServer
|
hlsServer *hls.Server
|
||||||
paths map[string]*path
|
paths map[string]*pathData
|
||||||
pathsByConf map[string]map[*path]struct{}
|
pathsByConf map[string]map[*path]struct{}
|
||||||
|
|
||||||
// in
|
// in
|
||||||
chReloadConf chan map[string]*conf.Path
|
chReloadConf chan map[string]*conf.Path
|
||||||
chSetHLSServer chan pathManagerHLSServer
|
chSetHLSServer chan pathSetHLSServerReq
|
||||||
chClosePath chan *path
|
chClosePath chan *path
|
||||||
chPathReady chan *path
|
chPathReady chan *path
|
||||||
chPathNotReady chan *path
|
chPathNotReady chan *path
|
||||||
@@ -86,10 +98,10 @@ func (pm *pathManager) initialize() {
|
|||||||
|
|
||||||
pm.ctx = ctx
|
pm.ctx = ctx
|
||||||
pm.ctxCancel = ctxCancel
|
pm.ctxCancel = ctxCancel
|
||||||
pm.paths = make(map[string]*path)
|
pm.paths = make(map[string]*pathData)
|
||||||
pm.pathsByConf = make(map[string]map[*path]struct{})
|
pm.pathsByConf = make(map[string]map[*path]struct{})
|
||||||
pm.chReloadConf = make(chan map[string]*conf.Path)
|
pm.chReloadConf = make(chan map[string]*conf.Path)
|
||||||
pm.chSetHLSServer = make(chan pathManagerHLSServer)
|
pm.chSetHLSServer = make(chan pathSetHLSServerReq)
|
||||||
pm.chClosePath = make(chan *path)
|
pm.chClosePath = make(chan *path)
|
||||||
pm.chPathReady = make(chan *path)
|
pm.chPathReady = make(chan *path)
|
||||||
pm.chPathNotReady = make(chan *path)
|
pm.chPathNotReady = make(chan *path)
|
||||||
@@ -110,10 +122,19 @@ func (pm *pathManager) initialize() {
|
|||||||
|
|
||||||
pm.wg.Add(1)
|
pm.wg.Add(1)
|
||||||
go pm.run()
|
go pm.run()
|
||||||
|
|
||||||
|
if pm.metrics != nil {
|
||||||
|
pm.metrics.SetPathManager(pm)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pm *pathManager) close() {
|
func (pm *pathManager) close() {
|
||||||
pm.Log(logger.Debug, "path manager is shutting down")
|
pm.Log(logger.Debug, "path manager is shutting down")
|
||||||
|
|
||||||
|
if pm.metrics != nil {
|
||||||
|
pm.metrics.SetPathManager(nil)
|
||||||
|
}
|
||||||
|
|
||||||
pm.ctxCancel()
|
pm.ctxCancel()
|
||||||
pm.wg.Wait()
|
pm.wg.Wait()
|
||||||
}
|
}
|
||||||
@@ -132,8 +153,9 @@ outer:
|
|||||||
case newPaths := <-pm.chReloadConf:
|
case newPaths := <-pm.chReloadConf:
|
||||||
pm.doReloadConf(newPaths)
|
pm.doReloadConf(newPaths)
|
||||||
|
|
||||||
case m := <-pm.chSetHLSServer:
|
case req := <-pm.chSetHLSServer:
|
||||||
pm.doSetHLSServer(m)
|
readyPaths := pm.doSetHLSServer(req.s)
|
||||||
|
req.res <- pathSetHLSServerRes{readyPaths: readyPaths}
|
||||||
|
|
||||||
case pa := <-pm.chClosePath:
|
case pa := <-pm.chClosePath:
|
||||||
pm.doClosePath(pa)
|
pm.doClosePath(pa)
|
||||||
@@ -207,26 +229,48 @@ func (pm *pathManager) doReloadConf(newPaths map[string]*conf.Path) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pm *pathManager) doSetHLSServer(m pathManagerHLSServer) {
|
func (pm *pathManager) doSetHLSServer(m *hls.Server) []defs.Path {
|
||||||
pm.hlsManager = m
|
pm.hlsServer = m
|
||||||
|
|
||||||
|
var ret []defs.Path
|
||||||
|
|
||||||
|
for _, pd := range pm.paths {
|
||||||
|
if pd.ready {
|
||||||
|
ret = append(ret, pd.path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pm *pathManager) doClosePath(pa *path) {
|
func (pm *pathManager) doClosePath(pa *path) {
|
||||||
if pmpa, ok := pm.paths[pa.name]; !ok || pmpa != pa {
|
if pd, ok := pm.paths[pa.name]; !ok || pd.path != pa {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
pm.removePath(pa)
|
pm.removePath(pa)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pm *pathManager) doPathReady(pa *path) {
|
func (pm *pathManager) doPathReady(pa *path) {
|
||||||
if pm.hlsManager != nil {
|
if pd, ok := pm.paths[pa.name]; !ok || pd.path != pa {
|
||||||
pm.hlsManager.PathReady(pa)
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
pm.paths[pa.name].ready = true
|
||||||
|
|
||||||
|
if pm.hlsServer != nil {
|
||||||
|
pm.hlsServer.PathReady(pa)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pm *pathManager) doPathNotReady(pa *path) {
|
func (pm *pathManager) doPathNotReady(pa *path) {
|
||||||
if pm.hlsManager != nil {
|
if pd, ok := pm.paths[pa.name]; !ok || pd.path != pa {
|
||||||
pm.hlsManager.PathNotReady(pa)
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
pm.paths[pa.name].ready = false
|
||||||
|
|
||||||
|
if pm.hlsServer != nil {
|
||||||
|
pm.hlsServer.PathNotReady(pa)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -264,7 +308,8 @@ func (pm *pathManager) doDescribe(req defs.PathDescribeReq) {
|
|||||||
pm.createPath(pathConf, req.AccessRequest.Name, pathMatches)
|
pm.createPath(pathConf, req.AccessRequest.Name, pathMatches)
|
||||||
}
|
}
|
||||||
|
|
||||||
req.Res <- defs.PathDescribeRes{Path: pm.paths[req.AccessRequest.Name]}
|
pd := pm.paths[req.AccessRequest.Name]
|
||||||
|
req.Res <- defs.PathDescribeRes{Path: pd.path}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pm *pathManager) doAddReader(req defs.PathAddReaderReq) {
|
func (pm *pathManager) doAddReader(req defs.PathAddReaderReq) {
|
||||||
@@ -287,7 +332,8 @@ func (pm *pathManager) doAddReader(req defs.PathAddReaderReq) {
|
|||||||
pm.createPath(pathConf, req.AccessRequest.Name, pathMatches)
|
pm.createPath(pathConf, req.AccessRequest.Name, pathMatches)
|
||||||
}
|
}
|
||||||
|
|
||||||
req.Res <- defs.PathAddReaderRes{Path: pm.paths[req.AccessRequest.Name]}
|
pd := pm.paths[req.AccessRequest.Name]
|
||||||
|
req.Res <- defs.PathAddReaderRes{Path: pd.path}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pm *pathManager) doAddPublisher(req defs.PathAddPublisherReq) {
|
func (pm *pathManager) doAddPublisher(req defs.PathAddPublisherReq) {
|
||||||
@@ -310,27 +356,28 @@ func (pm *pathManager) doAddPublisher(req defs.PathAddPublisherReq) {
|
|||||||
pm.createPath(pathConf, req.AccessRequest.Name, pathMatches)
|
pm.createPath(pathConf, req.AccessRequest.Name, pathMatches)
|
||||||
}
|
}
|
||||||
|
|
||||||
req.Res <- defs.PathAddPublisherRes{Path: pm.paths[req.AccessRequest.Name]}
|
pd := pm.paths[req.AccessRequest.Name]
|
||||||
|
req.Res <- defs.PathAddPublisherRes{Path: pd.path}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pm *pathManager) doAPIPathsList(req pathAPIPathsListReq) {
|
func (pm *pathManager) doAPIPathsList(req pathAPIPathsListReq) {
|
||||||
paths := make(map[string]*path)
|
paths := make(map[string]*path)
|
||||||
|
|
||||||
for name, pa := range pm.paths {
|
for name, pd := range pm.paths {
|
||||||
paths[name] = pa
|
paths[name] = pd.path
|
||||||
}
|
}
|
||||||
|
|
||||||
req.res <- pathAPIPathsListRes{paths: paths}
|
req.res <- pathAPIPathsListRes{paths: paths}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pm *pathManager) doAPIPathsGet(req pathAPIPathsGetReq) {
|
func (pm *pathManager) doAPIPathsGet(req pathAPIPathsGetReq) {
|
||||||
path, ok := pm.paths[req.name]
|
pd, ok := pm.paths[req.name]
|
||||||
if !ok {
|
if !ok {
|
||||||
req.res <- pathAPIPathsGetRes{err: conf.ErrPathNotFound}
|
req.res <- pathAPIPathsGetRes{err: conf.ErrPathNotFound}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
req.res <- pathAPIPathsGetRes{path: path}
|
req.res <- pathAPIPathsGetRes{path: pd.path}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pm *pathManager) createPath(
|
func (pm *pathManager) createPath(
|
||||||
@@ -355,7 +402,7 @@ func (pm *pathManager) createPath(
|
|||||||
}
|
}
|
||||||
pa.initialize()
|
pa.initialize()
|
||||||
|
|
||||||
pm.paths[name] = pa
|
pm.paths[name] = &pathData{path: pa}
|
||||||
|
|
||||||
if _, ok := pm.pathsByConf[pathConf.Name]; !ok {
|
if _, ok := pm.pathsByConf[pathConf.Name]; !ok {
|
||||||
pm.pathsByConf[pathConf.Name] = make(map[*path]struct{})
|
pm.pathsByConf[pathConf.Name] = make(map[*path]struct{})
|
||||||
@@ -476,11 +523,20 @@ func (pm *pathManager) AddReader(req defs.PathAddReaderReq) (defs.Path, *stream.
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// setHLSServer is called by hlsManager.
|
// SetHLSServer is called by hls.Server.
|
||||||
func (pm *pathManager) setHLSServer(s pathManagerHLSServer) {
|
func (pm *pathManager) SetHLSServer(s *hls.Server) []defs.Path {
|
||||||
|
req := pathSetHLSServerReq{
|
||||||
|
s: s,
|
||||||
|
res: make(chan pathSetHLSServerRes),
|
||||||
|
}
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case pm.chSetHLSServer <- s:
|
case pm.chSetHLSServer <- req:
|
||||||
|
res := <-req.res
|
||||||
|
return res.readyPaths
|
||||||
|
|
||||||
case <-pm.ctx.Done():
|
case <-pm.ctx.Done():
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -8,6 +8,48 @@ import (
|
|||||||
"github.com/bluenviron/mediamtx/internal/conf"
|
"github.com/bluenviron/mediamtx/internal/conf"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// APIPathManager contains methods used by the API and Metrics server.
|
||||||
|
type APIPathManager interface {
|
||||||
|
APIPathsList() (*APIPathList, error)
|
||||||
|
APIPathsGet(string) (*APIPath, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// APIHLSServer contains methods used by the API and Metrics server.
|
||||||
|
type APIHLSServer interface {
|
||||||
|
APIMuxersList() (*APIHLSMuxerList, error)
|
||||||
|
APIMuxersGet(string) (*APIHLSMuxer, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// APIRTSPServer contains methods used by the API and Metrics server.
|
||||||
|
type APIRTSPServer interface {
|
||||||
|
APIConnsList() (*APIRTSPConnsList, error)
|
||||||
|
APIConnsGet(uuid.UUID) (*APIRTSPConn, error)
|
||||||
|
APISessionsList() (*APIRTSPSessionList, error)
|
||||||
|
APISessionsGet(uuid.UUID) (*APIRTSPSession, error)
|
||||||
|
APISessionsKick(uuid.UUID) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// APIRTMPServer contains methods used by the API and Metrics server.
|
||||||
|
type APIRTMPServer interface {
|
||||||
|
APIConnsList() (*APIRTMPConnList, error)
|
||||||
|
APIConnsGet(uuid.UUID) (*APIRTMPConn, error)
|
||||||
|
APIConnsKick(uuid.UUID) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// APISRTServer contains methods used by the API and Metrics server.
|
||||||
|
type APISRTServer interface {
|
||||||
|
APIConnsList() (*APISRTConnList, error)
|
||||||
|
APIConnsGet(uuid.UUID) (*APISRTConn, error)
|
||||||
|
APIConnsKick(uuid.UUID) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// APIWebRTCServer contains methods used by the API and Metrics server.
|
||||||
|
type APIWebRTCServer interface {
|
||||||
|
APISessionsList() (*APIWebRTCSessionList, error)
|
||||||
|
APISessionsGet(uuid.UUID) (*APIWebRTCSession, error)
|
||||||
|
APISessionsKick(uuid.UUID) error
|
||||||
|
}
|
||||||
|
|
||||||
// APIError is a generic error.
|
// APIError is a generic error.
|
||||||
type APIError struct {
|
type APIError struct {
|
||||||
Error string `json:"error"`
|
Error string `json:"error"`
|
||||||
|
@@ -12,9 +12,9 @@ import (
|
|||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
|
||||||
"github.com/bluenviron/mediamtx/internal/api"
|
|
||||||
"github.com/bluenviron/mediamtx/internal/auth"
|
"github.com/bluenviron/mediamtx/internal/auth"
|
||||||
"github.com/bluenviron/mediamtx/internal/conf"
|
"github.com/bluenviron/mediamtx/internal/conf"
|
||||||
|
"github.com/bluenviron/mediamtx/internal/defs"
|
||||||
"github.com/bluenviron/mediamtx/internal/logger"
|
"github.com/bluenviron/mediamtx/internal/logger"
|
||||||
"github.com/bluenviron/mediamtx/internal/protocols/httpp"
|
"github.com/bluenviron/mediamtx/internal/protocols/httpp"
|
||||||
"github.com/bluenviron/mediamtx/internal/restrictnetwork"
|
"github.com/bluenviron/mediamtx/internal/restrictnetwork"
|
||||||
@@ -54,14 +54,14 @@ type Metrics struct {
|
|||||||
|
|
||||||
httpServer *httpp.Server
|
httpServer *httpp.Server
|
||||||
mutex sync.Mutex
|
mutex sync.Mutex
|
||||||
pathManager api.PathManager
|
pathManager defs.APIPathManager
|
||||||
rtspServer api.RTSPServer
|
rtspServer defs.APIRTSPServer
|
||||||
rtspsServer api.RTSPServer
|
rtspsServer defs.APIRTSPServer
|
||||||
rtmpServer api.RTMPServer
|
rtmpServer defs.APIRTMPServer
|
||||||
rtmpsServer api.RTMPServer
|
rtmpsServer defs.APIRTMPServer
|
||||||
srtServer api.SRTServer
|
srtServer defs.APISRTServer
|
||||||
hlsManager api.HLSServer
|
hlsServer defs.APIHLSServer
|
||||||
webRTCServer api.WebRTCServer
|
webRTCServer defs.APIWebRTCServer
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize initializes metrics.
|
// Initialize initializes metrics.
|
||||||
@@ -166,8 +166,8 @@ func (m *Metrics) onMetrics(ctx *gin.Context) {
|
|||||||
out += metric("paths", "", 0)
|
out += metric("paths", "", 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !interfaceIsEmpty(m.hlsManager) {
|
if !interfaceIsEmpty(m.hlsServer) {
|
||||||
data, err := m.hlsManager.APIMuxersList()
|
data, err := m.hlsServer.APIMuxersList()
|
||||||
if err == nil && len(data.Items) != 0 {
|
if err == nil && len(data.Items) != 0 {
|
||||||
for _, i := range data.Items {
|
for _, i := range data.Items {
|
||||||
tags := "{name=\"" + i.Path + "\"}"
|
tags := "{name=\"" + i.Path + "\"}"
|
||||||
@@ -447,56 +447,56 @@ func (m *Metrics) onMetrics(ctx *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SetPathManager is called by core.
|
// SetPathManager is called by core.
|
||||||
func (m *Metrics) SetPathManager(s api.PathManager) {
|
func (m *Metrics) SetPathManager(s defs.APIPathManager) {
|
||||||
m.mutex.Lock()
|
m.mutex.Lock()
|
||||||
defer m.mutex.Unlock()
|
defer m.mutex.Unlock()
|
||||||
m.pathManager = s
|
m.pathManager = s
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetHLSServer is called by core.
|
// SetHLSServer is called by core.
|
||||||
func (m *Metrics) SetHLSServer(s api.HLSServer) {
|
func (m *Metrics) SetHLSServer(s defs.APIHLSServer) {
|
||||||
m.mutex.Lock()
|
m.mutex.Lock()
|
||||||
defer m.mutex.Unlock()
|
defer m.mutex.Unlock()
|
||||||
m.hlsManager = s
|
m.hlsServer = s
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetRTSPServer is called by core.
|
// SetRTSPServer is called by core.
|
||||||
func (m *Metrics) SetRTSPServer(s api.RTSPServer) {
|
func (m *Metrics) SetRTSPServer(s defs.APIRTSPServer) {
|
||||||
m.mutex.Lock()
|
m.mutex.Lock()
|
||||||
defer m.mutex.Unlock()
|
defer m.mutex.Unlock()
|
||||||
m.rtspServer = s
|
m.rtspServer = s
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetRTSPSServer is called by core.
|
// SetRTSPSServer is called by core.
|
||||||
func (m *Metrics) SetRTSPSServer(s api.RTSPServer) {
|
func (m *Metrics) SetRTSPSServer(s defs.APIRTSPServer) {
|
||||||
m.mutex.Lock()
|
m.mutex.Lock()
|
||||||
defer m.mutex.Unlock()
|
defer m.mutex.Unlock()
|
||||||
m.rtspsServer = s
|
m.rtspsServer = s
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetRTMPServer is called by core.
|
// SetRTMPServer is called by core.
|
||||||
func (m *Metrics) SetRTMPServer(s api.RTMPServer) {
|
func (m *Metrics) SetRTMPServer(s defs.APIRTMPServer) {
|
||||||
m.mutex.Lock()
|
m.mutex.Lock()
|
||||||
defer m.mutex.Unlock()
|
defer m.mutex.Unlock()
|
||||||
m.rtmpServer = s
|
m.rtmpServer = s
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetRTMPSServer is called by core.
|
// SetRTMPSServer is called by core.
|
||||||
func (m *Metrics) SetRTMPSServer(s api.RTMPServer) {
|
func (m *Metrics) SetRTMPSServer(s defs.APIRTMPServer) {
|
||||||
m.mutex.Lock()
|
m.mutex.Lock()
|
||||||
defer m.mutex.Unlock()
|
defer m.mutex.Unlock()
|
||||||
m.rtmpsServer = s
|
m.rtmpsServer = s
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetSRTServer is called by core.
|
// SetSRTServer is called by core.
|
||||||
func (m *Metrics) SetSRTServer(s api.SRTServer) {
|
func (m *Metrics) SetSRTServer(s defs.APISRTServer) {
|
||||||
m.mutex.Lock()
|
m.mutex.Lock()
|
||||||
defer m.mutex.Unlock()
|
defer m.mutex.Unlock()
|
||||||
m.srtServer = s
|
m.srtServer = s
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetWebRTCServer is called by core.
|
// SetWebRTCServer is called by core.
|
||||||
func (m *Metrics) SetWebRTCServer(s api.WebRTCServer) {
|
func (m *Metrics) SetWebRTCServer(s defs.APIWebRTCServer) {
|
||||||
m.mutex.Lock()
|
m.mutex.Lock()
|
||||||
defer m.mutex.Unlock()
|
defer m.mutex.Unlock()
|
||||||
m.webRTCServer = s
|
m.webRTCServer = s
|
||||||
|
@@ -5,6 +5,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"reflect"
|
||||||
"sort"
|
"sort"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
@@ -17,6 +18,10 @@ import (
|
|||||||
// ErrMuxerNotFound is returned when a muxer is not found.
|
// ErrMuxerNotFound is returned when a muxer is not found.
|
||||||
var ErrMuxerNotFound = errors.New("muxer not found")
|
var ErrMuxerNotFound = errors.New("muxer not found")
|
||||||
|
|
||||||
|
func interfaceIsEmpty(i interface{}) bool {
|
||||||
|
return reflect.ValueOf(i).Kind() != reflect.Ptr || reflect.ValueOf(i).IsNil()
|
||||||
|
}
|
||||||
|
|
||||||
type serverGetMuxerRes struct {
|
type serverGetMuxerRes struct {
|
||||||
muxer *muxer
|
muxer *muxer
|
||||||
err error
|
err error
|
||||||
@@ -49,7 +54,12 @@ type serverAPIMuxersGetReq struct {
|
|||||||
res chan serverAPIMuxersGetRes
|
res chan serverAPIMuxersGetRes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type serverMetrics interface {
|
||||||
|
SetHLSServer(defs.APIHLSServer)
|
||||||
|
}
|
||||||
|
|
||||||
type serverPathManager interface {
|
type serverPathManager interface {
|
||||||
|
SetHLSServer(*Server) []defs.Path
|
||||||
FindPathConf(req defs.PathFindPathConfReq) (*conf.Path, error)
|
FindPathConf(req defs.PathFindPathConfReq) (*conf.Path, error)
|
||||||
AddReader(req defs.PathAddReaderReq) (defs.Path, *stream.Stream, error)
|
AddReader(req defs.PathAddReaderReq) (defs.Path, *stream.Stream, error)
|
||||||
}
|
}
|
||||||
@@ -75,6 +85,7 @@ type Server struct {
|
|||||||
Directory string
|
Directory string
|
||||||
ReadTimeout conf.Duration
|
ReadTimeout conf.Duration
|
||||||
MuxerCloseAfter conf.Duration
|
MuxerCloseAfter conf.Duration
|
||||||
|
Metrics serverMetrics
|
||||||
PathManager serverPathManager
|
PathManager serverPathManager
|
||||||
Parent serverParent
|
Parent serverParent
|
||||||
|
|
||||||
@@ -129,6 +140,10 @@ func (s *Server) Initialize() error {
|
|||||||
s.wg.Add(1)
|
s.wg.Add(1)
|
||||||
go s.run()
|
go s.run()
|
||||||
|
|
||||||
|
if !interfaceIsEmpty(s.Metrics) {
|
||||||
|
s.Metrics.SetHLSServer(s)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,6 +155,11 @@ func (s *Server) Log(level logger.Level, format string, args ...interface{}) {
|
|||||||
// Close closes the server.
|
// Close closes the server.
|
||||||
func (s *Server) Close() {
|
func (s *Server) Close() {
|
||||||
s.Log(logger.Info, "listener is closing")
|
s.Log(logger.Info, "listener is closing")
|
||||||
|
|
||||||
|
if !interfaceIsEmpty(s.Metrics) {
|
||||||
|
s.Metrics.SetHLSServer(nil)
|
||||||
|
}
|
||||||
|
|
||||||
s.ctxCancel()
|
s.ctxCancel()
|
||||||
s.wg.Wait()
|
s.wg.Wait()
|
||||||
}
|
}
|
||||||
@@ -147,6 +167,19 @@ func (s *Server) Close() {
|
|||||||
func (s *Server) run() {
|
func (s *Server) run() {
|
||||||
defer s.wg.Done()
|
defer s.wg.Done()
|
||||||
|
|
||||||
|
readyPaths := s.PathManager.SetHLSServer(s)
|
||||||
|
defer s.PathManager.SetHLSServer(nil)
|
||||||
|
|
||||||
|
if s.AlwaysRemux {
|
||||||
|
for _, pa := range readyPaths {
|
||||||
|
if !pa.SafeConf().SourceOnDemand {
|
||||||
|
if _, ok := s.muxers[pa.Name()]; !ok {
|
||||||
|
s.createMuxer(pa.Name(), "", "")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
outer:
|
outer:
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
|
@@ -21,6 +21,27 @@ import (
|
|||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type dummyPathManager struct {
|
||||||
|
setHLSServerImpl func() []defs.Path
|
||||||
|
findPathConfImpl func(req defs.PathFindPathConfReq) (*conf.Path, error)
|
||||||
|
addReaderImpl func(req defs.PathAddReaderReq) (defs.Path, *stream.Stream, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pm *dummyPathManager) SetHLSServer(*Server) []defs.Path {
|
||||||
|
if pm.setHLSServerImpl != nil {
|
||||||
|
return pm.setHLSServerImpl()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pm *dummyPathManager) FindPathConf(req defs.PathFindPathConfReq) (*conf.Path, error) {
|
||||||
|
return pm.findPathConfImpl(req)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pm *dummyPathManager) AddReader(req defs.PathAddReaderReq) (defs.Path, *stream.Stream, error) {
|
||||||
|
return pm.addReaderImpl(req)
|
||||||
|
}
|
||||||
|
|
||||||
type dummyPath struct{}
|
type dummyPath struct{}
|
||||||
|
|
||||||
func (pa *dummyPath) Name() string {
|
func (pa *dummyPath) Name() string {
|
||||||
@@ -53,6 +74,7 @@ func TestPreflightRequest(t *testing.T) {
|
|||||||
Address: "127.0.0.1:8888",
|
Address: "127.0.0.1:8888",
|
||||||
AllowOrigin: "*",
|
AllowOrigin: "*",
|
||||||
ReadTimeout: conf.Duration(10 * time.Second),
|
ReadTimeout: conf.Duration(10 * time.Second),
|
||||||
|
PathManager: &dummyPathManager{},
|
||||||
Parent: test.NilLogger,
|
Parent: test.NilLogger,
|
||||||
}
|
}
|
||||||
err := s.Initialize()
|
err := s.Initialize()
|
||||||
@@ -90,12 +112,12 @@ func TestServerNotFound(t *testing.T) {
|
|||||||
"always remux on",
|
"always remux on",
|
||||||
} {
|
} {
|
||||||
t.Run(ca, func(t *testing.T) {
|
t.Run(ca, func(t *testing.T) {
|
||||||
pm := &test.PathManager{
|
pm := &dummyPathManager{
|
||||||
FindPathConfImpl: func(req defs.PathFindPathConfReq) (*conf.Path, error) {
|
findPathConfImpl: func(req defs.PathFindPathConfReq) (*conf.Path, error) {
|
||||||
require.Equal(t, "nonexisting", req.AccessRequest.Name)
|
require.Equal(t, "nonexisting", req.AccessRequest.Name)
|
||||||
return &conf.Path{}, nil
|
return &conf.Path{}, nil
|
||||||
},
|
},
|
||||||
AddReaderImpl: func(req defs.PathAddReaderReq) (defs.Path, *stream.Stream, error) {
|
addReaderImpl: func(req defs.PathAddReaderReq) (defs.Path, *stream.Stream, error) {
|
||||||
require.Equal(t, "nonexisting", req.AccessRequest.Name)
|
require.Equal(t, "nonexisting", req.AccessRequest.Name)
|
||||||
return nil, nil, fmt.Errorf("not found")
|
return nil, nil, fmt.Errorf("not found")
|
||||||
},
|
},
|
||||||
@@ -164,15 +186,15 @@ func TestServerRead(t *testing.T) {
|
|||||||
err := strm.Initialize()
|
err := strm.Initialize()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
pm := &test.PathManager{
|
pm := &dummyPathManager{
|
||||||
FindPathConfImpl: func(req defs.PathFindPathConfReq) (*conf.Path, error) {
|
findPathConfImpl: func(req defs.PathFindPathConfReq) (*conf.Path, error) {
|
||||||
require.Equal(t, "teststream", req.AccessRequest.Name)
|
require.Equal(t, "teststream", req.AccessRequest.Name)
|
||||||
require.Equal(t, "param=value", req.AccessRequest.Query)
|
require.Equal(t, "param=value", req.AccessRequest.Query)
|
||||||
require.Equal(t, "myuser", req.AccessRequest.User)
|
require.Equal(t, "myuser", req.AccessRequest.User)
|
||||||
require.Equal(t, "mypass", req.AccessRequest.Pass)
|
require.Equal(t, "mypass", req.AccessRequest.Pass)
|
||||||
return &conf.Path{}, nil
|
return &conf.Path{}, nil
|
||||||
},
|
},
|
||||||
AddReaderImpl: func(req defs.PathAddReaderReq) (defs.Path, *stream.Stream, error) {
|
addReaderImpl: func(req defs.PathAddReaderReq) (defs.Path, *stream.Stream, error) {
|
||||||
require.Equal(t, "teststream", req.AccessRequest.Name)
|
require.Equal(t, "teststream", req.AccessRequest.Name)
|
||||||
require.Equal(t, "param=value", req.AccessRequest.Query)
|
require.Equal(t, "param=value", req.AccessRequest.Query)
|
||||||
return &dummyPath{}, strm, nil
|
return &dummyPath{}, strm, nil
|
||||||
@@ -264,15 +286,15 @@ func TestServerRead(t *testing.T) {
|
|||||||
err := strm.Initialize()
|
err := strm.Initialize()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
pm := &test.PathManager{
|
pm := &dummyPathManager{
|
||||||
FindPathConfImpl: func(req defs.PathFindPathConfReq) (*conf.Path, error) {
|
findPathConfImpl: func(req defs.PathFindPathConfReq) (*conf.Path, error) {
|
||||||
require.Equal(t, "teststream", req.AccessRequest.Name)
|
require.Equal(t, "teststream", req.AccessRequest.Name)
|
||||||
require.Equal(t, "param=value", req.AccessRequest.Query)
|
require.Equal(t, "param=value", req.AccessRequest.Query)
|
||||||
require.Equal(t, "myuser", req.AccessRequest.User)
|
require.Equal(t, "myuser", req.AccessRequest.User)
|
||||||
require.Equal(t, "mypass", req.AccessRequest.Pass)
|
require.Equal(t, "mypass", req.AccessRequest.Pass)
|
||||||
return &conf.Path{}, nil
|
return &conf.Path{}, nil
|
||||||
},
|
},
|
||||||
AddReaderImpl: func(req defs.PathAddReaderReq) (defs.Path, *stream.Stream, error) {
|
addReaderImpl: func(req defs.PathAddReaderReq) (defs.Path, *stream.Stream, error) {
|
||||||
require.Equal(t, "teststream", req.AccessRequest.Name)
|
require.Equal(t, "teststream", req.AccessRequest.Name)
|
||||||
require.Equal(t, "", req.AccessRequest.Query)
|
require.Equal(t, "", req.AccessRequest.Query)
|
||||||
return &dummyPath{}, strm, nil
|
return &dummyPath{}, strm, nil
|
||||||
@@ -369,8 +391,8 @@ func TestDirectory(t *testing.T) {
|
|||||||
err = strm.Initialize()
|
err = strm.Initialize()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
pm := &test.PathManager{
|
pm := &dummyPathManager{
|
||||||
AddReaderImpl: func(_ defs.PathAddReaderReq) (defs.Path, *stream.Stream, error) {
|
addReaderImpl: func(_ defs.PathAddReaderReq) (defs.Path, *stream.Stream, error) {
|
||||||
return &dummyPath{}, strm, nil
|
return &dummyPath{}, strm, nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -404,3 +426,50 @@ func TestDirectory(t *testing.T) {
|
|||||||
_, err = os.Stat(filepath.Join(dir, "mydir", "teststream"))
|
_, err = os.Stat(filepath.Join(dir, "mydir", "teststream"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDynamicAlwaysRemux(t *testing.T) {
|
||||||
|
desc := &description.Session{Medias: []*description.Media{test.MediaH264}}
|
||||||
|
|
||||||
|
strm := &stream.Stream{
|
||||||
|
WriteQueueSize: 512,
|
||||||
|
UDPMaxPayloadSize: 1472,
|
||||||
|
Desc: desc,
|
||||||
|
GenerateRTPPackets: true,
|
||||||
|
Parent: test.NilLogger,
|
||||||
|
}
|
||||||
|
err := strm.Initialize()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
done := make(chan struct{})
|
||||||
|
|
||||||
|
pm := &dummyPathManager{
|
||||||
|
setHLSServerImpl: func() []defs.Path {
|
||||||
|
return []defs.Path{&dummyPath{}}
|
||||||
|
},
|
||||||
|
addReaderImpl: func(_ defs.PathAddReaderReq) (defs.Path, *stream.Stream, error) {
|
||||||
|
close(done)
|
||||||
|
return &dummyPath{}, strm, nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
s := &Server{
|
||||||
|
Address: "127.0.0.1:8888",
|
||||||
|
Encryption: false,
|
||||||
|
ServerKey: "",
|
||||||
|
ServerCert: "",
|
||||||
|
AlwaysRemux: true,
|
||||||
|
Variant: conf.HLSVariant(gohlslib.MuxerVariantMPEGTS),
|
||||||
|
SegmentCount: 7,
|
||||||
|
SegmentDuration: conf.Duration(1 * time.Second),
|
||||||
|
PartDuration: conf.Duration(200 * time.Millisecond),
|
||||||
|
SegmentMaxSize: 50 * 1024 * 1024,
|
||||||
|
ReadTimeout: conf.Duration(10 * time.Second),
|
||||||
|
PathManager: pm,
|
||||||
|
Parent: test.NilLogger,
|
||||||
|
}
|
||||||
|
err = s.Initialize()
|
||||||
|
require.NoError(t, err)
|
||||||
|
defer s.Close()
|
||||||
|
|
||||||
|
<-done
|
||||||
|
}
|
||||||
|
@@ -7,6 +7,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
"reflect"
|
||||||
"sort"
|
"sort"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
@@ -24,6 +25,10 @@ import (
|
|||||||
// ErrConnNotFound is returned when a connection is not found.
|
// ErrConnNotFound is returned when a connection is not found.
|
||||||
var ErrConnNotFound = errors.New("connection not found")
|
var ErrConnNotFound = errors.New("connection not found")
|
||||||
|
|
||||||
|
func interfaceIsEmpty(i interface{}) bool {
|
||||||
|
return reflect.ValueOf(i).Kind() != reflect.Ptr || reflect.ValueOf(i).IsNil()
|
||||||
|
}
|
||||||
|
|
||||||
type serverAPIConnsListRes struct {
|
type serverAPIConnsListRes struct {
|
||||||
data *defs.APIRTMPConnList
|
data *defs.APIRTMPConnList
|
||||||
err error
|
err error
|
||||||
@@ -52,6 +57,11 @@ type serverAPIConnsKickReq struct {
|
|||||||
res chan serverAPIConnsKickRes
|
res chan serverAPIConnsKickRes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type serverMetrics interface {
|
||||||
|
SetRTMPSServer(defs.APIRTMPServer)
|
||||||
|
SetRTMPServer(defs.APIRTMPServer)
|
||||||
|
}
|
||||||
|
|
||||||
type serverPathManager interface {
|
type serverPathManager interface {
|
||||||
AddPublisher(req defs.PathAddPublisherReq) (defs.Path, error)
|
AddPublisher(req defs.PathAddPublisherReq) (defs.Path, error)
|
||||||
AddReader(req defs.PathAddReaderReq) (defs.Path, *stream.Stream, error)
|
AddReader(req defs.PathAddReaderReq) (defs.Path, *stream.Stream, error)
|
||||||
@@ -74,6 +84,7 @@ type Server struct {
|
|||||||
RunOnConnectRestart bool
|
RunOnConnectRestart bool
|
||||||
RunOnDisconnect string
|
RunOnDisconnect string
|
||||||
ExternalCmdPool *externalcmd.Pool
|
ExternalCmdPool *externalcmd.Pool
|
||||||
|
Metrics serverMetrics
|
||||||
PathManager serverPathManager
|
PathManager serverPathManager
|
||||||
Parent serverParent
|
Parent serverParent
|
||||||
|
|
||||||
@@ -140,6 +151,14 @@ func (s *Server) Initialize() error {
|
|||||||
s.wg.Add(1)
|
s.wg.Add(1)
|
||||||
go s.run()
|
go s.run()
|
||||||
|
|
||||||
|
if !interfaceIsEmpty(s.Metrics) {
|
||||||
|
if s.IsTLS {
|
||||||
|
s.Metrics.SetRTMPSServer(s)
|
||||||
|
} else {
|
||||||
|
s.Metrics.SetRTMPServer(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,8 +176,18 @@ func (s *Server) Log(level logger.Level, format string, args ...interface{}) {
|
|||||||
// Close closes the server.
|
// Close closes the server.
|
||||||
func (s *Server) Close() {
|
func (s *Server) Close() {
|
||||||
s.Log(logger.Info, "listener is closing")
|
s.Log(logger.Info, "listener is closing")
|
||||||
|
|
||||||
|
if !interfaceIsEmpty((s.Metrics)) {
|
||||||
|
if s.IsTLS {
|
||||||
|
s.Metrics.SetRTMPSServer(nil)
|
||||||
|
} else {
|
||||||
|
s.Metrics.SetRTMPServer(nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
s.ctxCancel()
|
s.ctxCancel()
|
||||||
s.wg.Wait()
|
s.wg.Wait()
|
||||||
|
|
||||||
if s.loader != nil {
|
if s.loader != nil {
|
||||||
s.loader.Close()
|
s.loader.Close()
|
||||||
}
|
}
|
||||||
|
@@ -6,6 +6,7 @@ import (
|
|||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"reflect"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
@@ -31,6 +32,10 @@ var ErrConnNotFound = errors.New("connection not found")
|
|||||||
// ErrSessionNotFound is returned when a session is not found.
|
// ErrSessionNotFound is returned when a session is not found.
|
||||||
var ErrSessionNotFound = errors.New("session not found")
|
var ErrSessionNotFound = errors.New("session not found")
|
||||||
|
|
||||||
|
func interfaceIsEmpty(i interface{}) bool {
|
||||||
|
return reflect.ValueOf(i).Kind() != reflect.Ptr || reflect.ValueOf(i).IsNil()
|
||||||
|
}
|
||||||
|
|
||||||
func printAddresses(srv *gortsplib.Server) string {
|
func printAddresses(srv *gortsplib.Server) string {
|
||||||
var ret []string
|
var ret []string
|
||||||
|
|
||||||
@@ -47,6 +52,11 @@ func printAddresses(srv *gortsplib.Server) string {
|
|||||||
return strings.Join(ret, ", ")
|
return strings.Join(ret, ", ")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type serverMetrics interface {
|
||||||
|
SetRTSPSServer(defs.APIRTSPServer)
|
||||||
|
SetRTSPServer(defs.APIRTSPServer)
|
||||||
|
}
|
||||||
|
|
||||||
type serverPathManager interface {
|
type serverPathManager interface {
|
||||||
Describe(req defs.PathDescribeReq) defs.PathDescribeRes
|
Describe(req defs.PathDescribeReq) defs.PathDescribeRes
|
||||||
AddPublisher(_ defs.PathAddPublisherReq) (defs.Path, error)
|
AddPublisher(_ defs.PathAddPublisherReq) (defs.Path, error)
|
||||||
@@ -80,6 +90,7 @@ type Server struct {
|
|||||||
RunOnConnectRestart bool
|
RunOnConnectRestart bool
|
||||||
RunOnDisconnect string
|
RunOnDisconnect string
|
||||||
ExternalCmdPool *externalcmd.Pool
|
ExternalCmdPool *externalcmd.Pool
|
||||||
|
Metrics serverMetrics
|
||||||
PathManager serverPathManager
|
PathManager serverPathManager
|
||||||
Parent serverParent
|
Parent serverParent
|
||||||
|
|
||||||
@@ -144,6 +155,14 @@ func (s *Server) Initialize() error {
|
|||||||
s.wg.Add(1)
|
s.wg.Add(1)
|
||||||
go s.run()
|
go s.run()
|
||||||
|
|
||||||
|
if !interfaceIsEmpty(s.Metrics) {
|
||||||
|
if s.IsTLS {
|
||||||
|
s.Metrics.SetRTSPSServer(s)
|
||||||
|
} else {
|
||||||
|
s.Metrics.SetRTSPServer(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,8 +180,18 @@ func (s *Server) Log(level logger.Level, format string, args ...interface{}) {
|
|||||||
// Close closes the server.
|
// Close closes the server.
|
||||||
func (s *Server) Close() {
|
func (s *Server) Close() {
|
||||||
s.Log(logger.Info, "listener is closing")
|
s.Log(logger.Info, "listener is closing")
|
||||||
|
|
||||||
|
if !interfaceIsEmpty(s.Metrics) {
|
||||||
|
if s.IsTLS {
|
||||||
|
s.Metrics.SetRTSPSServer(nil)
|
||||||
|
} else {
|
||||||
|
s.Metrics.SetRTSPServer(nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
s.ctxCancel()
|
s.ctxCancel()
|
||||||
s.wg.Wait()
|
s.wg.Wait()
|
||||||
|
|
||||||
if s.loader != nil {
|
if s.loader != nil {
|
||||||
s.loader.Close()
|
s.loader.Close()
|
||||||
}
|
}
|
||||||
|
@@ -5,6 +5,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"reflect"
|
||||||
"sort"
|
"sort"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
@@ -22,6 +23,10 @@ import (
|
|||||||
// ErrConnNotFound is returned when a connection is not found.
|
// ErrConnNotFound is returned when a connection is not found.
|
||||||
var ErrConnNotFound = errors.New("connection not found")
|
var ErrConnNotFound = errors.New("connection not found")
|
||||||
|
|
||||||
|
func interfaceIsEmpty(i interface{}) bool {
|
||||||
|
return reflect.ValueOf(i).Kind() != reflect.Ptr || reflect.ValueOf(i).IsNil()
|
||||||
|
}
|
||||||
|
|
||||||
func srtMaxPayloadSize(u int) int {
|
func srtMaxPayloadSize(u int) int {
|
||||||
return ((u - 16) / 188) * 188 // 16 = SRT header, 188 = MPEG-TS packet
|
return ((u - 16) / 188) * 188 // 16 = SRT header, 188 = MPEG-TS packet
|
||||||
}
|
}
|
||||||
@@ -54,6 +59,10 @@ type serverAPIConnsKickReq struct {
|
|||||||
res chan serverAPIConnsKickRes
|
res chan serverAPIConnsKickRes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type serverMetrics interface {
|
||||||
|
SetSRTServer(defs.APISRTServer)
|
||||||
|
}
|
||||||
|
|
||||||
type serverPathManager interface {
|
type serverPathManager interface {
|
||||||
AddPublisher(req defs.PathAddPublisherReq) (defs.Path, error)
|
AddPublisher(req defs.PathAddPublisherReq) (defs.Path, error)
|
||||||
AddReader(req defs.PathAddReaderReq) (defs.Path, *stream.Stream, error)
|
AddReader(req defs.PathAddReaderReq) (defs.Path, *stream.Stream, error)
|
||||||
@@ -74,6 +83,7 @@ type Server struct {
|
|||||||
RunOnConnectRestart bool
|
RunOnConnectRestart bool
|
||||||
RunOnDisconnect string
|
RunOnDisconnect string
|
||||||
ExternalCmdPool *externalcmd.Pool
|
ExternalCmdPool *externalcmd.Pool
|
||||||
|
Metrics serverMetrics
|
||||||
PathManager serverPathManager
|
PathManager serverPathManager
|
||||||
Parent serverParent
|
Parent serverParent
|
||||||
|
|
||||||
@@ -126,6 +136,10 @@ func (s *Server) Initialize() error {
|
|||||||
s.wg.Add(1)
|
s.wg.Add(1)
|
||||||
go s.run()
|
go s.run()
|
||||||
|
|
||||||
|
if !interfaceIsEmpty(s.Metrics) {
|
||||||
|
s.Metrics.SetSRTServer(s)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,6 +151,11 @@ func (s *Server) Log(level logger.Level, format string, args ...interface{}) {
|
|||||||
// Close closes the server.
|
// Close closes the server.
|
||||||
func (s *Server) Close() {
|
func (s *Server) Close() {
|
||||||
s.Log(logger.Info, "listener is closing")
|
s.Log(logger.Info, "listener is closing")
|
||||||
|
|
||||||
|
if !interfaceIsEmpty(s.Metrics) {
|
||||||
|
s.Metrics.SetSRTServer(nil)
|
||||||
|
}
|
||||||
|
|
||||||
s.ctxCancel()
|
s.ctxCancel()
|
||||||
s.wg.Wait()
|
s.wg.Wait()
|
||||||
}
|
}
|
||||||
|
@@ -11,6 +11,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"reflect"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
@@ -36,6 +37,10 @@ const (
|
|||||||
// ErrSessionNotFound is returned when a session is not found.
|
// ErrSessionNotFound is returned when a session is not found.
|
||||||
var ErrSessionNotFound = errors.New("session not found")
|
var ErrSessionNotFound = errors.New("session not found")
|
||||||
|
|
||||||
|
func interfaceIsEmpty(i interface{}) bool {
|
||||||
|
return reflect.ValueOf(i).Kind() != reflect.Ptr || reflect.ValueOf(i).IsNil()
|
||||||
|
}
|
||||||
|
|
||||||
type nilWriter struct{}
|
type nilWriter struct{}
|
||||||
|
|
||||||
func (nilWriter) Write(p []byte) (int, error) {
|
func (nilWriter) Write(p []byte) (int, error) {
|
||||||
@@ -163,6 +168,10 @@ type webRTCDeleteSessionReq struct {
|
|||||||
res chan webRTCDeleteSessionRes
|
res chan webRTCDeleteSessionRes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type serverMetrics interface {
|
||||||
|
SetWebRTCServer(defs.APIWebRTCServer)
|
||||||
|
}
|
||||||
|
|
||||||
type serverPathManager interface {
|
type serverPathManager interface {
|
||||||
FindPathConf(req defs.PathFindPathConfReq) (*conf.Path, error)
|
FindPathConf(req defs.PathFindPathConfReq) (*conf.Path, error)
|
||||||
AddPublisher(req defs.PathAddPublisherReq) (defs.Path, error)
|
AddPublisher(req defs.PathAddPublisherReq) (defs.Path, error)
|
||||||
@@ -192,6 +201,7 @@ type Server struct {
|
|||||||
TrackGatherTimeout conf.Duration
|
TrackGatherTimeout conf.Duration
|
||||||
STUNGatherTimeout conf.Duration
|
STUNGatherTimeout conf.Duration
|
||||||
ExternalCmdPool *externalcmd.Pool
|
ExternalCmdPool *externalcmd.Pool
|
||||||
|
Metrics serverMetrics
|
||||||
PathManager serverPathManager
|
PathManager serverPathManager
|
||||||
Parent serverParent
|
Parent serverParent
|
||||||
|
|
||||||
@@ -284,6 +294,10 @@ func (s *Server) Initialize() error {
|
|||||||
|
|
||||||
go s.run()
|
go s.run()
|
||||||
|
|
||||||
|
if !interfaceIsEmpty(s.Metrics) {
|
||||||
|
s.Metrics.SetWebRTCServer(s)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -295,6 +309,11 @@ func (s *Server) Log(level logger.Level, format string, args ...interface{}) {
|
|||||||
// Close closes the server.
|
// Close closes the server.
|
||||||
func (s *Server) Close() {
|
func (s *Server) Close() {
|
||||||
s.Log(logger.Info, "listener is closing")
|
s.Log(logger.Info, "listener is closing")
|
||||||
|
|
||||||
|
if !interfaceIsEmpty(s.Metrics) {
|
||||||
|
s.Metrics.SetWebRTCServer(nil)
|
||||||
|
}
|
||||||
|
|
||||||
s.ctxCancel()
|
s.ctxCancel()
|
||||||
<-s.done
|
<-s.done
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user