From b617796941f7e139046d08f0c49c30a92c7acb5d Mon Sep 17 00:00:00 2001 From: Alexey Khit Date: Sun, 13 Nov 2022 14:35:53 +0300 Subject: [PATCH] Improve RTCP for HomeKit --- cmd/srtp/srtp.go | 9 +++---- pkg/srtp/session.go | 57 +++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 56 insertions(+), 10 deletions(-) diff --git a/cmd/srtp/srtp.go b/cmd/srtp/srtp.go index 7f251ee4..a8e2c8b6 100644 --- a/cmd/srtp/srtp.go +++ b/cmd/srtp/srtp.go @@ -3,7 +3,6 @@ package srtp import ( "github.com/AlexxIT/go2rtc/cmd/app" "github.com/AlexxIT/go2rtc/pkg/srtp" - "github.com/rs/zerolog" "net" ) @@ -24,12 +23,12 @@ func Init() { return } - log = app.GetLogger("srtp") + log := app.GetLogger("srtp") // create SRTP server (endpoint) for receiving video from HomeKit camera conn, err := net.ListenPacket("udp", cfg.Mod.Listen) if err != nil { - log.Warn().Err(err).Msg("[srtp] listen") + log.Warn().Err(err).Caller().Send() } log.Info().Str("addr", cfg.Mod.Listen).Msg("[srtp] listen") @@ -38,11 +37,9 @@ func Init() { go func() { Server = &srtp.Server{} if err = Server.Serve(conn); err != nil { - log.Warn().Err(err).Msg("[srtp] serve") + log.Warn().Err(err).Caller().Send() } }() } var Server *srtp.Server - -var log zerolog.Logger diff --git a/pkg/srtp/session.go b/pkg/srtp/session.go index 1bb8208d..07321396 100644 --- a/pkg/srtp/session.go +++ b/pkg/srtp/session.go @@ -5,6 +5,7 @@ import ( "github.com/pion/rtcp" "github.com/pion/rtp" "github.com/pion/srtp/v2" + "time" ) type Session struct { @@ -16,6 +17,14 @@ type Session struct { Write func(b []byte) (int, error) Track *streamer.Track + + lastSequence uint32 + lastTimestamp uint32 + //lastPacket *rtp.Packet + lastTime time.Time + jitter float64 + //sequenceCycle uint16 + totalLost uint32 } func (s *Session) SetKeys( @@ -46,8 +55,33 @@ func (s *Session) HandleRTP(data []byte) (err error) { return } + now := time.Now() + + // https://www.ietf.org/rfc/rfc3550.txt + if s.lastTimestamp != 0 { + delta := packet.SequenceNumber - uint16(s.lastSequence) + + // lost packet + if delta > 1 { + s.totalLost += uint32(delta - 1) + } + + // D(i,j) = (Rj - Ri) - (Sj - Si) = (Rj - Sj) - (Ri - Si) + dTime := now.Sub(s.lastTime).Seconds()*float64(s.Track.Codec.ClockRate) - + float64(packet.Timestamp-s.lastTimestamp) + if dTime < 0 { + dTime = -dTime + } + // J(i) = J(i-1) + (|D(i-1,i)| - J(i-1))/16 + s.jitter += (dTime - s.jitter) / 16 + } + + // keeping cycles (overflow) + s.lastSequence = s.lastSequence&0xFFFF0000 | uint32(packet.SequenceNumber) + s.lastTimestamp = packet.Timestamp + s.lastTime = now + _ = s.Track.WriteRTP(packet) - //s.Output(core.RTP{Channel: s.Channel, Packet: packet}) return } @@ -64,7 +98,6 @@ func (s *Session) HandleRTCP(data []byte) (err error) { } _ = packets - //s.Output(core.RTCP{Channel: s.Channel + 1, Header: header, Packets: packets}) if header.Type == rtcp.TypeSenderReport { err = s.KeepAlive() @@ -74,9 +107,25 @@ func (s *Session) HandleRTCP(data []byte) (err error) { } func (s *Session) KeepAlive() (err error) { - var data []byte - // we can send empty receiver response, but should send it to hold the connection rep := rtcp.ReceiverReport{SSRC: s.LocalSSRC} + + if s.lastTimestamp > 0 { + //log.Printf("[RTCP] ssrc=%d seq=%d lost=%d jit=%.2f", s.RemoteSSRC, s.lastSequence, s.totalLost, s.jitter) + + rep.Reports = []rtcp.ReceptionReport{{ + SSRC: s.RemoteSSRC, + LastSequenceNumber: s.lastSequence, + LastSenderReport: s.lastTimestamp, + FractionLost: 0, // TODO + TotalLost: s.totalLost, + Delay: 0, // send just after receive + Jitter: uint32(s.jitter), + }} + } + + // we can send empty receiver response, but should send it to hold the connection + + var data []byte if data, err = rep.Marshal(); err != nil { return }