Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support SRTP #232

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ require (
github.com/jfreymuth/oggvorbis v1.0.5
github.com/livekit/mageutil v0.0.0-20230125210925-54e8a70427c1
github.com/livekit/mediatransportutil v0.0.0-20241128072814-c363618d4c98
github.com/livekit/protocol v1.28.2-0.20241128072830-b738aedbd841
github.com/livekit/protocol v1.29.5-0.20241212113100-b656ab075ab2 // FIXME: update when PR is merged
github.com/livekit/psrpc v0.6.1-0.20241018124827-1efff3d113a8
github.com/livekit/server-sdk-go/v2 v2.4.0
github.com/livekit/sipgo v0.13.2-0.20241209123643-27500ef99c39
Expand All @@ -21,7 +21,8 @@ require (
github.com/pion/interceptor v0.1.37
github.com/pion/rtp v1.8.9
github.com/pion/sdp/v3 v3.0.9
github.com/pion/webrtc/v4 v4.0.4
github.com/pion/srtp/v3 v3.0.4
github.com/pion/webrtc/v4 v4.0.5
github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.20.5
github.com/sirupsen/logrus v1.9.3
Expand Down Expand Up @@ -96,7 +97,6 @@ require (
github.com/pion/randutil v0.1.0 // indirect
github.com/pion/rtcp v1.2.14 // indirect
github.com/pion/sctp v1.8.34 // indirect
github.com/pion/srtp/v3 v3.0.4 // indirect
github.com/pion/stun/v3 v3.0.0 // indirect
github.com/pion/transport/v3 v3.0.7 // indirect
github.com/pion/turn/v4 v4.0.0 // indirect
Expand Down
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,8 @@ github.com/livekit/mageutil v0.0.0-20230125210925-54e8a70427c1 h1:jm09419p0lqTkD
github.com/livekit/mageutil v0.0.0-20230125210925-54e8a70427c1/go.mod h1:Rs3MhFwutWhGwmY1VQsygw28z5bWcnEYmS1OG9OxjOQ=
github.com/livekit/mediatransportutil v0.0.0-20241128072814-c363618d4c98 h1:QA7DqIC/ZSsMj8HC0+zNfMMwssHbA0alZALK68r30LQ=
github.com/livekit/mediatransportutil v0.0.0-20241128072814-c363618d4c98/go.mod h1:WIVFAGzVZ7VMjPC5+nbSfwdFjWcbuLgx97KeNSUDTEo=
github.com/livekit/protocol v1.28.2-0.20241128072830-b738aedbd841 h1:69dSvfL6H6odFhL9q4s+RjDRDdfLY+WUUQ/Lz0av2Bs=
github.com/livekit/protocol v1.28.2-0.20241128072830-b738aedbd841/go.mod h1:mqXSWNHbENjxM0/HG25wZ7wgja/K9fA0PeQxi+MPmWw=
github.com/livekit/protocol v1.29.5-0.20241212113100-b656ab075ab2 h1:+KYhwtahEf3RyfZzk2RozmFwWThSuM64gDfzonJ7XXA=
github.com/livekit/protocol v1.29.5-0.20241212113100-b656ab075ab2/go.mod h1:NDg1btMpKCzr/w6QR5kDuXw/e4Y7yOBE+RUAHsc+Y/M=
github.com/livekit/psrpc v0.6.1-0.20241018124827-1efff3d113a8 h1:Ibh0LoFl5NW5a1KFJEE0eLxxz7dqqKmYTj/BfCb0PbY=
github.com/livekit/psrpc v0.6.1-0.20241018124827-1efff3d113a8/go.mod h1:CQUBSPfYYAaevg1TNCc6/aYsa8DJH4jSRFdCeSZk5u0=
github.com/livekit/server-sdk-go/v2 v2.4.0 h1:ide41hppBf7btHLz/nj6rLIQSkaIOxP5tVSki74ZDhg=
Expand Down Expand Up @@ -192,8 +192,8 @@ github.com/pion/transport/v3 v3.0.7 h1:iRbMH05BzSNwhILHoBoAPxoB9xQgOaJk+591KC9P1
github.com/pion/transport/v3 v3.0.7/go.mod h1:YleKiTZ4vqNxVwh77Z0zytYi7rXHl7j6uPLGhhz9rwo=
github.com/pion/turn/v4 v4.0.0 h1:qxplo3Rxa9Yg1xXDxxH8xaqcyGUtbHYw4QSCvmFWvhM=
github.com/pion/turn/v4 v4.0.0/go.mod h1:MuPDkm15nYSklKpN8vWJ9W2M0PlyQZqYt1McGuxG7mA=
github.com/pion/webrtc/v4 v4.0.4 h1:X+gkoBLKDsR6FliKKQ/VXGBjnMR3yOPcyXEPt3z7Ep0=
github.com/pion/webrtc/v4 v4.0.4/go.mod h1:LvP8Np5b/sM0uyJIcUPvJcCvhtjHxJwzh2H2PYzE6cQ=
github.com/pion/webrtc/v4 v4.0.5 h1:8cVPojcv3cQTwVga2vF1rzCNvkiEimnYdCCG7yF317I=
github.com/pion/webrtc/v4 v4.0.5/go.mod h1:LvP8Np5b/sM0uyJIcUPvJcCvhtjHxJwzh2H2PYzE6cQ=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
Expand Down
6 changes: 3 additions & 3 deletions pkg/media/dtmf/dtmf.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,11 +161,11 @@ func Decode(data []byte) (Event, error) {
}, nil
}

func DecodeRTP(p *rtp.Packet) (Event, bool) {
if !p.Marker {
func DecodeRTP(h *rtp.Header, payload []byte) (Event, bool) {
if !h.Marker {
return Event{}, false
}
ev, err := Decode(p.Payload)
ev, err := Decode(payload)
if err != nil {
return Event{}, false
}
Expand Down
41 changes: 30 additions & 11 deletions pkg/media/rtp/conn.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,21 @@ package rtp

import (
"net"
"net/netip"
"sync"
"sync/atomic"
"time"

"github.com/frostbyte73/core"
"github.com/pion/rtp"

"github.com/livekit/protocol/logger"
)

var _ Writer = (*Conn)(nil)

type ConnConfig struct {
Log logger.Logger
MediaTimeoutInitial time.Duration
MediaTimeout time.Duration
TimeoutCallback func()
Expand All @@ -40,14 +44,18 @@ func NewConnWith(conn UDPConn, conf *ConnConfig) *Conn {
if conf == nil {
conf = &ConnConfig{}
}
if conf.Log == nil {
conf.Log = logger.GetLogger()
}
if conf.MediaTimeoutInitial <= 0 {
conf.MediaTimeoutInitial = 30 * time.Second
}
if conf.MediaTimeout <= 0 {
conf.MediaTimeout = 15 * time.Second
}
c := &Conn{
readBuf: make([]byte, 1500), // MTU
log: conf.Log,
readBuf: make([]byte, MTUSize+1), // larger buffer to detect overflow
received: make(chan struct{}),
conn: conn,
timeout: conf.MediaTimeout,
Expand All @@ -67,7 +75,9 @@ type UDPConn interface {
Close() error
}

// Deprecated: use MediaPort instead
type Conn struct {
log logger.Logger
wmu sync.Mutex
conn UDPConn
closed core.Fuse
Expand Down Expand Up @@ -131,9 +141,11 @@ func (c *Conn) Listen(portMin, portMax int, listenAddr string) error {
if listenAddr == "" {
listenAddr = "0.0.0.0"
}

var err error
c.conn, err = ListenUDPPortRange(portMin, portMax, net.ParseIP(listenAddr))
ip, err := netip.ParseAddr(listenAddr)
if err != nil {
return err
}
c.conn, err = ListenUDPPortRange(portMin, portMax, ip)
if err != nil {
return err
}
Expand All @@ -150,13 +162,21 @@ func (c *Conn) ListenAndServe(portMin, portMax int, listenAddr string) error {

func (c *Conn) readLoop() {
conn, buf := c.conn, c.readBuf
overflow := false
var p rtp.Packet
for {
n, srcAddr, err := conn.ReadFromUDP(buf)
if err != nil {
return
}
c.dest.Store(srcAddr)
if n > MTUSize {
if !overflow {
overflow = true
c.log.Errorw("RTP packet is larger than MTU limit", nil)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to alert on this? (sure sending invalid packet, potentially as an attempt to break our system)? If not, should this be a Warn or Info?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer to not pass broken packet. Go crashes are fine and easy to recover from/fix, but crashes from C code are not. We could specifically fuzz the system to (hopefully) detect those.

As for the error/warn, even though this case won't break the system, it will still cause audio glitches in a specific call. I'd like to know when it happens, especially when a fix is as easy as increasing the buffer size. So I'd like to keep it as an error here.

}
continue // ignore partial messages
}

p = rtp.Packet{}
if err := p.Unmarshal(buf[:n]); err != nil {
Expand All @@ -167,24 +187,23 @@ func (c *Conn) readLoop() {
close(c.received)
}
if h := c.onRTP.Load(); h != nil {
_ = (*h).HandleRTP(&p)
_ = (*h).HandleRTP(&p.Header, p.Payload)
}
}
}

func (c *Conn) WriteRTP(p *rtp.Packet) error {
func (c *Conn) WriteRTP(h *rtp.Header, payload []byte) (int, error) {
addr := c.dest.Load()
if addr == nil {
return nil
return 0, nil
}
data, err := p.Marshal()
data, err := (&rtp.Packet{Header: *h, Payload: payload}).Marshal()
if err != nil {
return err
return 0, err
}
c.wmu.Lock()
defer c.wmu.Unlock()
_, err = c.conn.WriteToUDP(data, addr)
return err
return c.conn.WriteToUDP(data, addr)
}

func (c *Conn) ReadRTP() (*rtp.Packet, *net.UDPAddr, error) {
Expand Down
11 changes: 6 additions & 5 deletions pkg/media/rtp/jitter.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@ package rtp
import (
"time"

"github.com/livekit/server-sdk-go/v2/pkg/jitter"
"github.com/pion/rtp"

"github.com/livekit/server-sdk-go/v2/pkg/jitter"
)

const (
Expand All @@ -41,11 +42,11 @@ type jitterHandler struct {
buf *jitter.Buffer
}

func (h *jitterHandler) HandleRTP(p *rtp.Packet) error {
h.buf.Push(p)
func (r *jitterHandler) HandleRTP(h *rtp.Header, payload []byte) error {
r.buf.Push(&rtp.Packet{Header: *h, Payload: payload})
var last error
for _, p := range h.buf.Pop(false) {
if err := h.h.HandleRTP(p); err != nil {
for _, p := range r.buf.Pop(false) {
if err := r.h.HandleRTP(&p.Header, p.Payload); err != nil {
last = err
}
}
Expand Down
7 changes: 4 additions & 3 deletions pkg/media/rtp/listen.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,15 @@ import (
"errors"
"math/rand"
"net"
"net/netip"
)

var ListenErr = errors.New("failed to listen on udp port")

func ListenUDPPortRange(portMin, portMax int, IP net.IP) (*net.UDPConn, error) {
func ListenUDPPortRange(portMin, portMax int, ip netip.Addr) (*net.UDPConn, error) {
if portMin == 0 && portMax == 0 {
return net.ListenUDP("udp", &net.UDPAddr{
IP: IP,
IP: ip.AsSlice(),
Port: 0,
})
}
Expand All @@ -48,7 +49,7 @@ func ListenUDPPortRange(portMin, portMax int, IP net.IP) (*net.UDPConn, error) {
portCurrent := portStart

for {
c, e := net.ListenUDP("udp", &net.UDPAddr{IP: IP, Port: portCurrent})
c, e := net.ListenUDP("udp", &net.UDPAddr{IP: ip.AsSlice(), Port: portCurrent})
if e == nil {
return c, nil
}
Expand Down
18 changes: 9 additions & 9 deletions pkg/media/rtp/mux.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,25 +35,25 @@ type Mux struct {

// HandleRTP selects a Handler based on payload type.
// Types can be registered with Register. If no handler is set, a default one will be used.
func (m *Mux) HandleRTP(p *rtp.Packet) error {
func (m *Mux) HandleRTP(h *rtp.Header, payload []byte) error {
if m == nil {
return nil
}
var h Handler
var r Handler
m.mu.RLock()
if p.PayloadType < byte(len(m.static)) {
h = m.static[p.PayloadType]
if h.PayloadType < byte(len(m.static)) {
r = m.static[h.PayloadType]
} else {
h = m.dynamic[p.PayloadType]
r = m.dynamic[h.PayloadType]
}
if h == nil {
h = m.def
if r == nil {
r = m.def
}
m.mu.RUnlock()
if h == nil {
if r == nil {
return nil
}
return h.HandleRTP(p)
return r.HandleRTP(h, payload)
}

// SetDefault sets a default RTP handler.
Expand Down
51 changes: 26 additions & 25 deletions pkg/media/rtp/rtp.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package rtp
import (
"fmt"
"math/rand/v2"
"slices"
"sync"

"github.com/pion/interceptor"
Expand All @@ -31,21 +32,21 @@ type BytesFrame interface {
}

type Writer interface {
WriteRTP(p *rtp.Packet) error
WriteRTP(h *rtp.Header, payload []byte) (int, error)
}

type Reader interface {
ReadRTP() (*rtp.Packet, interceptor.Attributes, error)
}

type Handler interface {
HandleRTP(p *rtp.Packet) error
HandleRTP(h *rtp.Header, payload []byte) error
}

type HandlerFunc func(p *rtp.Packet) error
type HandlerFunc func(h *rtp.Header, payload []byte) error

func (fnc HandlerFunc) HandleRTP(p *rtp.Packet) error {
return fnc(p)
func (fnc HandlerFunc) HandleRTP(h *rtp.Header, payload []byte) error {
return fnc(h, payload)
}

func HandleLoop(r Reader, h Handler) error {
Expand All @@ -54,7 +55,7 @@ func HandleLoop(r Reader, h Handler) error {
if err != nil {
return err
}
err = h.HandleRTP(p)
err = h.HandleRTP(&p.Header, p.Payload)
if err != nil {
return err
}
Expand All @@ -64,26 +65,27 @@ func HandleLoop(r Reader, h Handler) error {
// Buffer is a Writer that clones and appends RTP packets into a slice.
type Buffer []*Packet

func (b *Buffer) WriteRTP(p *Packet) error {
p2 := p.Clone()
*b = append(*b, p2)
return nil
func (b *Buffer) WriteRTP(h *rtp.Header, payload []byte) (int, error) {
*b = append(*b, &rtp.Packet{
Header: *h,
Payload: slices.Clone(payload),
})
return len(payload), nil
}

// NewSeqWriter creates an RTP writer that automatically increments the sequence number.
func NewSeqWriter(w Writer) *SeqWriter {
s := &SeqWriter{w: w}
s.p = rtp.Packet{
Header: rtp.Header{
Version: 2,
SSRC: rand.Uint32(),
SequenceNumber: 0,
},
s.h = rtp.Header{
Version: 2,
SSRC: rand.Uint32(),
SequenceNumber: 0,
}
return s
}

type Packet = rtp.Packet
type Header = rtp.Header

type Event struct {
Type byte
Expand All @@ -95,20 +97,19 @@ type Event struct {
type SeqWriter struct {
mu sync.Mutex
w Writer
p Packet
h Header
}

func (s *SeqWriter) WriteEvent(ev *Event) error {
s.mu.Lock()
defer s.mu.Unlock()
s.p.PayloadType = ev.Type
s.p.Payload = ev.Payload
s.p.Marker = ev.Marker
s.p.Timestamp = ev.Timestamp
if err := s.w.WriteRTP(&s.p); err != nil {
s.h.PayloadType = ev.Type
s.h.Marker = ev.Marker
s.h.Timestamp = ev.Timestamp
if _, err := s.w.WriteRTP(&s.h, ev.Payload); err != nil {
return err
}
s.p.Header.SequenceNumber++
s.h.SequenceNumber++
return nil
}

Expand Down Expand Up @@ -211,6 +212,6 @@ func (s *MediaStreamIn[T]) String() string {
return fmt.Sprintf("RTP(%d) -> %s", s.Writer.SampleRate(), s.Writer)
}

func (s *MediaStreamIn[T]) HandleRTP(p *rtp.Packet) error {
return s.Writer.WriteSample(T(p.Payload))
func (s *MediaStreamIn[T]) HandleRTP(_ *rtp.Header, payload []byte) error {
return s.Writer.WriteSample(T(payload))
}
Loading
Loading