mediamtx/internal/core/rtsp_server.go

335 lines
7.5 KiB
Go
Raw Normal View History

package core
2020-10-19 20:17:48 +00:00
import (
2021-05-10 19:32:59 +00:00
"context"
"crypto/rand"
2021-03-06 08:11:46 +00:00
"crypto/tls"
"encoding/binary"
"strconv"
2021-04-27 11:43:15 +00:00
"sync"
2021-03-06 08:11:46 +00:00
"time"
2020-12-06 17:01:10 +00:00
"github.com/aler9/gortsplib"
2021-04-27 11:43:15 +00:00
"github.com/aler9/gortsplib/pkg/base"
"github.com/aler9/rtsp-simple-server/internal/conf"
"github.com/aler9/rtsp-simple-server/internal/logger"
2020-10-19 20:17:48 +00:00
)
func newSessionVisualID(sessions map[*gortsplib.ServerSession]*rtspSession) (string, error) {
for {
b := make([]byte, 4)
_, err := rand.Read(b)
if err != nil {
return "", err
}
id := strconv.FormatUint(uint64(binary.LittleEndian.Uint32(b)), 10)
alreadyPresent := func() bool {
for _, s := range sessions {
if s.VisualID() == id {
return true
}
}
return false
}()
if !alreadyPresent {
return id, nil
}
}
}
type rtspServerParent interface {
Log(logger.Level, string, ...interface{})
2020-10-19 20:17:48 +00:00
}
type rtspServer struct {
2021-04-27 11:43:15 +00:00
readTimeout time.Duration
isTLS bool
rtspAddress string
protocols map[conf.Protocol]struct{}
2021-04-27 11:43:15 +00:00
runOnConnect string
runOnConnectRestart bool
stats *stats
pathManager *pathManager
parent rtspServerParent
2021-04-27 11:43:15 +00:00
2021-05-10 19:32:59 +00:00
ctx context.Context
ctxCancel func()
wg sync.WaitGroup
srv *gortsplib.Server
mutex sync.RWMutex
conns map[*gortsplib.ServerConn]*rtspConn
sessions map[*gortsplib.ServerSession]*rtspSession
2020-10-19 20:17:48 +00:00
}
func newRTSPServer(
parentCtx context.Context,
address string,
2021-03-06 08:11:46 +00:00
readTimeout time.Duration,
writeTimeout time.Duration,
readBufferCount int,
readBufferSize int,
2021-03-06 08:11:46 +00:00
useUDP bool,
useMulticast bool,
rtpAddress string,
rtcpAddress string,
multicastIPRange string,
multicastRTPPort int,
multicastRTCPPort int,
2021-04-27 11:43:15 +00:00
isTLS bool,
2021-03-06 08:11:46 +00:00
serverCert string,
serverKey string,
2021-04-27 11:43:15 +00:00
rtspAddress string,
protocols map[conf.Protocol]struct{},
2021-04-27 11:43:15 +00:00
runOnConnect string,
runOnConnectRestart bool,
stats *stats,
pathManager *pathManager,
parent rtspServerParent) (*rtspServer, error) {
ctx, ctxCancel := context.WithCancel(parentCtx)
2021-05-10 19:32:59 +00:00
s := &rtspServer{
2021-05-07 21:07:31 +00:00
readTimeout: readTimeout,
isTLS: isTLS,
rtspAddress: rtspAddress,
protocols: protocols,
stats: stats,
pathManager: pathManager,
2021-05-07 21:07:31 +00:00
parent: parent,
2021-05-10 19:32:59 +00:00
ctx: ctx,
ctxCancel: ctxCancel,
conns: make(map[*gortsplib.ServerConn]*rtspConn),
sessions: make(map[*gortsplib.ServerSession]*rtspSession),
2021-05-07 21:07:31 +00:00
}
s.srv = &gortsplib.Server{
Handler: s,
2021-03-06 08:11:46 +00:00
ReadTimeout: readTimeout,
WriteTimeout: writeTimeout,
ReadBufferCount: readBufferCount,
ReadBufferSize: readBufferSize,
2021-03-06 08:11:46 +00:00
}
if useUDP {
2021-05-07 21:07:31 +00:00
s.srv.UDPRTPAddress = rtpAddress
s.srv.UDPRTCPAddress = rtcpAddress
2021-03-06 08:11:46 +00:00
}
if useMulticast {
s.srv.MulticastIPRange = multicastIPRange
s.srv.MulticastRTPPort = multicastRTPPort
s.srv.MulticastRTCPPort = multicastRTCPPort
}
2021-04-27 11:43:15 +00:00
if isTLS {
2021-03-06 08:11:46 +00:00
cert, err := tls.LoadX509KeyPair(serverCert, serverKey)
if err != nil {
return nil, err
}
2021-05-07 21:07:31 +00:00
s.srv.TLSConfig = &tls.Config{Certificates: []tls.Certificate{cert}}
2021-03-06 08:11:46 +00:00
}
2021-05-07 21:07:31 +00:00
err := s.srv.Start(address)
2020-10-19 20:17:48 +00:00
if err != nil {
return nil, err
}
2021-05-07 21:07:31 +00:00
if s.srv.UDPRTPAddress != "" {
s.Log(logger.Info, "UDP/RTP listener opened on %s", s.srv.UDPRTPAddress)
}
2021-03-06 08:54:10 +00:00
2021-05-07 21:07:31 +00:00
if s.srv.UDPRTCPAddress != "" {
s.Log(logger.Info, "UDP/RTCP listener opened on %s", s.srv.UDPRTCPAddress)
}
2021-03-06 08:54:10 +00:00
2021-04-27 11:43:15 +00:00
s.Log(logger.Info, "TCP listener opened on %s", address)
2021-05-10 19:32:59 +00:00
s.wg.Add(1)
go s.run()
return s, nil
}
func (s *rtspServer) Log(level logger.Level, format string, args ...interface{}) {
label := func() string {
2021-04-27 11:43:15 +00:00
if s.isTLS {
return "RTSPS"
}
2021-04-27 11:43:15 +00:00
return "RTSP"
}()
2021-04-27 11:43:15 +00:00
s.parent.Log(level, "[%s] "+format, append([]interface{}{label}, args...)...)
2020-10-19 20:17:48 +00:00
}
func (s *rtspServer) close() {
2021-05-10 19:32:59 +00:00
s.ctxCancel()
s.wg.Wait()
2020-10-19 20:17:48 +00:00
}
func (s *rtspServer) run() {
2021-05-10 19:32:59 +00:00
defer s.wg.Done()
2020-10-19 20:17:48 +00:00
2021-05-10 19:32:59 +00:00
s.wg.Add(1)
2021-05-07 21:07:31 +00:00
serverErr := make(chan error)
2021-04-27 11:43:15 +00:00
go func() {
2021-05-10 19:32:59 +00:00
defer s.wg.Done()
err := s.srv.Wait()
select {
case serverErr <- err:
case <-s.ctx.Done():
}
2021-04-27 11:43:15 +00:00
}()
outer:
2021-05-07 21:07:31 +00:00
select {
case err := <-serverErr:
s.Log(logger.Warn, "ERR: %s", err)
break outer
2021-05-10 19:32:59 +00:00
case <-s.ctx.Done():
2021-05-07 21:07:31 +00:00
break outer
2021-04-27 11:43:15 +00:00
}
2021-05-10 19:32:59 +00:00
s.ctxCancel()
2020-10-19 20:17:48 +00:00
2021-04-27 11:43:15 +00:00
s.srv.Close()
2021-05-07 21:07:31 +00:00
}
// OnConnOpen implements gortsplib.ServerHandlerOnConnOpen.
func (s *rtspServer) OnConnOpen(ctx *gortsplib.ServerHandlerOnConnOpenCtx) {
c := newRTSPConn(
2021-05-07 21:07:31 +00:00
s.rtspAddress,
s.readTimeout,
s.runOnConnect,
s.runOnConnectRestart,
s.pathManager,
2021-05-07 21:07:31 +00:00
s.stats,
ctx.Conn,
2021-05-07 21:07:31 +00:00
s)
s.mutex.Lock()
2021-05-09 12:41:18 +00:00
s.conns[ctx.Conn] = c
2021-05-07 21:07:31 +00:00
s.mutex.Unlock()
}
// OnConnClose implements gortsplib.ServerHandlerOnConnClose.
func (s *rtspServer) OnConnClose(ctx *gortsplib.ServerHandlerOnConnCloseCtx) {
2021-05-07 21:07:31 +00:00
s.mutex.Lock()
2021-05-09 12:41:18 +00:00
c := s.conns[ctx.Conn]
delete(s.conns, ctx.Conn)
2021-05-07 21:07:31 +00:00
s.mutex.Unlock()
2021-05-09 14:12:15 +00:00
c.ParentClose(ctx.Error)
2021-05-07 21:07:31 +00:00
}
// OnRequest implements gortsplib.ServerHandlerOnRequest.
func (s *rtspServer) OnRequest(sc *gortsplib.ServerConn, req *base.Request) {
2021-05-07 21:07:31 +00:00
s.mutex.Lock()
2021-05-09 12:41:18 +00:00
c := s.conns[sc]
2021-05-07 21:07:31 +00:00
s.mutex.Unlock()
c.OnRequest(req)
}
// OnResponse implements gortsplib.ServerHandlerOnResponse.
func (s *rtspServer) OnResponse(sc *gortsplib.ServerConn, res *base.Response) {
2021-05-07 21:07:31 +00:00
s.mutex.Lock()
2021-05-09 12:41:18 +00:00
c := s.conns[sc]
2021-05-07 21:07:31 +00:00
s.mutex.Unlock()
c.OnResponse(res)
}
// OnSessionOpen implements gortsplib.ServerHandlerOnSessionOpen.
func (s *rtspServer) OnSessionOpen(ctx *gortsplib.ServerHandlerOnSessionOpenCtx) {
s.mutex.Lock()
// do not use ss.ID() in logs, since it allows to take ownership of a session
// use a new random ID
visualID, _ := newSessionVisualID(s.sessions)
se := newRTSPSession(
2021-05-07 21:07:31 +00:00
s.rtspAddress,
s.protocols,
visualID,
ctx.Session,
ctx.Conn,
s.pathManager,
2021-05-07 21:07:31 +00:00
s)
s.sessions[ctx.Session] = se
2021-05-07 21:07:31 +00:00
s.mutex.Unlock()
}
// OnSessionClose implements gortsplib.ServerHandlerOnSessionClose.
func (s *rtspServer) OnSessionClose(ctx *gortsplib.ServerHandlerOnSessionCloseCtx) {
2021-05-07 21:07:31 +00:00
s.mutex.Lock()
se := s.sessions[ctx.Session]
delete(s.sessions, ctx.Session)
2021-05-07 21:07:31 +00:00
s.mutex.Unlock()
2020-10-19 20:17:48 +00:00
2021-05-09 14:12:15 +00:00
se.ParentClose()
2021-05-07 21:07:31 +00:00
}
// OnDescribe implements gortsplib.ServerHandlerOnDescribe.
func (s *rtspServer) OnDescribe(ctx *gortsplib.ServerHandlerOnDescribeCtx) (*base.Response, *gortsplib.ServerStream, error) {
2021-05-07 21:07:31 +00:00
s.mutex.RLock()
2021-05-09 12:41:18 +00:00
c := s.conns[ctx.Conn]
2021-05-07 21:07:31 +00:00
s.mutex.RUnlock()
return c.OnDescribe(ctx)
}
// OnAnnounce implements gortsplib.ServerHandlerOnAnnounce.
func (s *rtspServer) OnAnnounce(ctx *gortsplib.ServerHandlerOnAnnounceCtx) (*base.Response, error) {
2021-05-07 21:07:31 +00:00
s.mutex.RLock()
2021-05-09 12:41:18 +00:00
c := s.conns[ctx.Conn]
2021-05-07 21:07:31 +00:00
se := s.sessions[ctx.Session]
s.mutex.RUnlock()
return se.OnAnnounce(c, ctx)
}
// OnSetup implements gortsplib.ServerHandlerOnSetup.
func (s *rtspServer) OnSetup(ctx *gortsplib.ServerHandlerOnSetupCtx) (*base.Response, *gortsplib.ServerStream, error) {
2021-05-07 21:07:31 +00:00
s.mutex.RLock()
2021-05-09 12:41:18 +00:00
c := s.conns[ctx.Conn]
2021-05-07 21:07:31 +00:00
se := s.sessions[ctx.Session]
s.mutex.RUnlock()
return se.OnSetup(c, ctx)
}
// OnPlay implements gortsplib.ServerHandlerOnPlay.
func (s *rtspServer) OnPlay(ctx *gortsplib.ServerHandlerOnPlayCtx) (*base.Response, error) {
2021-05-07 21:07:31 +00:00
s.mutex.RLock()
se := s.sessions[ctx.Session]
s.mutex.RUnlock()
return se.OnPlay(ctx)
}
2021-04-27 11:43:15 +00:00
// OnRecord implements gortsplib.ServerHandlerOnRecord.
func (s *rtspServer) OnRecord(ctx *gortsplib.ServerHandlerOnRecordCtx) (*base.Response, error) {
2021-05-07 21:07:31 +00:00
s.mutex.RLock()
se := s.sessions[ctx.Session]
s.mutex.RUnlock()
return se.OnRecord(ctx)
2021-04-27 11:43:15 +00:00
}
// OnPause implements gortsplib.ServerHandlerOnPause.
func (s *rtspServer) OnPause(ctx *gortsplib.ServerHandlerOnPauseCtx) (*base.Response, error) {
2021-05-07 21:07:31 +00:00
s.mutex.RLock()
se := s.sessions[ctx.Session]
s.mutex.RUnlock()
return se.OnPause(ctx)
2020-10-19 20:17:48 +00:00
}
// OnFrame implements gortsplib.ServerHandlerOnFrame.
func (s *rtspServer) OnFrame(ctx *gortsplib.ServerHandlerOnFrameCtx) {
2021-05-07 21:07:31 +00:00
s.mutex.RLock()
se := s.sessions[ctx.Session]
s.mutex.RUnlock()
se.OnIncomingFrame(ctx)
2020-10-19 20:17:48 +00:00
}