owpengram-server/internal/sfu/demux.go

108 lines
3 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package sfu
import (
"errors"
"io"
"net"
"time"
"github.com/pion/transport/v4/packetio"
)
// demuxer 把 ICE conn 上的混合流量按 RFC 7983 首字节分发:
// - [20,63] → DTLS握手与应用数据
// - [128,191] → RTP/RTCP再按 RTCP PT 200..207 细分)
//
// 写方向全部直写底层 ICE conn同一 5 元组RTCP-mux
type demuxer struct {
base net.Conn
dtls *packetio.Buffer
srtp *packetio.Buffer
srtcp *packetio.Buffer
done chan struct{}
}
func newDemuxer(base net.Conn) *demuxer {
d := &demuxer{
base: base,
dtls: packetio.NewBuffer(),
srtp: packetio.NewBuffer(),
srtcp: packetio.NewBuffer(),
done: make(chan struct{}),
}
go d.readLoop()
return d
}
func (d *demuxer) readLoop() {
defer close(d.done)
buf := make([]byte, 1500)
for {
n, err := d.base.Read(buf)
if err != nil {
_ = d.dtls.Close()
_ = d.srtp.Close()
_ = d.srtcp.Close()
return
}
if n == 0 {
continue
}
first := buf[0]
switch {
case first >= 20 && first <= 63:
_, _ = d.dtls.Write(buf[:n])
case first >= 128 && first <= 191:
if n >= 2 && isRTCPPayloadType(buf[1]) {
_, _ = d.srtcp.Write(buf[:n])
} else {
_, _ = d.srtp.Write(buf[:n])
}
default:
// STUN 已被 ICE 层消费;其余丢弃。
}
}
}
func isRTCPPayloadType(pt byte) bool {
// RTCP packet type 范围SR/RR/SDES/BYE/APP/RTPFB/PSFB...)。
return pt >= 192 && pt <= 223
}
func (d *demuxer) Close() {
_ = d.dtls.Close()
_ = d.srtp.Close()
_ = d.srtcp.Close()
}
// demuxConn 把单一 buffer 包成 net.Conn读取自 buffer写直达底层。
type demuxConn struct {
buf *packetio.Buffer
base net.Conn
}
func (c *demuxConn) Read(b []byte) (int, error) {
n, err := c.buf.Read(b)
if errors.Is(err, io.EOF) || errors.Is(err, packetio.ErrFull) {
return n, err
}
return n, err
}
func (c *demuxConn) Write(b []byte) (int, error) { return c.base.Write(b) }
func (c *demuxConn) Close() error { return c.buf.Close() }
func (c *demuxConn) LocalAddr() net.Addr { return c.base.LocalAddr() }
func (c *demuxConn) RemoteAddr() net.Addr { return c.base.RemoteAddr() }
// SetDeadline/SetReadDeadline 透传给 packetio.BufferDTLS 握手依赖读超时
// 推进重传与失败退出pion/dtls v3 默认 Handshake 无限期阻塞,调用方必须
// 在握手期间设硬上限,否则停滞的握手会把 goroutine 挂死)。
func (c *demuxConn) SetDeadline(t time.Time) error { return c.buf.SetReadDeadline(t) }
func (c *demuxConn) SetReadDeadline(t time.Time) error { return c.buf.SetReadDeadline(t) }
// 写方向直达底层 ICE conn无队列可超时。
func (c *demuxConn) SetWriteDeadline(t time.Time) error { return nil }
func (d *demuxer) dtlsConn() net.Conn { return &demuxConn{buf: d.dtls, base: d.base} }
func (d *demuxer) srtpConn() net.Conn { return &demuxConn{buf: d.srtp, base: d.base} }
func (d *demuxer) srtcpConn() net.Conn { return &demuxConn{buf: d.srtcp, base: d.base} }