Merge branch 'AlexxIT:master' into onvif-client

This commit is contained in:
seydx
2025-09-26 15:09:11 +02:00
committed by GitHub
19 changed files with 249 additions and 79 deletions
+1 -1
View File
@@ -19,7 +19,7 @@ jobs:
- name: Setup Go - name: Setup Go
uses: actions/setup-go@v5 uses: actions/setup-go@v5
with: { go-version: '1.24' } with: { go-version: '1.25' }
- name: Build go2rtc_win64 - name: Build go2rtc_win64
env: { GOOS: windows, GOARCH: amd64 } env: { GOOS: windows, GOARCH: amd64 }
+9 -4
View File
@@ -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/): Download binary for your OS from [latest release](https://github.com/AlexxIT/go2rtc/releases/):
- `go2rtc_win64.zip` - Windows 10+ 64-bit - `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_win_arm64.zip` - Windows ARM 64-bit
- `go2rtc_linux_amd64` - Linux 64-bit - `go2rtc_linux_amd64` - Linux 64-bit
- `go2rtc_linux_i386` - Linux 32-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_arm` - Linux ARM 32-bit (ex. Raspberry 32-bit OS)
- `go2rtc_linux_armv6` - Linux ARMv6 (for old Raspberry 1 and Zero) - `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_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_mac_arm64.zip` - macOS ARM 64-bit
- `go2rtc_freebsd_amd64.zip` - FreeBSD 64-bit - `go2rtc_freebsd_amd64.zip` - FreeBSD 64-bit
- `go2rtc_freebsd_arm64.zip` - FreeBSD ARM 64-bit - `go2rtc_freebsd_arm64.zip` - FreeBSD ARM 64-bit
@@ -531,7 +531,7 @@ streams:
- stream quality is the same as [RTSP protocol](https://www.tapo.com/en/faq/34/) - 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! - 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 - some new camera firmwares require SHA256 instead of MD5
```yaml ```yaml
@@ -542,6 +542,10 @@ streams:
camera2: tapo://admin:UPPERCASE-MD5@192.168.1.123 camera2: tapo://admin:UPPERCASE-MD5@192.168.1.123
# admin username and UPPERCASE SHA256 cloud-password hash # admin username and UPPERCASE SHA256 cloud-password hash
camera3: tapo://admin:UPPERCASE-SHA256@192.168.1.123 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 ```bash
@@ -1384,6 +1388,7 @@ streams:
- [ioBroker.euSec](https://github.com/bropat/ioBroker.eusec) - [ioBroker](https://www.iobroker.net/) adapter for controlling Eufy security devices - [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 - [MMM-go2rtc](https://github.com/Anonym-tsk/MMM-go2rtc) - MagicMirror² module
- [ring-mqtt](https://github.com/tsightler/ring-mqtt) - Ring-to-MQTT bridge - [ring-mqtt](https://github.com/tsightler/ring-mqtt) - Ring-to-MQTT bridge
- [lightNVR](https://github.com/opensensor/lightNVR)
**Distributions** **Distributions**
@@ -1391,7 +1396,7 @@ streams:
- [Arch User Repository](https://linux-packages.com/aur/package/go2rtc) - [Arch User Repository](https://linux-packages.com/aur/package/go2rtc)
- [Gentoo](https://github.com/inode64/inode64-overlay/tree/main/media-video/go2rtc) - [Gentoo](https://github.com/inode64/inode64-overlay/tree/main/media-video/go2rtc)
- [NixOS](https://search.nixos.org/packages?query=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/) - [QNAP](https://www.myqnap.org/product/go2rtc/)
- [Synology NAS](https://synocommunity.com/package/go2rtc) - [Synology NAS](https://synocommunity.com/package/go2rtc)
- [Unraid](https://unraid.net/community/apps?q=go2rtc) - [Unraid](https://unraid.net/community/apps?q=go2rtc)
+1 -1
View File
@@ -2,7 +2,7 @@
# 0. Prepare images # 0. Prepare images
ARG PYTHON_VERSION="3.11" ARG PYTHON_VERSION="3.11"
ARG GO_VERSION="1.24" ARG GO_VERSION="1.25"
# 1. Build go2rtc binary # 1. Build go2rtc binary
+1 -1
View File
@@ -4,7 +4,7 @@
# only debian 13 (trixie) has latest ffmpeg # only debian 13 (trixie) has latest ffmpeg
# https://packages.debian.org/trixie/ffmpeg # https://packages.debian.org/trixie/ffmpeg
ARG DEBIAN_VERSION="trixie-slim" ARG DEBIAN_VERSION="trixie-slim"
ARG GO_VERSION="1.24-bookworm" ARG GO_VERSION="1.25-bookworm"
# 1. Build go2rtc binary # 1. Build go2rtc binary
+1 -1
View File
@@ -2,7 +2,7 @@
# 0. Prepare images # 0. Prepare images
ARG PYTHON_VERSION="3.13-slim-bookworm" ARG PYTHON_VERSION="3.13-slim-bookworm"
ARG GO_VERSION="1.24-bookworm" ARG GO_VERSION="1.25-bookworm"
# 1. Build go2rtc binary # 1. Build go2rtc binary
+3 -1
View File
@@ -11,6 +11,7 @@ import (
"github.com/AlexxIT/go2rtc/internal/api" "github.com/AlexxIT/go2rtc/internal/api"
"github.com/AlexxIT/go2rtc/internal/app" "github.com/AlexxIT/go2rtc/internal/app"
"github.com/AlexxIT/go2rtc/pkg/core"
"github.com/gorilla/websocket" "github.com/gorilla/websocket"
"github.com/rs/zerolog" "github.com/rs/zerolog"
) )
@@ -132,7 +133,8 @@ func apiWS(w http.ResponseWriter, r *http.Request) {
if handler := wsHandlers[msg.Type]; handler != nil { if handler := wsHandlers[msg.Type]; handler != nil {
go func() { go func() {
if err = handler(tr, msg); err != nil { if err = handler(tr, msg); err != nil {
tr.Write(&Message{Type: "error", Value: msg.Type + ": " + err.Error()}) errMsg := core.StripUserinfo(err.Error())
tr.Write(&Message{Type: "error", Value: msg.Type + ": " + errMsg})
} }
}() }()
} }
+6
View File
@@ -5,6 +5,7 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
"sync"
"github.com/AlexxIT/go2rtc/pkg/shell" "github.com/AlexxIT/go2rtc/pkg/shell"
"github.com/AlexxIT/go2rtc/pkg/yaml" "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 { func PatchConfig(path []string, value any) error {
if ConfigPath == "" { if ConfigPath == "" {
return errors.New("config file disabled") return errors.New("config file disabled")
} }
configMu.Lock()
defer configMu.Unlock()
// empty config is OK // empty config is OK
b, _ := os.ReadFile(ConfigPath) b, _ := os.ReadFile(ConfigPath)
+1 -1
View File
@@ -44,7 +44,7 @@ import (
) )
func main() { func main() {
app.Version = "1.9.9" app.Version = "1.9.10"
// 1. Core modules: app, api/ws, streams // 1. Core modules: app, api/ws, streams
+14
View File
@@ -118,3 +118,17 @@ func TestName(t *testing.T) {
// stage3 // stage3
_ = prod2.Stop() _ = 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)
}
+12
View File
@@ -2,6 +2,7 @@ package core
import ( import (
"crypto/rand" "crypto/rand"
"regexp"
"runtime" "runtime"
"strconv" "strconv"
"strings" "strings"
@@ -77,3 +78,14 @@ func Caller() string {
_, file, line, _ := runtime.Caller(1) _, file, line, _ := runtime.Caller(1)
return file + ":" + strconv.Itoa(line) 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, `://***@`)
}
+5
View File
@@ -16,6 +16,11 @@ func RepairAVCC(codec *core.Codec, handler core.HandlerFunc) core.HandlerFunc {
ps := JoinNALU(sps, pps) ps := JoinNALU(sps, pps)
return func(packet *rtp.Packet) { 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 { if NALUType(packet.Payload) == NALUTypeIFrame {
packet.Payload = Join(ps, packet.Payload) packet.Payload = Join(ps, packet.Payload)
} }
+13 -13
View File
@@ -12,7 +12,7 @@ func NewAccessory(manuf, model, name, serial, firmware string) *hap.Accessory {
hap.ServiceAccessoryInformation(manuf, model, name, serial, firmware), hap.ServiceAccessoryInformation(manuf, model, name, serial, firmware),
ServiceCameraRTPStreamManagement(), ServiceCameraRTPStreamManagement(),
//hap.ServiceHAPProtocolInformation(), //hap.ServiceHAPProtocolInformation(),
//ServiceMicrophone(), ServiceMicrophone(),
}, },
} }
acc.InitIID() acc.InitIID()
@@ -30,17 +30,17 @@ func ServiceMicrophone() *hap.Service {
Perms: hap.EVPRPW, Perms: hap.EVPRPW,
//Descr: "Mute", //Descr: "Mute",
}, },
{ //{
Type: "119", // Type: "119",
Format: hap.FormatUInt8, // Format: hap.FormatUInt8,
Value: 100, // Value: 100,
Perms: hap.EVPRPW, // Perms: hap.EVPRPW,
//Descr: "Volume", // //Descr: "Volume",
//Unit: hap.UnitPercentage, // //Unit: hap.UnitPercentage,
//MinValue: 0, // //MinValue: 0,
//MaxValue: 100, // //MaxValue: 100,
//MinStep: 1, // //MinStep: 1,
}, //},
}, },
} }
} }
@@ -62,7 +62,7 @@ func ServiceCameraRTPStreamManagement() *hap.Service {
VideoAttrs: []VideoAttrs{ VideoAttrs: []VideoAttrs{
{Width: 1920, Height: 1080, Framerate: 30}, {Width: 1920, Height: 1080, Framerate: 30},
{Width: 1280, Height: 720, Framerate: 30}, // important for iPhones {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
}, },
}, },
}, },
+6
View File
@@ -71,11 +71,17 @@ type JSONCharacter struct {
Event any `json:"ev,omitempty"` 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) { func SanitizePin(pin string) (string, error) {
s := strings.ReplaceAll(pin, "-", "") s := strings.ReplaceAll(pin, "-", "")
if len(s) != 8 { if len(s) != 8 {
return "", errors.New("hap: wrong PIN format: " + pin) return "", errors.New("hap: wrong PIN format: " + pin)
} }
if strings.Contains(insecurePINs, s) {
return "", errors.New("hap: insecure PIN: " + pin)
}
// 123-45-678 // 123-45-678
return s[:3] + "-" + s[3:5] + "-" + s[5:], nil return s[:3] + "-" + s[3:5] + "-" + s[5:], nil
} }
+86 -45
View File
@@ -46,6 +46,8 @@ func Marshal(v any) ([]byte, error) {
} }
switch kind { switch kind {
case reflect.Slice:
return appendSlice(nil, value)
case reflect.Struct: case reflect.Struct:
return appendStruct(nil, value) return appendStruct(nil, value)
} }
@@ -53,6 +55,23 @@ func Marshal(v any) ([]byte, error) {
return nil, errors.New("tlv8: not implemented: " + kind.String()) 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) { func appendStruct(b []byte, value reflect.Value) ([]byte, error) {
valueType := value.Type() valueType := value.Type()
@@ -121,7 +140,7 @@ func appendValue(b []byte, tag byte, value reflect.Value) ([]byte, error) {
case reflect.Slice: case reflect.Slice:
for i := 0; i < value.Len(); i++ { for i := 0; i < value.Len(); i++ {
if i > 0 { if i > 0 {
b = append(b, 0, 0) b = append(b, separator, 0)
} }
if b, err = appendValue(b, tag, value.Index(i)); err != nil { if b, err = appendValue(b, tag, value.Index(i)); err != nil {
return nil, err return nil, err
@@ -179,64 +198,86 @@ func Unmarshal(data []byte, v any) error {
kind = value.Kind() kind = value.Kind()
} }
if kind != reflect.Struct { switch kind {
return errors.New("tlv8: not implemented: " + kind.String()) 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 { // unmarshalTLV can return two types of errors:
var waitSlice bool // - 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]
t := b[0] l := int(b[1])
l := int(b[1])
// array item divider // array item divider (t == 0x00 || t == 0xFF)
if t == 0 && l == 0 { if l == 0 {
b = b[2:] return b[2:], errors.New("tlv8: zero item")
waitSlice = true }
continue
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 size == 255 and same tag - continue read big payload
if len(b) < 2+l { if l < 255 || len(b) < 2 || b[0] != t {
return errors.New("tlv8: wrong size: " + value.Type().Name()) 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 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 return nil
} }
+47
View File
@@ -2,6 +2,7 @@ package tlv8
import ( import (
"encoding/hex" "encoding/hex"
"strings"
"testing" "testing"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@@ -107,3 +108,49 @@ func TestInterface(t *testing.T) {
require.Equal(t, src, dst) 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)
}
+23 -4
View File
@@ -116,20 +116,39 @@ func findFmtpLine(payloadType uint8, descriptions []*sdp.MediaDescription) strin
// urlParse fix bugs: // urlParse fix bugs:
// 1. Content-Base: rtsp://::ffff:192.168.1.123/onvif/profile.1/ // 1. Content-Base: rtsp://::ffff:192.168.1.123/onvif/profile.1/
// 2. Content-Base: rtsp://rtsp://turret2-cam.lan:554/stream1/ // 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) { func urlParse(rawURL string) (*url.URL, error) {
// fix https://github.com/AlexxIT/go2rtc/issues/830 // fix https://github.com/AlexxIT/go2rtc/issues/830
if strings.HasPrefix(rawURL, "rtsp://rtsp://") { if strings.HasPrefix(rawURL, "rtsp://rtsp://") {
rawURL = rawURL[7:] rawURL = rawURL[7:]
} }
// fix https://github.com/AlexxIT/go2rtc/issues/1852
if !strings.Contains(rawURL, "://") {
rawURL = "rtsp://" + rawURL
}
u, err := url.Parse(rawURL) u, err := url.Parse(rawURL)
if err != nil && strings.HasSuffix(err.Error(), "after host") { if err != nil && strings.HasSuffix(err.Error(), "after host") {
if i1 := strings.Index(rawURL, "://"); i1 > 0 { if i := indexN(rawURL, '/', 3); i > 0 {
if i2 := strings.IndexByte(rawURL[i1+3:], '/'); i2 > 0 { return urlParse(rawURL[:i] + ":" + rawURL[i:])
return urlParse(rawURL[:i1+3+i2] + ":" + rawURL[i1+3+i2:])
}
} }
} }
return u, err 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
}
+8 -2
View File
@@ -11,14 +11,20 @@ func TestURLParse(t *testing.T) {
// https://github.com/AlexxIT/WebRTC/issues/395 // https://github.com/AlexxIT/WebRTC/issues/395
base := "rtsp://::ffff:192.168.1.123/onvif/profile.1/" base := "rtsp://::ffff:192.168.1.123/onvif/profile.1/"
u, err := urlParse(base) u, err := urlParse(base)
assert.Empty(t, err) assert.NoError(t, err)
assert.Equal(t, "::ffff:192.168.1.123:", u.Host) assert.Equal(t, "::ffff:192.168.1.123:", u.Host)
// https://github.com/AlexxIT/go2rtc/issues/208 // https://github.com/AlexxIT/go2rtc/issues/208
base = "rtsp://rtsp://turret2-cam.lan:554/stream1/" base = "rtsp://rtsp://turret2-cam.lan:554/stream1/"
u, err = urlParse(base) u, err = urlParse(base)
assert.Empty(t, err) assert.NoError(t, err)
assert.Equal(t, "turret2-cam.lan:554", u.Host) 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) { func TestBugSDP1(t *testing.T) {
+10 -3
View File
@@ -125,13 +125,20 @@ func NewServerAPI(network, address string, filters *Filters) (*webrtc.API, error
networks = append(networks, ice.NetworkType(ntype)) networks = append(networks, ice.NetworkType(ntype))
} }
udpMux, _ = ice.NewMultiUDPMuxFromPort( var err error
if udpMux, err = ice.NewMultiUDPMuxFromPort(
port, port,
ice.UDPMuxFromPortWithInterfaceFilter(interfaceFilter), ice.UDPMuxFromPortWithInterfaceFilter(interfaceFilter),
ice.UDPMuxFromPortWithIPFilter(ipFilter), ice.UDPMuxFromPortWithIPFilter(ipFilter),
ice.UDPMuxFromPortWithNetworks(networks...), ice.UDPMuxFromPortWithNetworks(networks...),
) ); err != nil {
} else if ln, err := net.ListenPacket("udp", address); 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}) udpMux = ice.NewUDPMuxDefault(ice.UDPMuxParams{UDPConn: ln})
} }
s.SetICEUDPMux(udpMux) s.SetICEUDPMux(udpMux)
+2 -2
View File
@@ -1,5 +1,7 @@
## Versions ## 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.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. 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 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 ## Build
- UPX-3.96 pack broken bin for `linux_mipsel` - UPX-3.96 pack broken bin for `linux_mipsel`