Browse Source

add ticker to check whether udp packets are being received or not while publishing; fix #15

pull/31/head
aler9 5 years ago
parent
commit
60371afc1a
  1. 71
      server-client.go
  2. 29
      server-udpl.go

71
server-client.go

@ -8,11 +8,17 @@ import (
"net" "net"
"os/exec" "os/exec"
"strings" "strings"
"time"
"github.com/aler9/gortsplib" "github.com/aler9/gortsplib"
"gortc.io/sdp" "gortc.io/sdp"
) )
const (
_UDP_CHECK_STREAM_INTERVAL = 5 * time.Second
_UDP_STREAM_DEAD_AFTER = 10 * time.Second
)
func interleavedChannelToTrack(channel uint8) (int, trackFlow) { func interleavedChannelToTrack(channel uint8) (int, trackFlow) {
if (channel % 2) == 0 { if (channel % 2) == 0 {
return int(channel / 2), _TRACK_FLOW_RTP return int(channel / 2), _TRACK_FLOW_RTP
@ -62,18 +68,20 @@ func (cs clientState) String() string {
} }
type serverClient struct { type serverClient struct {
p *program p *program
conn *gortsplib.ConnServer conn *gortsplib.ConnServer
state clientState state clientState
path string path string
publishAuth *gortsplib.AuthServer publishAuth *gortsplib.AuthServer
readAuth *gortsplib.AuthServer readAuth *gortsplib.AuthServer
streamSdpText []byte // filled only if publisher streamSdpText []byte // filled only if publisher
streamSdpParsed *sdp.Message // filled only if publisher streamSdpParsed *sdp.Message // filled only if publisher
streamProtocol streamProtocol streamProtocol streamProtocol
streamTracks []*track streamTracks []*track
write chan *gortsplib.InterleavedFrame udpLastFrameTime time.Time
done chan struct{} udpCheckStreamTicker *time.Ticker
write chan *gortsplib.InterleavedFrame
done chan struct{}
} }
func newServerClient(p *program, nconn net.Conn) *serverClient { func newServerClient(p *program, nconn net.Conn) *serverClient {
@ -170,6 +178,10 @@ func (c *serverClient) run() {
c.close() c.close()
}() }()
if c.udpCheckStreamTicker != nil {
c.udpCheckStreamTicker.Stop()
}
c.log("disconnected") c.log("disconnected")
func() { func() {
@ -262,6 +274,7 @@ func (c *serverClient) validateAuth(req *gortsplib.Request, user string, pass st
return errAuthNotCritical return errAuthNotCritical
} }
return nil return nil
}() }()
if err != nil { if err != nil {
@ -871,10 +884,6 @@ func (c *serverClient) handleRequest(req *gortsplib.Request) bool {
}, },
}) })
c.p.tcpl.mutex.Lock()
c.state = _CLIENT_STATE_RECORD
c.p.tcpl.mutex.Unlock()
c.log("is publishing on path '%s', %d %s via %s", c.path, len(c.streamTracks), func() string { c.log("is publishing on path '%s', %d %s via %s", c.path, len(c.streamTracks), func() string {
if len(c.streamTracks) == 1 { if len(c.streamTracks) == 1 {
return "track" return "track"
@ -885,6 +894,10 @@ func (c *serverClient) handleRequest(req *gortsplib.Request) bool {
// when protocol is TCP, the RTSP connection becomes a RTP connection // when protocol is TCP, the RTSP connection becomes a RTP connection
// receive RTP data and parse it // receive RTP data and parse it
if c.streamProtocol == _STREAM_PROTOCOL_TCP { if c.streamProtocol == _STREAM_PROTOCOL_TCP {
c.p.tcpl.mutex.Lock()
c.state = _CLIENT_STATE_RECORD
c.p.tcpl.mutex.Unlock()
for { for {
frame, err := c.conn.ReadInterleavedFrame() frame, err := c.conn.ReadInterleavedFrame()
if err != nil { if err != nil {
@ -905,6 +918,32 @@ func (c *serverClient) handleRequest(req *gortsplib.Request) bool {
c.p.tcpl.forwardTrack(c.path, trackId, trackFlow, frame.Content) c.p.tcpl.forwardTrack(c.path, trackId, trackFlow, frame.Content)
c.p.tcpl.mutex.RUnlock() c.p.tcpl.mutex.RUnlock()
} }
} else {
c.p.tcpl.mutex.Lock()
c.state = _CLIENT_STATE_RECORD
c.udpLastFrameTime = time.Now()
c.udpCheckStreamTicker = time.NewTicker(_UDP_CHECK_STREAM_INTERVAL)
c.p.tcpl.mutex.Unlock()
go func() {
for range c.udpCheckStreamTicker.C {
ok := func() bool {
c.p.tcpl.mutex.Lock()
defer c.p.tcpl.mutex.Unlock()
if time.Since(c.udpLastFrameTime) >= _UDP_STREAM_DEAD_AFTER {
return false
}
return true
}()
if !ok {
c.log("ERR: stream is dead")
c.conn.NetConn().Close()
break
}
}
}()
} }
return true return true

29
server-udpl.go

@ -68,35 +68,38 @@ func (l *serverUdpListener) run() {
} }
func() { func() {
l.p.tcpl.mutex.RLock() l.p.tcpl.mutex.Lock()
defer l.p.tcpl.mutex.RUnlock() defer l.p.tcpl.mutex.Unlock()
// find path and track id from ip and port // find publisher and track id from ip and port
path, trackId := func() (string, int) { pub, trackId := func() (*serverClient, int) {
for _, pub := range l.p.tcpl.publishers { for _, pub := range l.p.tcpl.publishers {
for i, t := range pub.streamTracks { if pub.streamProtocol != _STREAM_PROTOCOL_UDP ||
if !pub.ip().Equal(addr.IP) { pub.state != _CLIENT_STATE_RECORD ||
continue !pub.ip().Equal(addr.IP) {
} continue
}
for i, t := range pub.streamTracks {
if l.flow == _TRACK_FLOW_RTP { if l.flow == _TRACK_FLOW_RTP {
if t.rtpPort == addr.Port { if t.rtpPort == addr.Port {
return pub.path, i return pub, i
} }
} else { } else {
if t.rtcpPort == addr.Port { if t.rtcpPort == addr.Port {
return pub.path, i return pub, i
} }
} }
} }
} }
return "", -1 return nil, -1
}() }()
if path == "" { if pub == nil {
return return
} }
l.p.tcpl.forwardTrack(path, trackId, l.flow, buf[:n]) pub.udpLastFrameTime = time.Now()
l.p.tcpl.forwardTrack(pub.path, trackId, l.flow, buf[:n])
}() }()
} }

Loading…
Cancel
Save