From 4577390130b351e56dd0d031ef3a7effd04d82cc Mon Sep 17 00:00:00 2001 From: Hugo Aboud Date: Tue, 19 Aug 2025 16:16:01 -0300 Subject: [PATCH 01/14] Sanitize credentials on websocket error messages --- internal/api/ws/ws.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/internal/api/ws/ws.go b/internal/api/ws/ws.go index 1d945bfe..5a7d34be 100644 --- a/internal/api/ws/ws.go +++ b/internal/api/ws/ws.go @@ -8,6 +8,7 @@ import ( "strings" "sync" "time" + "regexp" "github.com/AlexxIT/go2rtc/internal/api" "github.com/AlexxIT/go2rtc/internal/app" @@ -132,7 +133,11 @@ func apiWS(w http.ResponseWriter, r *http.Request) { if handler := wsHandlers[msg.Type]; handler != nil { go func() { if err = handler(tr, msg); err != nil { - tr.Write(&Message{Type: "error", Value: msg.Type + ": " + err.Error()}) + // Some streams such as ffmpeg might return credentials on error messages + errMsg := err.Error() + sanitizer := regexp.MustCompile(`(\w+)://(.*)@`) + errMsg = sanitizer.ReplaceAllString(errMsg, "$1://******@") + tr.Write(&Message{Type: "error", Value: msg.Type + ": " + errMsg}) } }() } From 8f7cbdf60a6227d90a8e3a7bd57b484bb0bf0d73 Mon Sep 17 00:00:00 2001 From: Ragnar Petursson <74888286+kvikindi@users.noreply.github.com> Date: Sat, 23 Aug 2025 18:09:28 +0100 Subject: [PATCH 02/14] Update Proxmox Helper Scripts link in README.md Changed link to current link, as previous repository is inactive as of November 2nd 2024. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9712bbde..12342a03 100644 --- a/README.md +++ b/README.md @@ -1391,7 +1391,7 @@ streams: - [Arch User Repository](https://linux-packages.com/aur/package/go2rtc) - [Gentoo](https://github.com/inode64/inode64-overlay/tree/main/media-video/go2rtc) - [NixOS](https://search.nixos.org/packages?query=go2rtc) -- [Proxmox Helper Scripts](https://tteck.github.io/Proxmox/) +- [Proxmox Helper Scripts](https://github.com/community-scripts/ProxmoxVE/) - [QNAP](https://www.myqnap.org/product/go2rtc/) - [Synology NAS](https://synocommunity.com/package/go2rtc) - [Unraid](https://unraid.net/community/apps?q=go2rtc) From 33f0fd5fe6b6d1baf0fe742ce7ffa237a58dfddf Mon Sep 17 00:00:00 2001 From: Alex X Date: Thu, 10 Jul 2025 16:47:52 +0300 Subject: [PATCH 03/14] Add lightNVR project to readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 12342a03..13943770 100644 --- a/README.md +++ b/README.md @@ -1384,6 +1384,7 @@ streams: - [ioBroker.euSec](https://github.com/bropat/ioBroker.eusec) - [ioBroker](https://www.iobroker.net/) adapter for controlling Eufy security devices - [MMM-go2rtc](https://github.com/Anonym-tsk/MMM-go2rtc) - MagicMirror² module - [ring-mqtt](https://github.com/tsightler/ring-mqtt) - Ring-to-MQTT bridge +- [lightNVR](https://github.com/opensensor/lightNVR) **Distributions** From beb82045ffd31dca4ef0046cf7c7da05f0fa19a1 Mon Sep 17 00:00:00 2001 From: Alex X Date: Fri, 29 Aug 2025 16:45:19 +0300 Subject: [PATCH 04/14] Fix yet another broken Content-Base for RTSP #1852 --- pkg/rtsp/helpers.go | 27 +++++++++++++++++++++++---- pkg/rtsp/rtsp_test.go | 10 ++++++++-- 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/pkg/rtsp/helpers.go b/pkg/rtsp/helpers.go index d8ed1685..c73bd0a2 100644 --- a/pkg/rtsp/helpers.go +++ b/pkg/rtsp/helpers.go @@ -116,20 +116,39 @@ func findFmtpLine(payloadType uint8, descriptions []*sdp.MediaDescription) strin // urlParse fix bugs: // 1. Content-Base: rtsp://::ffff:192.168.1.123/onvif/profile.1/ // 2. Content-Base: rtsp://rtsp://turret2-cam.lan:554/stream1/ +// 3. Content-Base: 192.168.253.220:1935/ func urlParse(rawURL string) (*url.URL, error) { // fix https://github.com/AlexxIT/go2rtc/issues/830 if strings.HasPrefix(rawURL, "rtsp://rtsp://") { rawURL = rawURL[7:] } + // fix https://github.com/AlexxIT/go2rtc/issues/1852 + if !strings.Contains(rawURL, "://") { + rawURL = "rtsp://" + rawURL + } + u, err := url.Parse(rawURL) if err != nil && strings.HasSuffix(err.Error(), "after host") { - if i1 := strings.Index(rawURL, "://"); i1 > 0 { - if i2 := strings.IndexByte(rawURL[i1+3:], '/'); i2 > 0 { - return urlParse(rawURL[:i1+3+i2] + ":" + rawURL[i1+3+i2:]) - } + if i := indexN(rawURL, '/', 3); i > 0 { + return urlParse(rawURL[:i] + ":" + rawURL[i:]) } } return u, err } + +func indexN(s string, c byte, n int) int { + var offset int + for { + i := strings.IndexByte(s[offset:], c) + if i < 0 { + break + } + if n--; n == 0 { + return offset + i + } + offset += i + 1 + } + return -1 +} diff --git a/pkg/rtsp/rtsp_test.go b/pkg/rtsp/rtsp_test.go index 14c99803..282c04f8 100644 --- a/pkg/rtsp/rtsp_test.go +++ b/pkg/rtsp/rtsp_test.go @@ -11,14 +11,20 @@ func TestURLParse(t *testing.T) { // https://github.com/AlexxIT/WebRTC/issues/395 base := "rtsp://::ffff:192.168.1.123/onvif/profile.1/" u, err := urlParse(base) - assert.Empty(t, err) + assert.NoError(t, err) assert.Equal(t, "::ffff:192.168.1.123:", u.Host) // https://github.com/AlexxIT/go2rtc/issues/208 base = "rtsp://rtsp://turret2-cam.lan:554/stream1/" u, err = urlParse(base) - assert.Empty(t, err) + assert.NoError(t, err) assert.Equal(t, "turret2-cam.lan:554", u.Host) + + // https://github.com/AlexxIT/go2rtc/issues/1852 + base = "192.168.253.220:1935/" + u, err = urlParse(base) + assert.NoError(t, err) + assert.Equal(t, "192.168.253.220:1935", u.Host) } func TestBugSDP1(t *testing.T) { From cd7fa5d09cc020d6ce697f619d02c91eaf146ac1 Mon Sep 17 00:00:00 2001 From: Alex X Date: Wed, 10 Sep 2025 12:27:13 +0300 Subject: [PATCH 05/14] Fix RepairAVCC in some cases --- pkg/h264/avcc.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pkg/h264/avcc.go b/pkg/h264/avcc.go index d21e3ea3..dd3a5687 100644 --- a/pkg/h264/avcc.go +++ b/pkg/h264/avcc.go @@ -16,6 +16,11 @@ func RepairAVCC(codec *core.Codec, handler core.HandlerFunc) core.HandlerFunc { ps := JoinNALU(sps, pps) return func(packet *rtp.Packet) { + // this can happen for FLV from FFmpeg + if NALUType(packet.Payload) == NALUTypeSEI { + size := int(binary.BigEndian.Uint32(packet.Payload)) + 4 + packet.Payload = packet.Payload[size:] + } if NALUType(packet.Payload) == NALUTypeIFrame { packet.Payload = Join(ps, packet.Payload) } From 788afb7189979db3533cae1f7a1ed0c3c859121d Mon Sep 17 00:00:00 2001 From: Alex X Date: Thu, 18 Sep 2025 23:08:33 +0300 Subject: [PATCH 06/14] Fix HomeKit server support on iOS 26 #1843 --- pkg/hap/camera/accessory.go | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/pkg/hap/camera/accessory.go b/pkg/hap/camera/accessory.go index 42037d96..973983ec 100644 --- a/pkg/hap/camera/accessory.go +++ b/pkg/hap/camera/accessory.go @@ -12,7 +12,7 @@ func NewAccessory(manuf, model, name, serial, firmware string) *hap.Accessory { hap.ServiceAccessoryInformation(manuf, model, name, serial, firmware), ServiceCameraRTPStreamManagement(), //hap.ServiceHAPProtocolInformation(), - //ServiceMicrophone(), + ServiceMicrophone(), }, } acc.InitIID() @@ -30,17 +30,17 @@ func ServiceMicrophone() *hap.Service { Perms: hap.EVPRPW, //Descr: "Mute", }, - { - Type: "119", - Format: hap.FormatUInt8, - Value: 100, - Perms: hap.EVPRPW, - //Descr: "Volume", - //Unit: hap.UnitPercentage, - //MinValue: 0, - //MaxValue: 100, - //MinStep: 1, - }, + //{ + // Type: "119", + // Format: hap.FormatUInt8, + // Value: 100, + // Perms: hap.EVPRPW, + // //Descr: "Volume", + // //Unit: hap.UnitPercentage, + // //MinValue: 0, + // //MaxValue: 100, + // //MinStep: 1, + //}, }, } } @@ -62,7 +62,7 @@ func ServiceCameraRTPStreamManagement() *hap.Service { VideoAttrs: []VideoAttrs{ {Width: 1920, Height: 1080, Framerate: 30}, {Width: 1280, Height: 720, Framerate: 30}, // important for iPhones - {Width: 320, Height: 240, Framerate: 15}, // apple watch + {Width: 320, Height: 240, Framerate: 15}, // apple watch }, }, }, From 8b4df5f02c7882256799f8c769e5c1e999d8bd6b Mon Sep 17 00:00:00 2001 From: Alex X Date: Fri, 19 Sep 2025 15:21:02 +0300 Subject: [PATCH 07/14] Code refactoring for #1841 --- internal/api/ws/ws.go | 7 ++----- pkg/core/core_test.go | 14 ++++++++++++++ pkg/core/helpers.go | 12 ++++++++++++ 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/internal/api/ws/ws.go b/internal/api/ws/ws.go index 5a7d34be..981d1b41 100644 --- a/internal/api/ws/ws.go +++ b/internal/api/ws/ws.go @@ -8,10 +8,10 @@ import ( "strings" "sync" "time" - "regexp" "github.com/AlexxIT/go2rtc/internal/api" "github.com/AlexxIT/go2rtc/internal/app" + "github.com/AlexxIT/go2rtc/pkg/core" "github.com/gorilla/websocket" "github.com/rs/zerolog" ) @@ -133,10 +133,7 @@ func apiWS(w http.ResponseWriter, r *http.Request) { if handler := wsHandlers[msg.Type]; handler != nil { go func() { if err = handler(tr, msg); err != nil { - // Some streams such as ffmpeg might return credentials on error messages - errMsg := err.Error() - sanitizer := regexp.MustCompile(`(\w+)://(.*)@`) - errMsg = sanitizer.ReplaceAllString(errMsg, "$1://******@") + errMsg := core.StripUserinfo(err.Error()) tr.Write(&Message{Type: "error", Value: msg.Type + ": " + errMsg}) } }() diff --git a/pkg/core/core_test.go b/pkg/core/core_test.go index 4a05380a..e7845ca7 100644 --- a/pkg/core/core_test.go +++ b/pkg/core/core_test.go @@ -118,3 +118,17 @@ func TestName(t *testing.T) { // stage3 _ = prod2.Stop() } + +func TestStripUserinfo(t *testing.T) { + s := `streams: + test: + - ffmpeg:rtsp://username:password@10.1.2.3:554/stream1 + - ffmpeg:rtsp://10.1.2.3:554/stream1@#video=copy +` + s = StripUserinfo(s) + require.Equal(t, `streams: + test: + - ffmpeg:rtsp://***@10.1.2.3:554/stream1 + - ffmpeg:rtsp://10.1.2.3:554/stream1@#video=copy +`, s) +} diff --git a/pkg/core/helpers.go b/pkg/core/helpers.go index 72afe897..161a5504 100644 --- a/pkg/core/helpers.go +++ b/pkg/core/helpers.go @@ -2,6 +2,7 @@ package core import ( "crypto/rand" + "regexp" "runtime" "strconv" "strings" @@ -77,3 +78,14 @@ func Caller() string { _, file, line, _ := runtime.Caller(1) return file + ":" + strconv.Itoa(line) } + +const ( + unreserved = `A-Za-z0-9-._~` + subdelims = `!$&'()*+,;=` + userinfo = unreserved + subdelims + `%:` +) + +func StripUserinfo(s string) string { + sanitizer := regexp.MustCompile(`://[` + userinfo + `]+@`) + return sanitizer.ReplaceAllString(s, `://***@`) +} From 45cbbaf1cfa399d79081d7a55708b0019ac77dc1 Mon Sep 17 00:00:00 2001 From: Alex X Date: Fri, 19 Sep 2025 15:26:54 +0300 Subject: [PATCH 08/14] Fixed a race condition when changing the config file --- internal/app/config.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/internal/app/config.go b/internal/app/config.go index 9d4480b7..f0eb36e0 100644 --- a/internal/app/config.go +++ b/internal/app/config.go @@ -5,6 +5,7 @@ import ( "os" "path/filepath" "strings" + "sync" "github.com/AlexxIT/go2rtc/pkg/shell" "github.com/AlexxIT/go2rtc/pkg/yaml" @@ -18,11 +19,16 @@ func LoadConfig(v any) { } } +var configMu sync.Mutex + func PatchConfig(path []string, value any) error { if ConfigPath == "" { return errors.New("config file disabled") } + configMu.Lock() + defer configMu.Unlock() + // empty config is OK b, _ := os.ReadFile(ConfigPath) From 40269328fb28eb79413a097e4f3e94b051ff477c Mon Sep 17 00:00:00 2001 From: Alex X Date: Fri, 19 Sep 2025 15:27:58 +0300 Subject: [PATCH 09/14] Fix insecure PINs for HomeKit server --- pkg/hap/helpers.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pkg/hap/helpers.go b/pkg/hap/helpers.go index d1400b84..3900f935 100644 --- a/pkg/hap/helpers.go +++ b/pkg/hap/helpers.go @@ -71,11 +71,17 @@ type JSONCharacter struct { Event any `json:"ev,omitempty"` } +// 4.2.1.2 Invalid Setup Codes +const insecurePINs = "00000000 11111111 22222222 33333333 44444444 55555555 66666666 77777777 88888888 99999999 12345678 87654321" + func SanitizePin(pin string) (string, error) { s := strings.ReplaceAll(pin, "-", "") if len(s) != 8 { return "", errors.New("hap: wrong PIN format: " + pin) } + if strings.Contains(insecurePINs, s) { + return "", errors.New("hap: insecure PIN: " + pin) + } // 123-45-678 return s[:3] + "-" + s[3:5] + "-" + s[5:], nil } From 3b976c68122228e84fbf41c4c280edbe3e10ecbb Mon Sep 17 00:00:00 2001 From: Alex X Date: Fri, 19 Sep 2025 15:29:24 +0300 Subject: [PATCH 10/14] Improve HomeKit TLV format parser --- pkg/hap/tlv8/tlv8.go | 131 +++++++++++++++++++++++++------------- pkg/hap/tlv8/tlv8_test.go | 47 ++++++++++++++ 2 files changed, 133 insertions(+), 45 deletions(-) diff --git a/pkg/hap/tlv8/tlv8.go b/pkg/hap/tlv8/tlv8.go index 068f21c3..7af27ea4 100644 --- a/pkg/hap/tlv8/tlv8.go +++ b/pkg/hap/tlv8/tlv8.go @@ -46,6 +46,8 @@ func Marshal(v any) ([]byte, error) { } switch kind { + case reflect.Slice: + return appendSlice(nil, value) case reflect.Struct: return appendStruct(nil, value) } @@ -53,6 +55,23 @@ func Marshal(v any) ([]byte, error) { return nil, errors.New("tlv8: not implemented: " + kind.String()) } +// separator the most confusing meaning in the documentation. +// It can have a value of 0x00 or 0xFF or even 0x05. +const separator = 0xFF + +func appendSlice(b []byte, value reflect.Value) ([]byte, error) { + for i := 0; i < value.Len(); i++ { + if i > 0 { + b = append(b, separator, 0) + } + var err error + if b, err = appendStruct(b, value.Index(i)); err != nil { + return nil, err + } + } + return b, nil +} + func appendStruct(b []byte, value reflect.Value) ([]byte, error) { valueType := value.Type() @@ -121,7 +140,7 @@ func appendValue(b []byte, tag byte, value reflect.Value) ([]byte, error) { case reflect.Slice: for i := 0; i < value.Len(); i++ { if i > 0 { - b = append(b, 0, 0) + b = append(b, separator, 0) } if b, err = appendValue(b, tag, value.Index(i)); err != nil { return nil, err @@ -179,64 +198,86 @@ func Unmarshal(data []byte, v any) error { kind = value.Kind() } - if kind != reflect.Struct { - return errors.New("tlv8: not implemented: " + kind.String()) + switch kind { + case reflect.Slice: + return unmarshalSlice(data, value) + case reflect.Struct: + return unmarshalStruct(data, value) } - return unmarshalStruct(data, value) + return errors.New("tlv8: not implemented: " + kind.String()) } -func unmarshalStruct(b []byte, value reflect.Value) error { - var waitSlice bool +// unmarshalTLV can return two types of errors: +// - critical and then the value of []byte will be nil +// - not critical and then []byte will contain the value +func unmarshalTLV(b []byte, value reflect.Value) ([]byte, error) { + if len(b) < 2 { + return nil, errors.New("tlv8: wrong size: " + value.Type().Name()) + } - for len(b) >= 2 { - t := b[0] - l := int(b[1]) + t := b[0] + l := int(b[1]) - // array item divider - if t == 0 && l == 0 { - b = b[2:] - waitSlice = true - continue + // array item divider (t == 0x00 || t == 0xFF) + if l == 0 { + return b[2:], errors.New("tlv8: zero item") + } + + var v []byte + + for { + if len(b) < 2+l { + return nil, errors.New("tlv8: wrong size: " + value.Type().Name()) } - var v []byte + v = append(v, b[2:2+l]...) + b = b[2+l:] - for { - if len(b) < 2+l { - return errors.New("tlv8: wrong size: " + value.Type().Name()) + // if size == 255 and same tag - continue read big payload + if l < 255 || len(b) < 2 || b[0] != t { + break + } + + l = int(b[1]) + } + + tag := strconv.Itoa(int(t)) + + valueField, ok := getStructField(value, tag) + if !ok { + return b, fmt.Errorf("tlv8: can't find T=%d,L=%d,V=%x for: %s", t, l, v, value.Type().Name()) + } + + if err := unmarshalValue(v, valueField); err != nil { + return nil, err + } + + return b, nil +} + +func unmarshalSlice(b []byte, value reflect.Value) error { + valueIndex := value.Index(growSlice(value)) + for len(b) > 0 { + var err error + if b, err = unmarshalTLV(b, valueIndex); err != nil { + if b != nil { + valueIndex = value.Index(growSlice(value)) + continue } - - v = append(v, b[2:2+l]...) - b = b[2+l:] - - // if size == 255 and same tag - continue read big payload - if l < 255 || len(b) < 2 || b[0] != t { - break - } - - l = int(b[1]) - } - - tag := strconv.Itoa(int(t)) - - valueField, ok := getStructField(value, tag) - if !ok { - return fmt.Errorf("tlv8: can't find T=%d,L=%d,V=%x for: %s", t, l, v, value.Type().Name()) - } - - if waitSlice { - if valueField.Kind() != reflect.Slice { - return fmt.Errorf("tlv8: should be slice T=%d,L=%d,V=%x for: %s", t, l, v, value.Type().Name()) - } - waitSlice = false - } - - if err := unmarshalValue(v, valueField); err != nil { return err } } + return nil +} +func unmarshalStruct(b []byte, value reflect.Value) error { + for len(b) > 0 { + var err error + if b, err = unmarshalTLV(b, value); b == nil && err != nil { + return err + } + } return nil } diff --git a/pkg/hap/tlv8/tlv8_test.go b/pkg/hap/tlv8/tlv8_test.go index 5ac41fec..bb44c981 100644 --- a/pkg/hap/tlv8/tlv8_test.go +++ b/pkg/hap/tlv8/tlv8_test.go @@ -2,6 +2,7 @@ package tlv8 import ( "encoding/hex" + "strings" "testing" "github.com/stretchr/testify/require" @@ -107,3 +108,49 @@ func TestInterface(t *testing.T) { require.Equal(t, src, dst) } + +func TestSlice1(t *testing.T) { + var v struct { + VideoAttrs []struct { + Width uint16 `tlv8:"1"` + Height uint16 `tlv8:"2"` + Framerate uint8 `tlv8:"3"` + } `tlv8:"3"` + } + + s := `030b010280070202380403011e ff00 030b010200050202d00203011e` + b1, err := hex.DecodeString(strings.ReplaceAll(s, " ", "")) + require.NoError(t, err) + + err = Unmarshal(b1, &v) + require.NoError(t, err) + + require.Len(t, v.VideoAttrs, 2) + + b2, err := Marshal(v) + require.NoError(t, err) + + require.Equal(t, b1, b2) +} + +func TestSlice2(t *testing.T) { + var v []struct { + Width uint16 `tlv8:"1"` + Height uint16 `tlv8:"2"` + Framerate uint8 `tlv8:"3"` + } + + s := `010280070202380403011e ff00 010200050202d00203011e` + b1, err := hex.DecodeString(strings.ReplaceAll(s, " ", "")) + require.NoError(t, err) + + err = Unmarshal(b1, &v) + require.NoError(t, err) + + require.Len(t, v, 2) + + b2, err := Marshal(v) + require.NoError(t, err) + + require.Equal(t, b1, b2) +} From e072842b7a6ccd69cd2ddb8c9df9855df467a042 Mon Sep 17 00:00:00 2001 From: mihailstoynov Date: Sun, 21 Sep 2025 22:56:59 +0300 Subject: [PATCH 11/14] Update README.md example for VGA and HD streams for ease of use --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 13943770..c9b884f3 100644 --- a/README.md +++ b/README.md @@ -531,7 +531,7 @@ streams: - stream quality is the same as [RTSP protocol](https://www.tapo.com/en/faq/34/) - use the **cloud password**, this is not the RTSP password! you do not need to add a login! -- you can also use UPPERCASE MD5 hash from your cloud password with `admin` username +- you can also use **UPPERCASE** MD5 hash from your cloud password with `admin` username - some new camera firmwares require SHA256 instead of MD5 ```yaml @@ -542,6 +542,10 @@ streams: camera2: tapo://admin:UPPERCASE-MD5@192.168.1.123 # admin username and UPPERCASE SHA256 cloud-password hash camera3: tapo://admin:UPPERCASE-SHA256@192.168.1.123 + # VGA stream (the so called substream, the lower resolution one) + camera4: tapo://cloud-password@192.168.1.123?subtype=1 + # HD stream (default) + camera5: tapo://cloud-password@192.168.1.123?subtype=0 ``` ```bash From fd682306e7a236962b3e4ecbf9ce7358a3673551 Mon Sep 17 00:00:00 2001 From: Alex X Date: Mon, 22 Sep 2025 18:11:47 +0300 Subject: [PATCH 12/14] Fix MultiUDPMuxDefault panic #1646 --- pkg/webrtc/api.go | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/pkg/webrtc/api.go b/pkg/webrtc/api.go index fe49ef1e..79cf6d3c 100644 --- a/pkg/webrtc/api.go +++ b/pkg/webrtc/api.go @@ -125,13 +125,20 @@ func NewServerAPI(network, address string, filters *Filters) (*webrtc.API, error networks = append(networks, ice.NetworkType(ntype)) } - udpMux, _ = ice.NewMultiUDPMuxFromPort( + var err error + if udpMux, err = ice.NewMultiUDPMuxFromPort( port, ice.UDPMuxFromPortWithInterfaceFilter(interfaceFilter), ice.UDPMuxFromPortWithIPFilter(ipFilter), ice.UDPMuxFromPortWithNetworks(networks...), - ) - } else if ln, err := net.ListenPacket("udp", address); err == nil { + ); err != nil { + return nil, err + } + } else { + ln, err := net.ListenPacket("udp", address) + if err != nil { + return nil, err + } udpMux = ice.NewUDPMuxDefault(ice.UDPMuxParams{UDPConn: ln}) } s.SetICEUDPMux(udpMux) From 26f16e392f9bd3733b131efe477a7e7052e487f4 Mon Sep 17 00:00:00 2001 From: Alex X Date: Wed, 24 Sep 2025 16:18:18 +0300 Subject: [PATCH 13/14] Update go (build) version to 1.25 and related readme --- .github/workflows/build.yml | 2 +- README.md | 4 ++-- docker/Dockerfile | 2 +- docker/hardware.Dockerfile | 2 +- docker/rockchip.Dockerfile | 2 +- scripts/README.md | 4 ++-- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ac4d758d..c802df63 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -19,7 +19,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v5 - with: { go-version: '1.24' } + with: { go-version: '1.25' } - name: Build go2rtc_win64 env: { GOOS: windows, GOARCH: amd64 } diff --git a/README.md b/README.md index c9b884f3..edaa1159 100644 --- a/README.md +++ b/README.md @@ -116,7 +116,7 @@ Ultimate camera streaming application with support for RTSP, WebRTC, HomeKit, FF Download binary for your OS from [latest release](https://github.com/AlexxIT/go2rtc/releases/): - `go2rtc_win64.zip` - Windows 10+ 64-bit -- `go2rtc_win32.zip` - Windows 7+ 32-bit +- `go2rtc_win32.zip` - Windows 10+ 32-bit - `go2rtc_win_arm64.zip` - Windows ARM 64-bit - `go2rtc_linux_amd64` - Linux 64-bit - `go2rtc_linux_i386` - Linux 32-bit @@ -124,7 +124,7 @@ Download binary for your OS from [latest release](https://github.com/AlexxIT/go2 - `go2rtc_linux_arm` - Linux ARM 32-bit (ex. Raspberry 32-bit OS) - `go2rtc_linux_armv6` - Linux ARMv6 (for old Raspberry 1 and Zero) - `go2rtc_linux_mipsel` - Linux MIPS (ex. [Xiaomi Gateway 3](https://github.com/AlexxIT/XiaomiGateway3), [Wyze cameras](https://github.com/gtxaspec/wz_mini_hacks)) -- `go2rtc_mac_amd64.zip` - macOS 10.13+ Intel 64-bit +- `go2rtc_mac_amd64.zip` - macOS 11+ Intel 64-bit - `go2rtc_mac_arm64.zip` - macOS ARM 64-bit - `go2rtc_freebsd_amd64.zip` - FreeBSD 64-bit - `go2rtc_freebsd_arm64.zip` - FreeBSD ARM 64-bit diff --git a/docker/Dockerfile b/docker/Dockerfile index 34a96757..854ea6c9 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -2,7 +2,7 @@ # 0. Prepare images ARG PYTHON_VERSION="3.11" -ARG GO_VERSION="1.24" +ARG GO_VERSION="1.25" # 1. Build go2rtc binary diff --git a/docker/hardware.Dockerfile b/docker/hardware.Dockerfile index 03b7d496..a80d08d7 100644 --- a/docker/hardware.Dockerfile +++ b/docker/hardware.Dockerfile @@ -4,7 +4,7 @@ # only debian 13 (trixie) has latest ffmpeg # https://packages.debian.org/trixie/ffmpeg ARG DEBIAN_VERSION="trixie-slim" -ARG GO_VERSION="1.24-bookworm" +ARG GO_VERSION="1.25-bookworm" # 1. Build go2rtc binary diff --git a/docker/rockchip.Dockerfile b/docker/rockchip.Dockerfile index a7a1b450..949db83b 100644 --- a/docker/rockchip.Dockerfile +++ b/docker/rockchip.Dockerfile @@ -2,7 +2,7 @@ # 0. Prepare images ARG PYTHON_VERSION="3.13-slim-bookworm" -ARG GO_VERSION="1.24-bookworm" +ARG GO_VERSION="1.25-bookworm" # 1. Build go2rtc binary diff --git a/scripts/README.md b/scripts/README.md index 9c7f4544..5594915d 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -1,5 +1,7 @@ ## Versions +**PS.** Unfortunately, due to the dependency on `pion/webrtc/v4 v4.1.3`, had to upgrade go to `1.23`. Everything described below is not relevant. + [Go 1.20](https://go.dev/doc/go1.20) is last version with support Windows 7 and macOS 10.13. Go 1.21 support only Windows 10 and macOS 10.15. @@ -16,8 +18,6 @@ golang.org/x/sys v0.30.0 // indirect golang.org/x/tools v0.24.0 // indirect ``` -**PS.** Unfortunately, due to the dependency on `pion/webrtc/v4 v4.1.3`, had to upgrade go to `1.23`. - ## Build - UPX-3.96 pack broken bin for `linux_mipsel` From df95ce39d08f4eae0544f7dc340f8d8ee27a5752 Mon Sep 17 00:00:00 2001 From: Alex X Date: Wed, 24 Sep 2025 16:34:54 +0300 Subject: [PATCH 14/14] Update version to 1.9.10 --- main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.go b/main.go index e85c5900..0cfc31fb 100644 --- a/main.go +++ b/main.go @@ -44,7 +44,7 @@ import ( ) func main() { - app.Version = "1.9.9" + app.Version = "1.9.10" // 1. Core modules: app, api/ws, streams