Rewrite HomeKit client

This commit is contained in:
Alexey Khit
2023-08-30 21:52:06 +03:00
parent 7d65c60711
commit 22787b979d
30 changed files with 1094 additions and 916 deletions
+70 -116
View File
@@ -1,154 +1,108 @@
package srtp
import (
"time"
"net"
"github.com/AlexxIT/go2rtc/pkg/core"
"github.com/pion/rtcp"
"github.com/pion/rtp"
"github.com/pion/srtp/v2"
)
type Session struct {
LocalSSRC uint32 // outgoing SSRC
RemoteSSRC uint32 // incoming SSRC
Local *Endpoint
Remote *Endpoint
localCtx *srtp.Context // write context
remoteCtx *srtp.Context // read context
OnReadRTP func(packet *rtp.Packet)
Write func(b []byte) (int, error)
Track *core.Receiver
Recv uint32
Recv int // bytes recv
Send int // bytes send
Deadline *time.Timer
lastSequence uint32
lastTimestamp uint32
//lastPacket *rtp.Packet
lastTime time.Time
jitter float64
//sequenceCycle uint16
totalLost uint32
conn net.PacketConn // local conn endpoint
addr net.Addr // remote addr
}
func (s *Session) LastTime() time.Time {
return s.lastTime
type Endpoint struct {
Addr string
Port uint16
MasterKey []byte
MasterSalt []byte
SSRC uint32
srtp *srtp.Context
}
func (s *Session) SetKeys(localKey, localSalt, remoteKey, remoteSalt []byte) (err error) {
s.localCtx, err = srtp.CreateContext(localKey, localSalt, GuessProfile(localKey))
func (e *Endpoint) Init() error {
var profile srtp.ProtectionProfile
switch len(e.MasterKey) {
case 16:
profile = srtp.ProtectionProfileAes128CmHmacSha1_80
//case 32:
// return srtp.ProtectionProfileAes256CmHmacSha1_80
}
var err error
e.srtp, err = srtp.CreateContext(e.MasterKey, e.MasterSalt, profile)
return err
}
func (s *Session) WriteRTP(packet *rtp.Packet) (int, error) {
b, err := packet.Marshal()
if err != nil {
return 0, err
}
if b, err = s.Local.srtp.EncryptRTP(nil, b, nil); err != nil {
return 0, err
}
return s.conn.WriteTo(b, s.addr)
}
func (s *Session) ReadRTP(b []byte) {
packet := &rtp.Packet{}
b, err := s.Remote.srtp.DecryptRTP(nil, b, &packet.Header)
if err != nil {
return
}
s.remoteCtx, err = srtp.CreateContext(remoteKey, remoteSalt, GuessProfile(remoteKey))
return
if err = packet.Unmarshal(b); err != nil {
return
}
if s.OnReadRTP != nil {
s.OnReadRTP(packet)
}
}
func (s *Session) HandleRTP(data []byte) (err error) {
if data, err = s.remoteCtx.DecryptRTP(nil, data, nil); err != nil {
return
}
if s.Track == nil {
return
}
packet := &rtp.Packet{}
if err = packet.Unmarshal(data); err != nil {
return
}
if s.Deadline != nil {
s.Deadline.Reset(core.ConnDeadline)
}
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)
return
}
func (s *Session) HandleRTCP(data []byte) (err error) {
func (s *Session) ReadRTCP(b []byte) {
header := &rtcp.Header{}
if data, err = s.remoteCtx.DecryptRTCP(nil, data, header); err != nil {
b, err := s.Remote.srtp.DecryptRTCP(nil, b, header)
if err != nil {
return
}
if _, err = rtcp.Unmarshal(data); err != nil {
if _, err = rtcp.Unmarshal(b); err != nil {
return
}
if header.Type == rtcp.TypeSenderReport {
err = s.KeepAlive()
_ = s.KeepAlive()
}
return
}
func (s *Session) KeepAlive() (err error) {
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),
}}
func (s *Session) KeepAlive() error {
rep := rtcp.ReceiverReport{SSRC: s.Local.SSRC}
b, err := rep.Marshal()
if err != nil {
return err
}
// 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
if b, err = s.Local.srtp.EncryptRTCP(nil, b, nil); err != nil {
return err
}
if data, err = s.localCtx.EncryptRTCP(nil, data, nil); err != nil {
return
}
_, err = s.Write(data)
return
}
func GuessProfile(masterKey []byte) srtp.ProtectionProfile {
switch len(masterKey) {
case 16:
return srtp.ProtectionProfileAes128CmHmacSha1_80
//case 32:
// return srtp.ProtectionProfileAes256CmHmacSha1_80
}
return 0
_, err = s.conn.WriteTo(b, s.addr)
return err
}