mirror of
https://github.com/aler9/rtsp-simple-server
synced 2026-04-22 15:07:19 +08:00
hls: improve muxer performance (#5660)
use a mutex instead of a channel to get current instance.
This commit is contained in:
@@ -44,10 +44,6 @@ type muxerGetInstanceRes struct {
|
|||||||
cumulatedOutboundFramesDiscarded uint64
|
cumulatedOutboundFramesDiscarded uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
type muxerGetInstanceReq struct {
|
|
||||||
res chan muxerGetInstanceRes
|
|
||||||
}
|
|
||||||
|
|
||||||
type muxer struct {
|
type muxer struct {
|
||||||
parentCtx context.Context
|
parentCtx context.Context
|
||||||
remoteAddr string
|
remoteAddr string
|
||||||
@@ -71,8 +67,9 @@ type muxer struct {
|
|||||||
lastRequestTime atomic.Int64
|
lastRequestTime atomic.Int64
|
||||||
bytesSent atomic.Uint64
|
bytesSent atomic.Uint64
|
||||||
|
|
||||||
// in
|
instanceMutex sync.RWMutex
|
||||||
chGetInstance chan muxerGetInstanceReq
|
instance *muxerInstance
|
||||||
|
cumulatedOutboundFramesDiscarded uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *muxer) initialize() {
|
func (m *muxer) initialize() {
|
||||||
@@ -83,7 +80,6 @@ func (m *muxer) initialize() {
|
|||||||
m.created = time.Now()
|
m.created = time.Now()
|
||||||
m.lastRequestTime.Store(time.Now().UnixNano())
|
m.lastRequestTime.Store(time.Now().UnixNano())
|
||||||
m.bytesSent.Store(0)
|
m.bytesSent.Store(0)
|
||||||
m.chGetInstance = make(chan muxerGetInstanceReq)
|
|
||||||
|
|
||||||
m.Log(logger.Info, "created %s", func() string {
|
m.Log(logger.Info, "created %s", func() string {
|
||||||
if m.remoteAddr == "" {
|
if m.remoteAddr == "" {
|
||||||
@@ -92,6 +88,9 @@ func (m *muxer) initialize() {
|
|||||||
return "(requested by " + m.remoteAddr + ")"
|
return "(requested by " + m.remoteAddr + ")"
|
||||||
}())
|
}())
|
||||||
|
|
||||||
|
// block first request to getInstance() until the first instance is available
|
||||||
|
m.instanceMutex.Lock()
|
||||||
|
|
||||||
m.wg.Add(1)
|
m.wg.Add(1)
|
||||||
go m.run()
|
go m.run()
|
||||||
}
|
}
|
||||||
@@ -132,6 +131,7 @@ func (m *muxer) runInner() error {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
m.instanceMutex.Unlock()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,27 +139,30 @@ func (m *muxer) runInner() error {
|
|||||||
|
|
||||||
defer m.path.RemoveReader(defs.PathRemoveReaderReq{Author: m})
|
defer m.path.RemoveReader(defs.PathRemoveReaderReq{Author: m})
|
||||||
|
|
||||||
mi, err := m.createInstance(res.Stream)
|
tmp, err := m.createInstance(res.Stream)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if m.remoteAddr != "" || errors.Is(err, hls.ErrNoSupportedCodecs) {
|
if m.remoteAddr != "" || errors.Is(err, hls.ErrNoSupportedCodecs) {
|
||||||
|
m.instanceMutex.Unlock()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
m.Log(logger.Error, err.Error())
|
m.Log(logger.Error, err.Error())
|
||||||
mi = nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m.instance = tmp
|
||||||
|
m.instanceMutex.Unlock()
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
if mi != nil {
|
if m.instance != nil {
|
||||||
mi.close()
|
m.closeInstance()
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
var instanceError chan error
|
var instanceError chan error
|
||||||
var recreateTimer *time.Timer
|
var recreateTimer *time.Timer
|
||||||
|
|
||||||
if mi != nil {
|
if m.instance != nil {
|
||||||
instanceError = mi.errorChan()
|
instanceError = m.instance.errorChan()
|
||||||
recreateTimer = emptyTimer()
|
recreateTimer = emptyTimer()
|
||||||
} else {
|
} else {
|
||||||
instanceError = make(chan error)
|
instanceError = make(chan error)
|
||||||
@@ -173,36 +176,29 @@ func (m *muxer) runInner() error {
|
|||||||
activityCheckTimer = emptyTimer()
|
activityCheckTimer = emptyTimer()
|
||||||
}
|
}
|
||||||
|
|
||||||
cumulatedOutboundFramesDiscarded := uint64(0)
|
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case req := <-m.chGetInstance:
|
|
||||||
req.res <- muxerGetInstanceRes{
|
|
||||||
instance: mi,
|
|
||||||
cumulatedOutboundFramesDiscarded: cumulatedOutboundFramesDiscarded,
|
|
||||||
}
|
|
||||||
|
|
||||||
case err = <-instanceError:
|
case err = <-instanceError:
|
||||||
if m.remoteAddr != "" {
|
if m.remoteAddr != "" {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
m.Log(logger.Error, err.Error())
|
m.Log(logger.Error, err.Error())
|
||||||
mi.close()
|
m.closeInstance()
|
||||||
cumulatedOutboundFramesDiscarded += mi.reader.OutboundFramesDiscarded()
|
|
||||||
mi = nil
|
|
||||||
instanceError = make(chan error)
|
instanceError = make(chan error)
|
||||||
recreateTimer = time.NewTimer(recreatePause)
|
recreateTimer = time.NewTimer(recreatePause)
|
||||||
|
|
||||||
case <-recreateTimer.C:
|
case <-recreateTimer.C:
|
||||||
mi, err = m.createInstance(res.Stream)
|
tmp, err = m.createInstance(res.Stream)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
m.Log(logger.Error, err.Error())
|
m.Log(logger.Error, err.Error())
|
||||||
mi = nil
|
|
||||||
recreateTimer = time.NewTimer(recreatePause)
|
recreateTimer = time.NewTimer(recreatePause)
|
||||||
} else {
|
} else {
|
||||||
instanceError = mi.errorChan()
|
m.instanceMutex.Lock()
|
||||||
|
m.instance = tmp
|
||||||
|
m.instanceMutex.Unlock()
|
||||||
|
|
||||||
|
instanceError = m.instance.errorChan()
|
||||||
}
|
}
|
||||||
|
|
||||||
case <-activityCheckTimer.C:
|
case <-activityCheckTimer.C:
|
||||||
@@ -218,6 +214,16 @@ func (m *muxer) runInner() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *muxer) closeInstance() {
|
||||||
|
m.instanceMutex.Lock()
|
||||||
|
m.cumulatedOutboundFramesDiscarded += m.instance.reader.OutboundFramesDiscarded()
|
||||||
|
var tmp *muxerInstance
|
||||||
|
tmp, m.instance = m.instance, nil
|
||||||
|
m.instanceMutex.Unlock()
|
||||||
|
|
||||||
|
tmp.close()
|
||||||
|
}
|
||||||
|
|
||||||
func (m *muxer) createInstance(strm *stream.Stream) (*muxerInstance, error) {
|
func (m *muxer) createInstance(strm *stream.Stream) (*muxerInstance, error) {
|
||||||
mi := &muxerInstance{
|
mi := &muxerInstance{
|
||||||
variant: m.variant,
|
variant: m.variant,
|
||||||
@@ -235,14 +241,12 @@ func (m *muxer) createInstance(strm *stream.Stream) (*muxerInstance, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *muxer) getInstance() muxerGetInstanceRes {
|
func (m *muxer) getInstance() muxerGetInstanceRes {
|
||||||
req := muxerGetInstanceReq{res: make(chan muxerGetInstanceRes)}
|
m.instanceMutex.RLock()
|
||||||
|
defer m.instanceMutex.RUnlock()
|
||||||
|
|
||||||
select {
|
return muxerGetInstanceRes{
|
||||||
case m.chGetInstance <- req:
|
instance: m.instance,
|
||||||
return <-req.res
|
cumulatedOutboundFramesDiscarded: m.cumulatedOutboundFramesDiscarded,
|
||||||
|
|
||||||
case <-m.ctx.Done():
|
|
||||||
return muxerGetInstanceRes{}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user