From 514188201a4b4ab4c847d2c13efe6c1321d0a6b8 Mon Sep 17 00:00:00 2001 From: Alex X Date: Sun, 18 Jan 2026 08:38:38 +0300 Subject: [PATCH] Move tutk dtls to separate package #2011 --- README.md | 6 +++-- pkg/tutk/codec.go | 9 +++++++ pkg/tutk/{ => dtls}/auth.go | 2 +- pkg/tutk/{ => dtls}/cipher.go | 2 +- pkg/tutk/{ => dtls}/conn_dtls.go | 43 ++++++++++++++------------------ pkg/tutk/{ => dtls}/dtls.go | 2 +- pkg/wyze/client.go | 7 +++--- 7 files changed, 39 insertions(+), 32 deletions(-) rename pkg/tutk/{ => dtls}/auth.go (98%) rename pkg/tutk/{ => dtls}/cipher.go (99%) rename pkg/tutk/{ => dtls}/conn_dtls.go (96%) rename pkg/tutk/{ => dtls}/dtls.go (99%) diff --git a/README.md b/README.md index 5d484218..c70e65bd 100644 --- a/README.md +++ b/README.md @@ -637,11 +637,13 @@ Two-way audio support for Chinese version of [TP-Link cameras](https://www.tp-li This source allows you to view cameras from the [Xiaomi Mi Home](https://home.mi.com/) ecosystem. +*[read more](internal/xiaomi/README.md)* + ## Source: Wyze -This source allows you to stream from [Wyze](https://wyze.com/) cameras using native P2P protocol - no docker-wyze-bridge required. Supports H.264/H.265 video, AAC/G.711 audio, and two-way audio. [Read more](https://github.com/AlexxIT/go2rtc/blob/master/internal/wyze/README.md). +This source allows you to stream from [Wyze](https://wyze.com/) cameras using native P2P protocol - no `docker-wyze-bridge` required. Supports H.264/H.265 video, AAC/G.711 audio, and two-way audio. -*[read more](internal/xiaomi/README.md)* +*[read more](internal/wyze/README.md)* ## Source: GoPro diff --git a/pkg/tutk/codec.go b/pkg/tutk/codec.go index 68ca72ca..9ec7d8cb 100644 --- a/pkg/tutk/codec.go +++ b/pkg/tutk/codec.go @@ -26,6 +26,15 @@ const ( var sampleRates = [9]uint32{8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000} +func GetSampleRateIndex(sampleRate uint32) uint8 { + for i, rate := range sampleRates { + if rate == sampleRate { + return uint8(i) + } + } + return 3 // default 16kHz +} + func GetSamplesPerFrame(codecID byte) uint32 { switch codecID { case CodecAACRaw, CodecAACADTS, CodecAACLATM, CodecAACAlt: diff --git a/pkg/tutk/auth.go b/pkg/tutk/dtls/auth.go similarity index 98% rename from pkg/tutk/auth.go rename to pkg/tutk/dtls/auth.go index 8dca29aa..7354428d 100644 --- a/pkg/tutk/auth.go +++ b/pkg/tutk/dtls/auth.go @@ -1,4 +1,4 @@ -package tutk +package dtls import ( "crypto/sha256" diff --git a/pkg/tutk/cipher.go b/pkg/tutk/dtls/cipher.go similarity index 99% rename from pkg/tutk/cipher.go rename to pkg/tutk/dtls/cipher.go index 0a238fa3..e987ff8e 100644 --- a/pkg/tutk/cipher.go +++ b/pkg/tutk/dtls/cipher.go @@ -1,4 +1,4 @@ -package tutk +package dtls import ( "crypto/cipher" diff --git a/pkg/tutk/conn_dtls.go b/pkg/tutk/dtls/conn_dtls.go similarity index 96% rename from pkg/tutk/conn_dtls.go rename to pkg/tutk/dtls/conn_dtls.go index bdeb4dbd..c1d5f6ce 100644 --- a/pkg/tutk/conn_dtls.go +++ b/pkg/tutk/dtls/conn_dtls.go @@ -1,4 +1,4 @@ -package tutk +package dtls import ( "context" @@ -11,6 +11,7 @@ import ( "sync" "time" + "github.com/AlexxIT/go2rtc/pkg/tutk" "github.com/pion/dtls/v3" ) @@ -70,7 +71,7 @@ const ( type DTLSConn struct { conn *net.UDPConn addr *net.UDPAddr - frames *FrameHandler + frames *tutk.FrameHandler err error verbose bool ctx context.Context @@ -150,7 +151,7 @@ func DialDTLS(host string, port int, uid, authKey, enr string, verbose bool) (*D c.clientBuf = make(chan []byte, 64) c.serverBuf = make(chan []byte, 64) c.rawCmd = make(chan []byte, 16) - c.frames = NewFrameHandler(c.verbose) + c.frames = tutk.NewFrameHandler(c.verbose) c.wg.Add(1) go c.reader() @@ -167,7 +168,7 @@ func DialDTLS(host string, port int, uid, authKey, enr string, verbose bool) (*D } func (c *DTLSConn) AVClientStart(timeout time.Duration) error { - randomID := GenSessionID() + randomID := tutk.GenSessionID() pkt1 := c.msgAVLogin(magicAVLogin1, 570, 0x0001, randomID) pkt2 := c.msgAVLogin(magicAVLogin2, 572, 0x0000, randomID) pkt2[20]++ // pkt2 has randomID incremented by 1 @@ -311,7 +312,7 @@ func (c *DTLSConn) AVServStop() error { return nil } -func (c *DTLSConn) AVRecvFrameData() (*Packet, error) { +func (c *DTLSConn) AVRecvFrameData() (*tutk.Packet, error) { select { case pkt, ok := <-c.frames.Recv(): if !ok { @@ -351,7 +352,7 @@ func (c *DTLSConn) Write(data []byte) error { _, err := c.conn.WriteToUDP(data, c.addr) return err } - _, err := c.conn.WriteToUDP(TransCodeBlob(data), c.addr) + _, err := c.conn.WriteToUDP(tutk.TransCodeBlob(data), c.addr) return err } @@ -397,7 +398,7 @@ func (c *DTLSConn) WriteAndWait(req []byte, ok func(res []byte) bool) ([]byte, e if c.isCC51 { res = buf[:n] } else { - res = ReverseTransCodeBlob(buf[:n]) + res = tutk.ReverseTransCodeBlob(buf[:n]) } if ok(res) { @@ -496,9 +497,9 @@ func (c *DTLSConn) Error() error { } func (c *DTLSConn) discovery() error { - c.sid = GenSessionID() + c.sid = tutk.GenSessionID() - pktIOTC := TransCodeBlob(c.msgDisco(1)) + pktIOTC := tutk.TransCodeBlob(c.msgDisco(1)) pktCC51 := c.msgDiscoCC51(0, 0, false) buf := make([]byte, 2048) @@ -530,7 +531,7 @@ func (c *DTLSConn) discovery() error { } // IOTC Protocol (Basis) - data := ReverseTransCodeBlob(buf[:n]) + data := tutk.ReverseTransCodeBlob(buf[:n]) if len(data) >= 16 && binary.LittleEndian.Uint16(data[8:]) == cmdDiscoRes { c.addr, c.isCC51 = addr, false return c.discoDone() @@ -638,7 +639,7 @@ func (c *DTLSConn) worker() { default: channel := data[0] - if channel == ChannelAudio || channel == ChannelIVideo || channel == ChannelPVideo { + if channel == tutk.ChannelAudio || channel == tutk.ChannelIVideo || channel == tutk.ChannelPVideo { c.frames.Handle(data) } } @@ -700,7 +701,7 @@ func (c *DTLSConn) reader() { } // IOTC Protocol (Basis) - data := ReverseTransCodeBlob(buf[:n]) + data := tutk.ReverseTransCodeBlob(buf[:n]) if len(data) < 16 { continue } @@ -843,8 +844,8 @@ func (c *DTLSConn) msgAudioFrame(payload []byte, timestampUS uint32, codec byte, b := make([]byte, 36+totalPayload) // Outer header (36 bytes) - b[0] = ChannelAudio // 0x03 - b[1] = FrameTypeStartAlt // 0x09 + b[0] = tutk.ChannelAudio // 0x03 + b[1] = tutk.FrameTypeStartAlt // 0x09 binary.LittleEndian.PutUint16(b[2:], protoVersion) binary.LittleEndian.PutUint32(b[4:], c.audioSeq) binary.LittleEndian.PutUint32(b[8:], timestampUS) @@ -855,8 +856,8 @@ func (c *DTLSConn) msgAudioFrame(payload []byte, timestampUS uint32, codec byte, } // Inner header - b[16] = ChannelAudio - b[17] = FrameTypeEndSingle + b[16] = tutk.ChannelAudio + b[17] = tutk.FrameTypeEndSingle binary.LittleEndian.PutUint16(b[18:], uint16(prevFrame)) binary.LittleEndian.PutUint16(b[20:], 0x0001) // pkt_total binary.LittleEndian.PutUint16(b[22:], 0x0010) // flags @@ -868,19 +869,13 @@ func (c *DTLSConn) msgAudioFrame(payload []byte, timestampUS uint32, codec byte, fi[0] = codec // Codec ID (low byte) fi[1] = 0 // Codec ID (high byte, unused) // Audio flags: [3:2]=sampleRateIdx [1]=16bit [0]=stereo - var srIdx uint8 = 3 // default 16kHz - for i, rate := range sampleRates { - if rate == sampleRate { - srIdx = uint8(i) - break - } - } + srIdx := tutk.GetSampleRateIndex(sampleRate) fi[2] = (srIdx << 2) | 0x02 // 16-bit always set if channels == 2 { fi[2] |= 0x01 } fi[4] = 1 // online - binary.LittleEndian.PutUint32(fi[12:], (c.audioFrameNo-1)*GetSamplesPerFrame(codec)*1000/sampleRate) + binary.LittleEndian.PutUint32(fi[12:], (c.audioFrameNo-1)*tutk.GetSamplesPerFrame(codec)*1000/sampleRate) return b } diff --git a/pkg/tutk/dtls.go b/pkg/tutk/dtls/dtls.go similarity index 99% rename from pkg/tutk/dtls.go rename to pkg/tutk/dtls/dtls.go index 9088a664..3b0573ae 100644 --- a/pkg/tutk/dtls.go +++ b/pkg/tutk/dtls/dtls.go @@ -1,4 +1,4 @@ -package tutk +package dtls import ( "context" diff --git a/pkg/wyze/client.go b/pkg/wyze/client.go index 46c996e0..0fe878ee 100644 --- a/pkg/wyze/client.go +++ b/pkg/wyze/client.go @@ -13,6 +13,7 @@ import ( "time" "github.com/AlexxIT/go2rtc/pkg/tutk" + "github.com/AlexxIT/go2rtc/pkg/tutk/dtls" ) const ( @@ -49,7 +50,7 @@ const ( ) type Client struct { - conn *tutk.DTLSConn + conn *dtls.DTLSConn host string uid string @@ -97,7 +98,7 @@ func Dial(rawURL string) (*Client, error) { verbose: query.Get("verbose") == "true", } - c.authKey = string(tutk.CalculateAuthKey(c.enr, c.mac)) + c.authKey = string(dtls.CalculateAuthKey(c.enr, c.mac)) if c.verbose { fmt.Printf("[Wyze] Connecting to %s (UID: %s)\n", c.host, c.uid) @@ -303,7 +304,7 @@ func (c *Client) connect() error { host = host[:idx] } - conn, err := tutk.DialDTLS(host, port, c.uid, c.authKey, c.enr, c.verbose) + conn, err := dtls.DialDTLS(host, port, c.uid, c.authKey, c.enr, c.verbose) if err != nil { return fmt.Errorf("wyze: connect failed: %w", err) }