mirror of
https://github.com/aler9/gortsplib
synced 2025-10-05 15:16:51 +08:00
expose number of lost packets without passing through an error (#735)
This commit is contained in:
29
client.go
29
client.go
@@ -217,8 +217,13 @@ type ClientOnResponseFunc func(*base.Response)
|
|||||||
type ClientOnTransportSwitchFunc func(err error)
|
type ClientOnTransportSwitchFunc func(err error)
|
||||||
|
|
||||||
// ClientOnPacketLostFunc is the prototype of Client.OnPacketLost.
|
// ClientOnPacketLostFunc is the prototype of Client.OnPacketLost.
|
||||||
|
//
|
||||||
|
// Deprecated: replaced by ClientOnPacketLost2Func
|
||||||
type ClientOnPacketLostFunc func(err error)
|
type ClientOnPacketLostFunc func(err error)
|
||||||
|
|
||||||
|
// ClientOnPacketLost2Func is the prototype of Client.OnPacketLost2.
|
||||||
|
type ClientOnPacketLost2Func func(lost uint64)
|
||||||
|
|
||||||
// ClientOnDecodeErrorFunc is the prototype of Client.OnDecodeError.
|
// ClientOnDecodeErrorFunc is the prototype of Client.OnDecodeError.
|
||||||
type ClientOnDecodeErrorFunc func(err error)
|
type ClientOnDecodeErrorFunc func(err error)
|
||||||
|
|
||||||
@@ -276,9 +281,11 @@ type Client struct {
|
|||||||
// explicitly request back channels to the server.
|
// explicitly request back channels to the server.
|
||||||
RequestBackChannels bool
|
RequestBackChannels bool
|
||||||
// pointer to a variable that stores received bytes.
|
// pointer to a variable that stores received bytes.
|
||||||
|
//
|
||||||
// Deprecated: use Client.Stats()
|
// Deprecated: use Client.Stats()
|
||||||
BytesReceived *uint64
|
BytesReceived *uint64
|
||||||
// pointer to a variable that stores sent bytes.
|
// pointer to a variable that stores sent bytes.
|
||||||
|
//
|
||||||
// Deprecated: use Client.Stats()
|
// Deprecated: use Client.Stats()
|
||||||
BytesSent *uint64
|
BytesSent *uint64
|
||||||
|
|
||||||
@@ -306,7 +313,11 @@ type Client struct {
|
|||||||
// called when the transport protocol changes.
|
// called when the transport protocol changes.
|
||||||
OnTransportSwitch ClientOnTransportSwitchFunc
|
OnTransportSwitch ClientOnTransportSwitchFunc
|
||||||
// called when the client detects lost packets.
|
// called when the client detects lost packets.
|
||||||
|
//
|
||||||
|
// Deprecated: replaced by OnPacketLost2.
|
||||||
OnPacketLost ClientOnPacketLostFunc
|
OnPacketLost ClientOnPacketLostFunc
|
||||||
|
// called when the client detects lost packets.
|
||||||
|
OnPacketLost2 ClientOnPacketLost2Func
|
||||||
// called when a non-fatal decode error occurs.
|
// called when a non-fatal decode error occurs.
|
||||||
OnDecodeError ClientOnDecodeErrorFunc
|
OnDecodeError ClientOnDecodeErrorFunc
|
||||||
|
|
||||||
@@ -423,9 +434,21 @@ func (c *Client) Start(scheme string, host string) error {
|
|||||||
log.Println(err.Error())
|
log.Println(err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if c.OnPacketLost == nil {
|
if c.OnPacketLost != nil {
|
||||||
c.OnPacketLost = func(err error) {
|
c.OnPacketLost2 = func(lost uint64) {
|
||||||
log.Println(err.Error())
|
c.OnPacketLost(liberrors.ErrClientRTPPacketsLost{Lost: uint(lost)}) //nolint:staticcheck
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if c.OnPacketLost2 == nil {
|
||||||
|
c.OnPacketLost2 = func(lost uint64) {
|
||||||
|
log.Printf("%d RTP %s lost",
|
||||||
|
lost,
|
||||||
|
func() string {
|
||||||
|
if lost == 1 {
|
||||||
|
return "packet"
|
||||||
|
}
|
||||||
|
return "packets"
|
||||||
|
}())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if c.OnDecodeError == nil {
|
if c.OnDecodeError == nil {
|
||||||
|
@@ -12,7 +12,6 @@ import (
|
|||||||
"github.com/bluenviron/gortsplib/v4/internal/rtplossdetector"
|
"github.com/bluenviron/gortsplib/v4/internal/rtplossdetector"
|
||||||
"github.com/bluenviron/gortsplib/v4/internal/rtpreorderer"
|
"github.com/bluenviron/gortsplib/v4/internal/rtpreorderer"
|
||||||
"github.com/bluenviron/gortsplib/v4/pkg/format"
|
"github.com/bluenviron/gortsplib/v4/pkg/format"
|
||||||
"github.com/bluenviron/gortsplib/v4/pkg/liberrors"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type clientFormat struct {
|
type clientFormat struct {
|
||||||
@@ -129,9 +128,9 @@ func (cf *clientFormat) handlePacketRTP(pkt *rtp.Packet, now time.Time) {
|
|||||||
cf.onPacketRTP(pkt)
|
cf.onPacketRTP(pkt)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cf *clientFormat) onPacketRTPLost(lost uint) {
|
func (cf *clientFormat) onPacketRTPLost(lost uint64) {
|
||||||
atomic.AddUint64(cf.rtpPacketsLost, uint64(lost))
|
atomic.AddUint64(cf.rtpPacketsLost, lost)
|
||||||
cf.cm.c.OnPacketLost(liberrors.ErrClientRTPPacketsLost{Lost: lost})
|
cf.cm.c.OnPacketLost2(lost)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cf *clientFormat) writePacketRTPInQueueUDP(payload []byte) error {
|
func (cf *clientFormat) writePacketRTPInQueueUDP(payload []byte) error {
|
||||||
|
@@ -13,7 +13,7 @@ type LossDetector struct {
|
|||||||
|
|
||||||
// Process processes a RTP packet.
|
// Process processes a RTP packet.
|
||||||
// It returns the number of lost packets.
|
// It returns the number of lost packets.
|
||||||
func (r *LossDetector) Process(pkt *rtp.Packet) uint {
|
func (r *LossDetector) Process(pkt *rtp.Packet) uint64 {
|
||||||
if !r.initialized {
|
if !r.initialized {
|
||||||
r.initialized = true
|
r.initialized = true
|
||||||
r.expectedSeqNum = pkt.SequenceNumber + 1
|
r.expectedSeqNum = pkt.SequenceNumber + 1
|
||||||
@@ -23,7 +23,7 @@ func (r *LossDetector) Process(pkt *rtp.Packet) uint {
|
|||||||
if pkt.SequenceNumber != r.expectedSeqNum {
|
if pkt.SequenceNumber != r.expectedSeqNum {
|
||||||
diff := pkt.SequenceNumber - r.expectedSeqNum
|
diff := pkt.SequenceNumber - r.expectedSeqNum
|
||||||
r.expectedSeqNum = pkt.SequenceNumber + 1
|
r.expectedSeqNum = pkt.SequenceNumber + 1
|
||||||
return uint(diff)
|
return uint64(diff)
|
||||||
}
|
}
|
||||||
|
|
||||||
r.expectedSeqNum = pkt.SequenceNumber + 1
|
r.expectedSeqNum = pkt.SequenceNumber + 1
|
||||||
|
@@ -15,19 +15,19 @@ func TestLossDetector(t *testing.T) {
|
|||||||
SequenceNumber: 65530,
|
SequenceNumber: 65530,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
require.Equal(t, uint(0), c)
|
require.Equal(t, uint64(0), c)
|
||||||
|
|
||||||
c = d.Process(&rtp.Packet{
|
c = d.Process(&rtp.Packet{
|
||||||
Header: rtp.Header{
|
Header: rtp.Header{
|
||||||
SequenceNumber: 65531,
|
SequenceNumber: 65531,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
require.Equal(t, uint(0), c)
|
require.Equal(t, uint64(0), c)
|
||||||
|
|
||||||
c = d.Process(&rtp.Packet{
|
c = d.Process(&rtp.Packet{
|
||||||
Header: rtp.Header{
|
Header: rtp.Header{
|
||||||
SequenceNumber: 65535,
|
SequenceNumber: 65535,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
require.Equal(t, uint(3), c)
|
require.Equal(t, uint64(3), c)
|
||||||
}
|
}
|
||||||
|
@@ -27,7 +27,7 @@ func (r *Reorderer) Initialize() {
|
|||||||
|
|
||||||
// Process processes a RTP packet.
|
// Process processes a RTP packet.
|
||||||
// It returns a sequence of ordered packets and the number of lost packets.
|
// It returns a sequence of ordered packets and the number of lost packets.
|
||||||
func (r *Reorderer) Process(pkt *rtp.Packet) ([]*rtp.Packet, uint) {
|
func (r *Reorderer) Process(pkt *rtp.Packet) ([]*rtp.Packet, uint64) {
|
||||||
if !r.initialized {
|
if !r.initialized {
|
||||||
r.initialized = true
|
r.initialized = true
|
||||||
r.expectedSeqNum = pkt.SequenceNumber + 1
|
r.expectedSeqNum = pkt.SequenceNumber + 1
|
||||||
@@ -86,7 +86,7 @@ func (r *Reorderer) Process(pkt *rtp.Packet) ([]*rtp.Packet, uint) {
|
|||||||
ret[pos] = pkt
|
ret[pos] = pkt
|
||||||
|
|
||||||
r.expectedSeqNum = pkt.SequenceNumber + 1
|
r.expectedSeqNum = pkt.SequenceNumber + 1
|
||||||
return ret, uint(int(relPos) - n + 1)
|
return ret, uint64(int(relPos) - n + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// there's a missing packet
|
// there's a missing packet
|
||||||
|
@@ -164,7 +164,7 @@ func TestReorder(t *testing.T) {
|
|||||||
for _, entry := range sequence {
|
for _, entry := range sequence {
|
||||||
out, missing := r.Process(entry.in)
|
out, missing := r.Process(entry.in)
|
||||||
require.Equal(t, entry.out, out)
|
require.Equal(t, entry.out, out)
|
||||||
require.Equal(t, uint(0), missing)
|
require.Equal(t, uint64(0), missing)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,7 +173,7 @@ func TestBufferIsFull(t *testing.T) {
|
|||||||
r.Initialize()
|
r.Initialize()
|
||||||
r.absPos = 25
|
r.absPos = 25
|
||||||
sn := uint16(1564)
|
sn := uint16(1564)
|
||||||
toMiss := uint(34)
|
toMiss := uint64(34)
|
||||||
|
|
||||||
out, missing := r.Process(&rtp.Packet{
|
out, missing := r.Process(&rtp.Packet{
|
||||||
Header: rtp.Header{
|
Header: rtp.Header{
|
||||||
@@ -185,19 +185,19 @@ func TestBufferIsFull(t *testing.T) {
|
|||||||
SequenceNumber: sn,
|
SequenceNumber: sn,
|
||||||
},
|
},
|
||||||
}}, out)
|
}}, out)
|
||||||
require.Equal(t, uint(0), missing)
|
require.Equal(t, uint64(0), missing)
|
||||||
sn++
|
sn++
|
||||||
|
|
||||||
var expected []*rtp.Packet
|
var expected []*rtp.Packet
|
||||||
|
|
||||||
for i := uint(0); i < 64-toMiss; i++ {
|
for i := uint64(0); i < 64-toMiss; i++ {
|
||||||
out, missing = r.Process(&rtp.Packet{
|
out, missing = r.Process(&rtp.Packet{
|
||||||
Header: rtp.Header{
|
Header: rtp.Header{
|
||||||
SequenceNumber: sn + uint16(toMiss),
|
SequenceNumber: sn + uint16(toMiss),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
require.Equal(t, []*rtp.Packet(nil), out)
|
require.Equal(t, []*rtp.Packet(nil), out)
|
||||||
require.Equal(t, uint(0), missing)
|
require.Equal(t, uint64(0), missing)
|
||||||
|
|
||||||
expected = append(expected, &rtp.Packet{
|
expected = append(expected, &rtp.Packet{
|
||||||
Header: rtp.Header{
|
Header: rtp.Header{
|
||||||
@@ -242,7 +242,7 @@ func TestReset(t *testing.T) {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
require.Equal(t, []*rtp.Packet(nil), out)
|
require.Equal(t, []*rtp.Packet(nil), out)
|
||||||
require.Equal(t, uint(0), missing)
|
require.Equal(t, uint64(0), missing)
|
||||||
sn++
|
sn++
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -256,5 +256,5 @@ func TestReset(t *testing.T) {
|
|||||||
SequenceNumber: sn,
|
SequenceNumber: sn,
|
||||||
},
|
},
|
||||||
}}, out)
|
}}, out)
|
||||||
require.Equal(t, uint(0), missing)
|
require.Equal(t, uint64(0), missing)
|
||||||
}
|
}
|
||||||
|
@@ -17,6 +17,7 @@ type Opus struct {
|
|||||||
PayloadTyp uint8
|
PayloadTyp uint8
|
||||||
ChannelCount int
|
ChannelCount int
|
||||||
|
|
||||||
|
//
|
||||||
// Deprecated: replaced by ChannelCount.
|
// Deprecated: replaced by ChannelCount.
|
||||||
IsStereo bool
|
IsStereo bool
|
||||||
}
|
}
|
||||||
|
@@ -250,6 +250,8 @@ func (e ErrClientWriteQueueFull) Error() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ErrClientRTPPacketsLost is an error that can be returned by a client.
|
// ErrClientRTPPacketsLost is an error that can be returned by a client.
|
||||||
|
//
|
||||||
|
// Deprecated: will be removed in next version.
|
||||||
type ErrClientRTPPacketsLost struct {
|
type ErrClientRTPPacketsLost struct {
|
||||||
Lost uint
|
Lost uint
|
||||||
}
|
}
|
||||||
|
@@ -239,6 +239,8 @@ func (e ErrServerUnexpectedResponse) Error() string {
|
|||||||
type ErrServerWriteQueueFull = ErrClientWriteQueueFull
|
type ErrServerWriteQueueFull = ErrClientWriteQueueFull
|
||||||
|
|
||||||
// ErrServerRTPPacketsLost is an error that can be returned by a server.
|
// ErrServerRTPPacketsLost is an error that can be returned by a server.
|
||||||
|
//
|
||||||
|
// Deprecated: will be removed in next version.
|
||||||
type ErrServerRTPPacketsLost = ErrClientRTPPacketsLost
|
type ErrServerRTPPacketsLost = ErrClientRTPPacketsLost
|
||||||
|
|
||||||
// ErrServerRTPPacketUnknownPayloadType is an error that can be returned by a server.
|
// ErrServerRTPPacketUnknownPayloadType is an error that can be returned by a server.
|
||||||
|
@@ -19,5 +19,5 @@ func New() *LossDetector {
|
|||||||
// Process processes a RTP packet.
|
// Process processes a RTP packet.
|
||||||
// It returns the number of lost packets.
|
// It returns the number of lost packets.
|
||||||
func (r *LossDetector) Process(pkt *rtp.Packet) uint {
|
func (r *LossDetector) Process(pkt *rtp.Packet) uint {
|
||||||
return (*rtplossdetector.LossDetector)(r).Process(pkt)
|
return uint((*rtplossdetector.LossDetector)(r).Process(pkt))
|
||||||
}
|
}
|
||||||
|
@@ -23,5 +23,6 @@ func New() *Reorderer {
|
|||||||
// Process processes a RTP packet.
|
// Process processes a RTP packet.
|
||||||
// It returns a sequence of ordered packets and the number of lost packets.
|
// It returns a sequence of ordered packets and the number of lost packets.
|
||||||
func (r *Reorderer) Process(pkt *rtp.Packet) ([]*rtp.Packet, uint) {
|
func (r *Reorderer) Process(pkt *rtp.Packet) ([]*rtp.Packet, uint) {
|
||||||
return (*rtpreorderer.Reorderer)(r).Process(pkt)
|
v1, v2 := (*rtpreorderer.Reorderer)(r).Process(pkt)
|
||||||
|
return v1, uint(v2)
|
||||||
}
|
}
|
||||||
|
@@ -195,7 +195,11 @@ type ServerHandlerOnSetParameter interface {
|
|||||||
// ServerHandlerOnPacketLostCtx is the context of OnPacketLost.
|
// ServerHandlerOnPacketLostCtx is the context of OnPacketLost.
|
||||||
type ServerHandlerOnPacketLostCtx struct {
|
type ServerHandlerOnPacketLostCtx struct {
|
||||||
Session *ServerSession
|
Session *ServerSession
|
||||||
Error error
|
Lost uint64
|
||||||
|
|
||||||
|
//
|
||||||
|
// Deprecated: replaced by Lost
|
||||||
|
Error error
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServerHandlerOnPacketLost can be implemented by a ServerHandler.
|
// ServerHandlerOnPacketLost can be implemented by a ServerHandler.
|
||||||
|
@@ -112,16 +112,24 @@ func (sf *serverSessionFormat) handlePacketRTP(pkt *rtp.Packet, now time.Time) {
|
|||||||
sf.onPacketRTP(pkt)
|
sf.onPacketRTP(pkt)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sf *serverSessionFormat) onPacketRTPLost(lost uint) {
|
func (sf *serverSessionFormat) onPacketRTPLost(lost uint64) {
|
||||||
atomic.AddUint64(sf.rtpPacketsLost, uint64(lost))
|
atomic.AddUint64(sf.rtpPacketsLost, lost)
|
||||||
|
|
||||||
if h, ok := sf.sm.ss.s.Handler.(ServerHandlerOnPacketLost); ok {
|
if h, ok := sf.sm.ss.s.Handler.(ServerHandlerOnPacketLost); ok {
|
||||||
h.OnPacketLost(&ServerHandlerOnPacketLostCtx{
|
h.OnPacketLost(&ServerHandlerOnPacketLostCtx{
|
||||||
Session: sf.sm.ss,
|
Session: sf.sm.ss,
|
||||||
Error: liberrors.ErrServerRTPPacketsLost{Lost: lost},
|
Lost: lost,
|
||||||
|
Error: liberrors.ErrServerRTPPacketsLost{Lost: uint(lost)}, //nolint:staticcheck
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
log.Println(liberrors.ErrServerRTPPacketsLost{Lost: lost}.Error())
|
log.Printf("%d RTP %s lost",
|
||||||
|
lost,
|
||||||
|
func() string {
|
||||||
|
if lost == 1 {
|
||||||
|
return "packet"
|
||||||
|
}
|
||||||
|
return "packets"
|
||||||
|
}())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user