diff --git a/pkg/wyze/client.go b/pkg/wyze/client.go index fb312a1f..80151a6b 100644 --- a/pkg/wyze/client.go +++ b/pkg/wyze/client.go @@ -409,7 +409,7 @@ func (c *Client) buildK10000() []byte { buf[0] = 'H' buf[1] = 'L' buf[2] = 5 - binary.LittleEndian.PutUint16(buf[4:6], tutk.KCmdAuth) + binary.LittleEndian.PutUint16(buf[4:], tutk.KCmdAuth) return buf } @@ -420,15 +420,15 @@ func (c *Client) buildK10002(challenge []byte, status byte) []byte { buf[0] = 'H' buf[1] = 'L' buf[2] = 5 - binary.LittleEndian.PutUint16(buf[4:6], tutk.KCmdChallengeResp) + binary.LittleEndian.PutUint16(buf[4:], tutk.KCmdChallengeResp) buf[6] = 22 // Payload length if len(response) >= 16 { - copy(buf[16:32], response[:16]) + copy(buf[16:], response[:16]) } if len(c.uid) >= 4 { - copy(buf[32:36], c.uid[:4]) + copy(buf[32:], c.uid[:4]) } buf[36] = 1 // Video flag (0 = disabled, 1 = enabled > will start video stream immediately) @@ -444,10 +444,10 @@ func (c *Client) buildK10010(mediaType byte, enabled bool) []byte { buf := make([]byte, 18) buf[0] = 'H' buf[1] = 'L' - buf[2] = 5 // Version - binary.LittleEndian.PutUint16(buf[4:6], tutk.KCmdControlChannel) // 0x271a = 10010 - binary.LittleEndian.PutUint16(buf[6:8], 2) // Payload length = 2 - buf[16] = mediaType // 1=Video, 2=Audio, 3=ReturnAudio + buf[2] = 5 // Version + binary.LittleEndian.PutUint16(buf[4:], tutk.KCmdControlChannel) // 0x271a = 10010 + binary.LittleEndian.PutUint16(buf[6:], 2) // Payload length = 2 + buf[16] = mediaType // 1=Video, 2=Audio, 3=ReturnAudio if enabled { buf[17] = 1 } else { @@ -463,11 +463,11 @@ func (c *Client) buildK10056(frameSize uint8, bitrate uint16) []byte { buf := make([]byte, 21) buf[0] = 'H' buf[1] = 'L' - buf[2] = 5 // Version - binary.LittleEndian.PutUint16(buf[4:6], tutk.KCmdSetResolution) // 0x2748 = 10056 - binary.LittleEndian.PutUint16(buf[6:8], 5) // Payload length = 5 - buf[16] = frameSize + 1 // 4 = HD - binary.LittleEndian.PutUint16(buf[17:19], bitrate) // 0x00f0 = 240 + buf[2] = 5 // Version + binary.LittleEndian.PutUint16(buf[4:], tutk.KCmdSetResolution) // 0x2748 = 10056 + binary.LittleEndian.PutUint16(buf[6:], 5) // Payload length = 5 + buf[16] = frameSize + 1 // 4 = HD + binary.LittleEndian.PutUint16(buf[17:], bitrate) // 0x00f0 = 240 // buf[19], buf[20] = FPS (0 = auto) return buf } @@ -485,7 +485,7 @@ func (c *Client) parseK10001(data []byte) (challenge []byte, status byte, err er return nil, 0, fmt.Errorf("invalid HL magic: %x %x", data[0], data[1]) } - cmdID := binary.LittleEndian.Uint16(data[4:6]) + cmdID := binary.LittleEndian.Uint16(data[4:]) if cmdID != tutk.KCmdChallenge { return nil, 0, fmt.Errorf("expected cmdID 10001, got %d", cmdID) } @@ -510,8 +510,8 @@ func (c *Client) parseK10003(data []byte) (*tutk.AuthResponse, error) { return &tutk.AuthResponse{}, nil } - cmdID := binary.LittleEndian.Uint16(data[4:6]) - textLen := binary.LittleEndian.Uint16(data[6:8]) + cmdID := binary.LittleEndian.Uint16(data[4:]) + textLen := binary.LittleEndian.Uint16(data[6:]) if cmdID != tutk.KCmdAuthResult { return &tutk.AuthResponse{}, nil diff --git a/pkg/wyze/tutk/avframe.go b/pkg/wyze/tutk/avframe.go index 3c125bf7..e6c72313 100644 --- a/pkg/wyze/tutk/avframe.go +++ b/pkg/wyze/tutk/avframe.go @@ -93,17 +93,17 @@ func ParseFrameInfo(data []byte) *FrameInfo { fi := data[offset:] return &FrameInfo{ - CodecID: binary.LittleEndian.Uint16(fi[0:2]), + CodecID: binary.LittleEndian.Uint16(fi), Flags: fi[2], CamIndex: fi[3], OnlineNum: fi[4], Framerate: fi[5], FrameSize: fi[6], Bitrate: fi[7], - TimestampUS: binary.LittleEndian.Uint32(fi[8:12]), - Timestamp: binary.LittleEndian.Uint32(fi[12:16]), - PayloadSize: binary.LittleEndian.Uint32(fi[16:20]), - FrameNo: binary.LittleEndian.Uint32(fi[20:24]), + TimestampUS: binary.LittleEndian.Uint32(fi[8:]), + Timestamp: binary.LittleEndian.Uint32(fi[12:]), + PayloadSize: binary.LittleEndian.Uint32(fi[16:]), + FrameNo: binary.LittleEndian.Uint32(fi[20:]), } } diff --git a/pkg/wyze/tutk/conn.go b/pkg/wyze/tutk/conn.go index fa19a55f..e5c383fe 100644 --- a/pkg/wyze/tutk/conn.go +++ b/pkg/wyze/tutk/conn.go @@ -168,9 +168,9 @@ func (c *Conn) AVClientStart(timeout time.Duration) error { if !ok { return io.EOF } - if len(data) >= 32 && binary.LittleEndian.Uint16(data[0:2]) == MagicAVLoginResp { + if len(data) >= 32 && binary.LittleEndian.Uint16(data) == MagicAVLoginResp { c.avLoginResp = &AVLoginResponse{ - ServerType: binary.LittleEndian.Uint32(data[4:8]), + ServerType: binary.LittleEndian.Uint32(data[4:]), Resend: int32(data[29]), TwoWayStreaming: int32(data[31]), } @@ -309,7 +309,7 @@ func (c *Conn) RecvIOCtrl(timeout time.Duration) (cmdID uint16, data []byte, err } // Parse cmdID from HL header at offset 4-5 if len(data) >= 6 { - cmdID = binary.LittleEndian.Uint16(data[4:6]) + cmdID = binary.LittleEndian.Uint16(data[4:]) } // Send ACK after receiving _ = c.sendACK() @@ -428,7 +428,7 @@ func (c *Conn) discoStage1() error { continue } - cmd := binary.LittleEndian.Uint16(data[8:10]) + cmd := binary.LittleEndian.Uint16(data[8:]) if c.verbose { fmt.Printf("[IOTC] Disco Stage 1: received cmd=0x%04x from %s\n", cmd, addr) } @@ -479,7 +479,7 @@ func (c *Conn) sessionSetup() error { continue } - cmd := binary.LittleEndian.Uint16(data[8:10]) + cmd := binary.LittleEndian.Uint16(data[8:]) if c.verbose { fmt.Printf("[IOTC] Session setup: received cmd=0x%04x from %s\n", cmd, addr) } @@ -555,7 +555,7 @@ func (c *Conn) iotcReader() { continue } - cmd := binary.LittleEndian.Uint16(data[8:10]) + cmd := binary.LittleEndian.Uint16(data[8:]) if cmd == CmdKeepaliveRes && len(data) > 16 { payload := data[16:] @@ -680,7 +680,7 @@ func (c *Conn) route(data []byte) { } // Check for control frame magic values first (uint16 LE) - magic := binary.LittleEndian.Uint16(data[0:2]) + magic := binary.LittleEndian.Uint16(data) switch magic { case MagicAVLoginResp: @@ -756,7 +756,7 @@ func (c *Conn) handleSpeakerAVLogin() error { } // Extract checksum from incoming request (bytes 20-23) - checksum := binary.LittleEndian.Uint32(buf[20:24]) + checksum := binary.LittleEndian.Uint32(buf[20:]) // Build AV Login response (60 bytes like SDK) resp := c.buildAVLoginResponse(checksum) @@ -852,7 +852,7 @@ func (c *Conn) extractPayload(data []byte, channel byte) ([]byte, *FrameInfo) { // Has FrameInfo only if pkt_total == 1 (single-packet frame) headerSize = 36 if len(data) >= 22 { - pktTotal := uint16(data[20]) | uint16(data[21])<<8 + pktTotal := binary.LittleEndian.Uint16(data[20:]) if pktTotal == 1 { frameInfoSize = FrameInfoSize } @@ -1148,31 +1148,31 @@ func (c *Conn) buildAudioFrame(payload []byte, timestampUS uint32, codec uint16, } // Type 0x09 "Single" - 36-byte header with full timestamp - frame[0] = ChannelAudio // 0x03 - frame[1] = FrameTypeStartAlt // 0x09 - binary.LittleEndian.PutUint16(frame[2:4], ProtocolVersion) // 0x000c + frame[0] = ChannelAudio // 0x03 + frame[1] = FrameTypeStartAlt // 0x09 + binary.LittleEndian.PutUint16(frame[2:], ProtocolVersion) // 0x000c - binary.LittleEndian.PutUint32(frame[4:8], c.audioTxSeq) - binary.LittleEndian.PutUint32(frame[8:12], timestampUS) // Timestamp in header + binary.LittleEndian.PutUint32(frame[4:], c.audioTxSeq) + binary.LittleEndian.PutUint32(frame[8:], timestampUS) // Timestamp in header // Flags at [12-15]: first frame uses 0x00000001, subsequent use 0x00100001 if c.audioTxFrameNo == 1 { - binary.LittleEndian.PutUint32(frame[12:16], 0x00000001) + binary.LittleEndian.PutUint32(frame[12:], 0x00000001) } else { - binary.LittleEndian.PutUint32(frame[12:16], 0x00100001) + binary.LittleEndian.PutUint32(frame[12:], 0x00100001) } // Inner header - frame[16] = ChannelAudio // 0x03 - frame[17] = FrameTypeEndSingle // 0x01 - binary.LittleEndian.PutUint16(frame[18:20], uint16(prevFrameNo)) // prev_frame_no (16-bit) + frame[16] = ChannelAudio // 0x03 + frame[17] = FrameTypeEndSingle // 0x01 + binary.LittleEndian.PutUint16(frame[18:], uint16(prevFrameNo)) // prev_frame_no (16-bit) - binary.LittleEndian.PutUint16(frame[20:22], 0x0001) // pkt_total = 1 - binary.LittleEndian.PutUint16(frame[22:24], 0x0010) // flags + binary.LittleEndian.PutUint16(frame[20:], 0x0001) // pkt_total = 1 + binary.LittleEndian.PutUint16(frame[22:], 0x0010) // flags - binary.LittleEndian.PutUint32(frame[24:28], uint32(totalPayload)) // payload size - binary.LittleEndian.PutUint32(frame[28:32], prevFrameNo) // prev_frame_no again (32-bit) - binary.LittleEndian.PutUint32(frame[32:36], c.audioTxFrameNo) // frame_no + binary.LittleEndian.PutUint32(frame[24:], uint32(totalPayload)) // payload size + binary.LittleEndian.PutUint32(frame[28:], prevFrameNo) // prev_frame_no again (32-bit) + binary.LittleEndian.PutUint32(frame[32:], c.audioTxFrameNo) // frame_no // Audio payload copy(frame[headerSize:], payload) @@ -1182,17 +1182,17 @@ func (c *Conn) buildAudioFrame(payload []byte, timestampUS uint32, codec uint16, frameDurationMs := samplesPerFrame * 1000 / sampleRate fi := frame[headerSize+len(payload):] - binary.LittleEndian.PutUint16(fi[0:2], codec) // codec_id + binary.LittleEndian.PutUint16(fi[:], codec) // codec_id fi[2] = BuildAudioFlags(sampleRate, true, channels == 2) // flags fi[3] = 0 // cam_index fi[4] = 1 // onlineNum = 1 fi[5] = 0 // tags // fi[6:12] = reserved (already 0) - binary.LittleEndian.PutUint32(fi[12:16], (c.audioTxFrameNo-1)*frameDurationMs) + binary.LittleEndian.PutUint32(fi[12:], (c.audioTxFrameNo-1)*frameDurationMs) if c.verbose { fmt.Printf("[AUDIO TX] FrameInfo: codec=0x%04x flags=0x%02x online=%d ts=%d\n", - codec, fi[2], fi[4], binary.LittleEndian.Uint32(fi[12:16])) + codec, fi[2], fi[4], binary.LittleEndian.Uint32(fi[12:])) } return frame @@ -1205,25 +1205,25 @@ func (c *Conn) buildDisco(stage byte) []byte { frame := make([]byte, frameSize) // IOTC Frame Header [0-15] - frame[0] = 0x04 // [0] Marker1 - frame[1] = 0x02 // [1] Marker2 - frame[2] = 0x1a // [2] Marker3 - frame[3] = 0x02 // [3] Mode = Disco - binary.LittleEndian.PutUint16(frame[4:6], bodySize) // [4-5] BodySize - binary.LittleEndian.PutUint16(frame[8:10], CmdDiscoReq) // [8-9] Command = 0x0601 - binary.LittleEndian.PutUint16(frame[10:12], 0x0021) // [10-11] Flags + frame[0] = 0x04 // [0] Marker1 + frame[1] = 0x02 // [1] Marker2 + frame[2] = 0x1a // [2] Marker3 + frame[3] = 0x02 // [3] Mode = Disco + binary.LittleEndian.PutUint16(frame[4:], bodySize) // [4-5] BodySize + binary.LittleEndian.PutUint16(frame[8:], CmdDiscoReq) // [8-9] Command = 0x0601 + binary.LittleEndian.PutUint16(frame[10:], 0x0021) // [10-11] Flags // Body [16-87] body := frame[16:] - copy(body[0:20], c.uid) // [0-19] UID (20 bytes) + copy(body[:20], c.uid) // [0-19] UID (20 bytes) body[36] = 0x01 // [36] Unknown1 body[37] = 0x01 // [37] Unknown2 body[38] = 0x02 // [38] Unknown3 body[39] = 0x04 // [39] Unknown4 - copy(body[40:48], c.randomID) // [40-47] RandomID - body[48] = stage // [48] Stage (1=broadcast, 2=direct) + copy(body[40:], c.randomID) // [40-47] RandomID + body[48] = stage // [48] Stage (1=broadcast, 2=direct) if stage == 1 && len(c.authKey) > 0 { copy(body[58:], c.authKey) // [58-65] AuthKey @@ -1239,21 +1239,21 @@ func (c *Conn) buildSession() []byte { frame := make([]byte, frameSize) // IOTC Frame Header [0-15] - frame[0] = 0x04 // [0] Marker1 - frame[1] = 0x02 // [1] Marker2 - frame[2] = 0x1a // [2] Marker3 - frame[3] = 0x02 // [3] Mode - binary.LittleEndian.PutUint16(frame[4:6], bodySize) // [4-5] BodySize - binary.LittleEndian.PutUint16(frame[8:10], CmdSessionReq) // [8-9] Command = 0x0402 - binary.LittleEndian.PutUint16(frame[10:12], 0x0033) // [10-11] Flags + frame[0] = 0x04 // [0] Marker1 + frame[1] = 0x02 // [1] Marker2 + frame[2] = 0x1a // [2] Marker3 + frame[3] = 0x02 // [3] Mode + binary.LittleEndian.PutUint16(frame[4:], bodySize) // [4-5] BodySize + binary.LittleEndian.PutUint16(frame[8:], CmdSessionReq) // [8-9] Command = 0x0402 + binary.LittleEndian.PutUint16(frame[10:], 0x0033) // [10-11] Flags // Body [16-51] body := frame[16:] - copy(body[0:20], c.uid) // [0-19] UID (20 bytes) - copy(body[20:28], c.randomID) // [20-27] RandomID + copy(body[:20], c.uid) // [0-19] UID (20 bytes) + copy(body[20:], c.randomID) // [20-27] RandomID ts := uint32(time.Now().Unix()) - binary.LittleEndian.PutUint32(body[32:36], ts) // [32-35] Timestamp + binary.LittleEndian.PutUint32(body[32:], ts) // [32-35] Timestamp return frame } @@ -1291,22 +1291,22 @@ func (c *Conn) buildDataTXChannel(payload []byte, channel byte) []byte { frame := make([]byte, frameSize) // IOTC Frame Header [0-15] - frame[0] = 0x04 // [0] Marker1 - frame[1] = 0x02 // [1] Marker2 - frame[2] = 0x1a // [2] Marker3 - frame[3] = 0x0b // [3] Mode = Data - binary.LittleEndian.PutUint16(frame[4:6], uint16(bodySize)) // [4-5] BodySize - binary.LittleEndian.PutUint16(frame[6:8], c.iotcTxSeq) // [6-7] Sequence + frame[0] = 0x04 // [0] Marker1 + frame[1] = 0x02 // [1] Marker2 + frame[2] = 0x1a // [2] Marker3 + frame[3] = 0x0b // [3] Mode = Data + binary.LittleEndian.PutUint16(frame[4:], uint16(bodySize)) // [4-5] BodySize + binary.LittleEndian.PutUint16(frame[6:], c.iotcTxSeq) // [6-7] Sequence c.iotcTxSeq++ - binary.LittleEndian.PutUint16(frame[8:10], CmdDataTX) // [8-9] Command = 0x0407 - binary.LittleEndian.PutUint16(frame[10:12], 0x0021) // [10-11] Flags - copy(frame[12:14], c.randomID[:2]) // [12-13] RandomID[0:2] - frame[14] = channel // [14] Channel (0=Main, 1=Back) - frame[15] = 0x01 // [15] Marker + binary.LittleEndian.PutUint16(frame[8:], CmdDataTX) // [8-9] Command = 0x0407 + binary.LittleEndian.PutUint16(frame[10:], 0x0021) // [10-11] Flags + copy(frame[12:], c.randomID[:2]) // [12-13] RandomID[0:2] + frame[14] = channel // [14] Channel (0=Main, 1=Back) + frame[15] = 0x01 // [15] Marker // Sub-Header [16-27] - binary.LittleEndian.PutUint32(frame[16:20], 0x0000000c) // [16-19] Const - copy(frame[20:28], c.randomID[:8]) // [20-27] RandomID + binary.LittleEndian.PutUint32(frame[16:], 0x0000000c) // [16-19] Const + copy(frame[20:], c.randomID[:8]) // [20-27] RandomID // Payload [28+] copy(frame[28:], payload) @@ -1322,13 +1322,13 @@ func (c *Conn) buildACK() []byte { } ack := make([]byte, 24) - binary.LittleEndian.PutUint16(ack[0:2], MagicACK) // [0-1] Magic = 0x0009 - binary.LittleEndian.PutUint16(ack[2:4], ProtocolVersion) // [2-3] Version = 0x000C - binary.LittleEndian.PutUint32(ack[4:8], c.avTxSeq) // [4-7] TxSeq + binary.LittleEndian.PutUint16(ack[0:], MagicACK) // [0-1] Magic = 0x0009 + binary.LittleEndian.PutUint16(ack[2:], ProtocolVersion) // [2-3] Version = 0x000C + binary.LittleEndian.PutUint32(ack[4:], c.avTxSeq) // [4-7] TxSeq c.avTxSeq++ - binary.LittleEndian.PutUint32(ack[8:12], 0xffffffff) // [8-11] RxSeq (not used) - binary.LittleEndian.PutUint16(ack[12:14], c.ackFlags) // [12-13] AckFlags - binary.LittleEndian.PutUint32(ack[16:20], uint32(c.ackFlags)<<16) // [16-19] AckCounter + binary.LittleEndian.PutUint32(ack[8:], 0xffffffff) // [8-11] RxSeq (not used) + binary.LittleEndian.PutUint16(ack[12:], c.ackFlags) // [12-13] AckFlags + binary.LittleEndian.PutUint32(ack[16:], uint32(c.ackFlags)<<16) // [16-19] AckCounter return ack } @@ -1337,17 +1337,17 @@ func (c *Conn) buildKeepaliveResponse(incomingPayload []byte) []byte { frame := make([]byte, 24) // IOTC Frame Header [0-15] - frame[0] = 0x04 // [0] Marker1 - frame[1] = 0x02 // [1] Marker2 - frame[2] = 0x1a // [2] Marker3 - frame[3] = 0x0a // [3] Mode - binary.LittleEndian.PutUint16(frame[4:6], 8) // [4-5] BodySize = 8 - binary.LittleEndian.PutUint16(frame[8:10], CmdKeepaliveReq) // [8-9] Command = 0x0427 - binary.LittleEndian.PutUint16(frame[10:12], 0x0021) // [10-11] Flags + frame[0] = 0x04 // [0] Marker1 + frame[1] = 0x02 // [1] Marker2 + frame[2] = 0x1a // [2] Marker3 + frame[3] = 0x0a // [3] Mode + binary.LittleEndian.PutUint16(frame[4:], 8) // [4-5] BodySize = 8 + binary.LittleEndian.PutUint16(frame[8:], CmdKeepaliveReq) // [8-9] Command = 0x0427 + binary.LittleEndian.PutUint16(frame[10:], 0x0021) // [10-11] Flags // Body [16-23]: Echo back incoming payload if len(incomingPayload) >= 8 { - copy(frame[16:24], incomingPayload[:8]) // [16-23] EchoPayload + copy(frame[16:], incomingPayload[:8]) // [16-23] EchoPayload } return frame @@ -1357,15 +1357,15 @@ func (c *Conn) buildAVLoginPacket(magic uint16, size int, flags uint16, randomID pkt := make([]byte, size) // Header - binary.LittleEndian.PutUint16(pkt[0:2], magic) - binary.LittleEndian.PutUint16(pkt[2:4], ProtocolVersion) + binary.LittleEndian.PutUint16(pkt, magic) + binary.LittleEndian.PutUint16(pkt[2:], ProtocolVersion) // bytes 4-15: reserved (zeros) // Payload info at offset 16 payloadSize := uint16(size - 24) // total - header(16) - random(4) - padding(4) - binary.LittleEndian.PutUint16(pkt[16:18], payloadSize) - binary.LittleEndian.PutUint16(pkt[18:20], flags) - copy(pkt[20:24], randomID[:4]) + binary.LittleEndian.PutUint16(pkt[16:], payloadSize) + binary.LittleEndian.PutUint16(pkt[18:], flags) + copy(pkt[20:], randomID[:4]) // Credentials (each field is 256 bytes) copy(pkt[24:], DefaultUser) // username at offset 24 (payload byte 0) @@ -1373,13 +1373,13 @@ func (c *Conn) buildAVLoginPacket(magic uint16, size int, flags uint16, randomID // Config section (AVClientStartInConfig) starts at offset 536 (= 24 + 256 + 256) // Layout: resend(4) + security_mode(4) + auth_type(4) + sync_recv_data(4) + ... - binary.LittleEndian.PutUint32(pkt[536:540], 0) // resend=0 - binary.LittleEndian.PutUint32(pkt[540:544], 2) // security_mode=2 (AV_SECURITY_AUTO) - binary.LittleEndian.PutUint32(pkt[544:548], 0) // auth_type=0 (AV_AUTH_PASSWORD) - binary.LittleEndian.PutUint32(pkt[548:552], 0) // sync_recv_data=0 - binary.LittleEndian.PutUint32(pkt[552:556], DefaultCapabilities) // capabilities - binary.LittleEndian.PutUint16(pkt[556:558], 0) // request_video_on_connect=0 - binary.LittleEndian.PutUint16(pkt[558:560], 0) // request_audio_on_connect=0 + binary.LittleEndian.PutUint32(pkt[536:], 0) // resend=0 + binary.LittleEndian.PutUint32(pkt[540:], 2) // security_mode=2 (AV_SECURITY_AUTO) + binary.LittleEndian.PutUint32(pkt[544:], 0) // auth_type=0 (AV_AUTH_PASSWORD) + binary.LittleEndian.PutUint32(pkt[548:], 0) // sync_recv_data=0 + binary.LittleEndian.PutUint32(pkt[552:], DefaultCapabilities) // capabilities + binary.LittleEndian.PutUint16(pkt[556:], 0) // request_video_on_connect=0 + binary.LittleEndian.PutUint16(pkt[558:], 0) // request_audio_on_connect=0 return pkt } @@ -1388,23 +1388,23 @@ func (c *Conn) buildAVLoginResponse(checksum uint32) []byte { resp := make([]byte, 60) // Header - binary.LittleEndian.PutUint16(resp[0:2], 0x2100) // Magic - binary.LittleEndian.PutUint16(resp[2:4], 0x000c) // Version - resp[4] = 0x10 // Response type (success) + binary.LittleEndian.PutUint16(resp, 0x2100) // Magic + binary.LittleEndian.PutUint16(resp[2:], 0x000c) // Version + resp[4] = 0x10 // Response type (success) // Payload info - binary.LittleEndian.PutUint32(resp[16:20], 0x24) // Payload size = 36 - binary.LittleEndian.PutUint32(resp[20:24], checksum) // Echo checksum from request! + binary.LittleEndian.PutUint32(resp[16:], 0x24) // Payload size = 36 + binary.LittleEndian.PutUint32(resp[20:], checksum) // Echo checksum from request! // Payload (36 bytes starting at offset 24) resp[29] = 0x01 // EnableFlag resp[31] = 0x01 // TwoWayStreaming - binary.LittleEndian.PutUint32(resp[36:40], 0x04) // BufferConfig - binary.LittleEndian.PutUint32(resp[40:44], 0x001f07fb) // Capabilities + binary.LittleEndian.PutUint32(resp[36:], 0x04) // BufferConfig + binary.LittleEndian.PutUint32(resp[40:], 0x001f07fb) // Capabilities - binary.LittleEndian.PutUint16(resp[54:56], 0x0003) // ChannelInfo1 - binary.LittleEndian.PutUint16(resp[56:58], 0x0002) // ChannelInfo2 + binary.LittleEndian.PutUint16(resp[54:], 0x0003) // ChannelInfo1 + binary.LittleEndian.PutUint16(resp[56:], 0x0002) // ChannelInfo2 return resp } @@ -1414,32 +1414,32 @@ func (c *Conn) buildIOCtrlFrame(payload []byte) []byte { frame := make([]byte, headerSize+len(payload)) // Magic (same as protocol version for IOCtrl frames) - binary.LittleEndian.PutUint16(frame[0:2], ProtocolVersion) + binary.LittleEndian.PutUint16(frame, ProtocolVersion) // Version - binary.LittleEndian.PutUint16(frame[2:4], ProtocolVersion) + binary.LittleEndian.PutUint16(frame[2:], ProtocolVersion) // AVSeq (4-7) seq := c.avTxSeq c.avTxSeq++ - binary.LittleEndian.PutUint32(frame[4:8], seq) + binary.LittleEndian.PutUint32(frame[4:], seq) // Bytes 8-15: reserved // Channel: MagicIOCtrl (0x7000) for IOCtrl frames - binary.LittleEndian.PutUint16(frame[16:18], MagicIOCtrl) + binary.LittleEndian.PutUint16(frame[16:], MagicIOCtrl) // SubChannel (18-19): increments with each IOCtrl command sent - binary.LittleEndian.PutUint16(frame[18:20], c.ioctrlSeq) + binary.LittleEndian.PutUint16(frame[18:], c.ioctrlSeq) // IOCTLSeq (20-23): always 1 - binary.LittleEndian.PutUint32(frame[20:24], 1) + binary.LittleEndian.PutUint32(frame[20:], 1) // PayloadSize (24-27): payload + 4 bytes padding - binary.LittleEndian.PutUint32(frame[24:28], uint32(len(payload)+4)) + binary.LittleEndian.PutUint32(frame[24:], uint32(len(payload)+4)) // Flag (28-31): matches subChannel in SDK - binary.LittleEndian.PutUint32(frame[28:32], uint32(c.ioctrlSeq)) + binary.LittleEndian.PutUint32(frame[28:], uint32(c.ioctrlSeq)) // Bytes 32-36: reserved // Byte 37: 0x01 diff --git a/pkg/wyze/tutk/types.go b/pkg/wyze/tutk/types.go index 3596a47e..4ba95f01 100644 --- a/pkg/wyze/tutk/types.go +++ b/pkg/wyze/tutk/types.go @@ -1,5 +1,7 @@ package tutk +import "encoding/binary" + const ( // Start packets - first fragment of a frame // 0x08: Extended start (36-byte header, no FrameInfo) @@ -114,10 +116,10 @@ func ParsePacketHeader(data []byte) *PacketHeader { // [14-15] pkt_idx OR 0x0028 (FrameInfo marker) - ONLY 0x0028 in End packets! // [16-17] payload_size // [24-27] frame_no (uint32) - hdr.PktTotal = uint16(data[12]) | uint16(data[13])<<8 - pktIdxOrMarker := uint16(data[14]) | uint16(data[15])<<8 - hdr.PayloadSize = uint16(data[16]) | uint16(data[17])<<8 - hdr.FrameNo = uint32(data[24]) | uint32(data[25])<<8 | uint32(data[26])<<16 | uint32(data[27])<<24 + hdr.PktTotal = binary.LittleEndian.Uint16(data[12:]) + pktIdxOrMarker := binary.LittleEndian.Uint16(data[14:]) + hdr.PayloadSize = binary.LittleEndian.Uint16(data[16:]) + hdr.FrameNo = binary.LittleEndian.Uint32(data[24:]) // 0x0028 is FrameInfo marker ONLY in End packets, otherwise it's pkt_idx=40 if IsEndFrame(hdr.FrameType) && pktIdxOrMarker == 0x0028 { @@ -135,10 +137,10 @@ func ParsePacketHeader(data []byte) *PacketHeader { // [24-25] payload_size // [32-35] frame_no (uint32) - GLOBAL frame counter, matches 28-byte [24-27] // NOTE: [18-19] is channel-specific frame index, NOT used for reassembly! - hdr.PktTotal = uint16(data[20]) | uint16(data[21])<<8 - pktIdxOrMarker := uint16(data[22]) | uint16(data[23])<<8 - hdr.PayloadSize = uint16(data[24]) | uint16(data[25])<<8 - hdr.FrameNo = uint32(data[32]) | uint32(data[33])<<8 | uint32(data[34])<<16 | uint32(data[35])<<24 + hdr.PktTotal = binary.LittleEndian.Uint16(data[20:]) + pktIdxOrMarker := binary.LittleEndian.Uint16(data[22:]) + hdr.PayloadSize = binary.LittleEndian.Uint16(data[24:]) + hdr.FrameNo = binary.LittleEndian.Uint32(data[32:]) // 0x0028 is FrameInfo marker ONLY in End packets, otherwise it's pkt_idx=40 if IsEndFrame(hdr.FrameType) && pktIdxOrMarker == 0x0028 {