Adds support HomeKit cameras!
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
package srtp
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"net"
|
||||
)
|
||||
|
||||
// Server using same UDP port for SRTP and for SRTCP as the iPhone does
|
||||
// this is not really necessary but anyway
|
||||
type Server struct {
|
||||
sessions map[uint32]*Session
|
||||
}
|
||||
|
||||
func (s *Server) AddSession(session *Session) {
|
||||
if s.sessions == nil {
|
||||
s.sessions = map[uint32]*Session{}
|
||||
}
|
||||
s.sessions[session.RemoteSSRC] = session
|
||||
}
|
||||
|
||||
func (s *Server) RemoveSession(session *Session) {
|
||||
delete(s.sessions, session.RemoteSSRC)
|
||||
}
|
||||
|
||||
func (s *Server) Serve(conn net.PacketConn) error {
|
||||
buf := make([]byte, 2048)
|
||||
for {
|
||||
n, addr, err := conn.ReadFrom(buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Multiplexing RTP Data and Control Packets on a Single Port
|
||||
// https://datatracker.ietf.org/doc/html/rfc5761
|
||||
|
||||
// this is default position for SSRC in RTP packet
|
||||
ssrc := binary.BigEndian.Uint32(buf[8:])
|
||||
session, ok := s.sessions[ssrc]
|
||||
if ok {
|
||||
if session.Write == nil {
|
||||
session.Write = func(b []byte) (int, error) {
|
||||
return conn.WriteTo(b, addr)
|
||||
}
|
||||
}
|
||||
|
||||
if err = session.HandleRTP(buf[:n]); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
// this is default position for SSRC in RTCP packet
|
||||
ssrc = binary.BigEndian.Uint32(buf[4:])
|
||||
if session, ok = s.sessions[ssrc]; !ok {
|
||||
continue // skip unknown ssrc
|
||||
}
|
||||
|
||||
if err = session.HandleRTCP(buf[:n]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package srtp
|
||||
|
||||
import (
|
||||
"github.com/AlexxIT/go2rtc/pkg/streamer"
|
||||
"github.com/pion/rtcp"
|
||||
"github.com/pion/rtp"
|
||||
"github.com/pion/srtp/v2"
|
||||
)
|
||||
|
||||
type Session struct {
|
||||
LocalSSRC uint32 // outgoing SSRC
|
||||
RemoteSSRC uint32 // incoming SSRC
|
||||
|
||||
localCtx *srtp.Context // write context
|
||||
remoteCtx *srtp.Context // read context
|
||||
|
||||
Write func(b []byte) (int, error)
|
||||
Track *streamer.Track
|
||||
}
|
||||
|
||||
func (s *Session) SetKeys(
|
||||
localKey, localSalt, remoteKey, remoteSalt []byte,
|
||||
) (err error) {
|
||||
if s.localCtx, err = srtp.CreateContext(
|
||||
localKey, localSalt, GuessProfile(localKey),
|
||||
); err != nil {
|
||||
return
|
||||
}
|
||||
s.remoteCtx, err = srtp.CreateContext(
|
||||
remoteKey, remoteSalt, GuessProfile(remoteKey),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
func (s *Session) HandleRTP(data []byte) (err error) {
|
||||
if data, err = s.remoteCtx.DecryptRTP(nil, data, nil); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
packet := &rtp.Packet{}
|
||||
if err = packet.Unmarshal(data); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
_ = s.Track.WriteRTP(packet)
|
||||
//s.Output(core.RTP{Channel: s.Channel, Packet: packet})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (s *Session) HandleRTCP(data []byte) (err error) {
|
||||
header := &rtcp.Header{}
|
||||
if data, err = s.remoteCtx.DecryptRTCP(nil, data, header); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var packets []rtcp.Packet
|
||||
if packets, err = rtcp.Unmarshal(data); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
_ = packets
|
||||
//s.Output(core.RTCP{Channel: s.Channel + 1, Header: header, Packets: packets})
|
||||
|
||||
if header.Type == rtcp.TypeSenderReport {
|
||||
err = s.KeepAlive()
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
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 data, err = rep.Marshal(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user