Merge branch 'AlexxIT:master' into documentation-site
This commit is contained in:
@@ -11,7 +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/AlexxIT/go2rtc/pkg/creds"
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
)
|
)
|
||||||
@@ -133,7 +133,7 @@ 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 {
|
||||||
errMsg := core.StripUserinfo(err.Error())
|
errMsg := creds.SecretString(err.Error())
|
||||||
tr.Write(&Message{Type: "error", Value: msg.Type + ": " + errMsg})
|
tr.Write(&Message{Type: "error", Value: msg.Type + ": " + errMsg})
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ rtsp:
|
|||||||
Editors like [GoLand](https://www.jetbrains.com/go/) and [VS Code](https://code.visualstudio.com/) supports autocomplete and syntax validation.
|
Editors like [GoLand](https://www.jetbrains.com/go/) and [VS Code](https://code.visualstudio.com/) supports autocomplete and syntax validation.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
# yaml-language-server: $schema=https://raw.githubusercontent.com/AlexxIT/go2rtc/master/website/schema.json
|
# yaml-language-server: $schema=https://raw.githubusercontent.com/AlexxIT/go2rtc/master/www/schema.json
|
||||||
```
|
```
|
||||||
|
|
||||||
## Defaults
|
## Defaults
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ streams:
|
|||||||
"ffmpeg:" + url3 + "#video=copy"
|
"ffmpeg:" + url3 + "#video=copy"
|
||||||
```
|
```
|
||||||
|
|
||||||
## Comparsion
|
## Comparison
|
||||||
|
|
||||||
| expr | python | js |
|
| expr | python | js |
|
||||||
|------------------------------|----------------------------|--------------------------------|
|
|------------------------------|----------------------------|--------------------------------|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ You **NEED** hardware acceleration if you using `#video=h264`, `#video=h265`, `#
|
|||||||
streams:
|
streams:
|
||||||
# auto select hardware encoder
|
# auto select hardware encoder
|
||||||
camera1_hw: ffmpeg:rtsp://rtsp:12345678@192.168.1.123/av_stream/ch0#video=h264#hardware
|
camera1_hw: ffmpeg:rtsp://rtsp:12345678@192.168.1.123/av_stream/ch0#video=h264#hardware
|
||||||
|
|
||||||
# manual select hardware encoder (vaapi, cuda, v4l2m2m, dxva2, videotoolbox)
|
# manual select hardware encoder (vaapi, cuda, v4l2m2m, dxva2, videotoolbox)
|
||||||
camera1_vaapi: ffmpeg:rtsp://rtsp:12345678@192.168.1.123/av_stream/ch0#video=h264#hardware=vaapi
|
camera1_vaapi: ffmpeg:rtsp://rtsp:12345678@192.168.1.123/av_stream/ch0#video=h264#hardware=vaapi
|
||||||
```
|
```
|
||||||
@@ -47,7 +47,7 @@ Read more [here](https://en.wikipedia.org/wiki/Intel_Quick_Sync_Video#Hardware_d
|
|||||||
Linux and Docker:
|
Linux and Docker:
|
||||||
|
|
||||||
- It may be important to have the latest version of the OS with the latest version of the Linux kernel. For example, on my **Debian 10 (kernel 4.19)** it did not work, but after update to **Debian 11 (kernel 5.10)** all was fine.
|
- It may be important to have the latest version of the OS with the latest version of the Linux kernel. For example, on my **Debian 10 (kernel 4.19)** it did not work, but after update to **Debian 11 (kernel 5.10)** all was fine.
|
||||||
- In case of troube check you have `/dev/dri/` folder on your host.
|
- In case of trouble check you have `/dev/dri/` folder on your host.
|
||||||
|
|
||||||
Docker users should add `--privileged` option to container for access to Hardware.
|
Docker users should add `--privileged` option to container for access to Hardware.
|
||||||
|
|
||||||
@@ -79,7 +79,7 @@ Read more [here](https://docs.frigate.video/configuration/hardware_acceleration)
|
|||||||
|
|
||||||
**Supported on:** Linux binary, Docker, Hass Addon.
|
**Supported on:** Linux binary, Docker, Hass Addon.
|
||||||
|
|
||||||
I don't recommend using transcoding on the Raspberry Pi 3. It's extreamly slow, even with hardware acceleration. Also it may fail when transcoding 2K+ stream.
|
I don't recommend using transcoding on the Raspberry Pi 3. It's extremely slow, even with hardware acceleration. Also it may fail when transcoding 2K+ stream.
|
||||||
|
|
||||||
## Raspberry Pi 4
|
## Raspberry Pi 4
|
||||||
|
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ What you should to know about WebRTC:
|
|||||||
If an external connection via STUN is used:
|
If an external connection via STUN is used:
|
||||||
|
|
||||||
- Uses [UDP hole punching](https://en.wikipedia.org/wiki/UDP_hole_punching) technology to bypass NAT even if you not open your server to the World
|
- Uses [UDP hole punching](https://en.wikipedia.org/wiki/UDP_hole_punching) technology to bypass NAT even if you not open your server to the World
|
||||||
- For about 20% of users, the techology will not work because of the [Symmetric NAT](https://tomchen.github.io/symmetric-nat-test/)
|
- For about 20% of users, the technology will not work because of the [Symmetric NAT](https://tomchen.github.io/symmetric-nat-test/)
|
||||||
- UDP is not suitable for transmitting 2K and 4K high bitrate video over open networks because of the high loss rate:
|
- UDP is not suitable for transmitting 2K and 4K high bit rate video over open networks because of the high loss rate:
|
||||||
- https://habr.com/ru/companies/flashphoner/articles/480006/
|
- https://habr.com/ru/companies/flashphoner/articles/480006/
|
||||||
- https://www.youtube.com/watch?v=FXVg2ckuKfs
|
- https://www.youtube.com/watch?v=FXVg2ckuKfs
|
||||||
|
|
||||||
@@ -26,7 +26,7 @@ webrtc:
|
|||||||
|
|
||||||
## Config
|
## Config
|
||||||
|
|
||||||
**Important!** This example is not for copypasting!
|
**Important!** This example is not for copy pasting!
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
webrtc:
|
webrtc:
|
||||||
@@ -49,13 +49,13 @@ webrtc:
|
|||||||
credential: your_pass
|
credential: your_pass
|
||||||
|
|
||||||
# optional filter list for auto discovery logic
|
# optional filter list for auto discovery logic
|
||||||
# some settings only make sense if you don't specify a fixed UDP port
|
# some settings only make sense if you don't specify a fixed UDP port
|
||||||
filters:
|
filters:
|
||||||
# list of host candidates from auto discovery to be sent
|
# list of host candidates from auto discovery to be sent
|
||||||
# including candidates from the `listen` option
|
# including candidates from the `listen` option
|
||||||
# use `candidates: []` to remove all auto discovery candidates
|
# use `candidates: []` to remove all auto discovery candidates
|
||||||
candidates: [ 192.168.1.123 ]
|
candidates: [ 192.168.1.123 ]
|
||||||
|
|
||||||
# enable localhost candidates
|
# enable localhost candidates
|
||||||
loopback: true
|
loopback: true
|
||||||
|
|
||||||
@@ -84,7 +84,7 @@ Don't know why, but you can disable TCP port and leave only random UDP ports - `
|
|||||||
|
|
||||||
## Config filters
|
## Config filters
|
||||||
|
|
||||||
**Importan!** By default go2rtc exclude all Docker-like candidates (`172.16.0.0/12`). This can not be disabled.
|
**Important!** By default go2rtc exclude all Docker-like candidates (`172.16.0.0/12`). This can not be disabled.
|
||||||
|
|
||||||
Filters allow you to exclude unnecessary candidates. Extra candidates don't make your connection worse or better. But the wrong filter settings can break everything. Skip this setting if you don't understand it.
|
Filters allow you to exclude unnecessary candidates. Extra candidates don't make your connection worse or better. But the wrong filter settings can break everything. Skip this setting if you don't understand it.
|
||||||
|
|
||||||
@@ -106,7 +106,7 @@ webrtc:
|
|||||||
candidates: [ 192.168.1.2:8555 ] # add manual host candidate (use docker port forwarding)
|
candidates: [ 192.168.1.2:8555 ] # add manual host candidate (use docker port forwarding)
|
||||||
```
|
```
|
||||||
|
|
||||||
## Userful links
|
## Useful links
|
||||||
|
|
||||||
- https://www.ietf.org/archive/id/draft-ietf-wish-whip-01.html
|
- https://www.ietf.org/archive/id/draft-ietf-wish-whip-01.html
|
||||||
- https://www.ietf.org/id/draft-murillo-whep-01.html
|
- https://www.ietf.org/id/draft-murillo-whep-01.html
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package core
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"regexp"
|
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -93,14 +92,3 @@ 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, `://***@`)
|
|
||||||
}
|
|
||||||
|
|||||||
+30
-19
@@ -3,6 +3,7 @@ package creds
|
|||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"regexp"
|
||||||
"slices"
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
@@ -27,6 +28,7 @@ func AddSecret(value string) {
|
|||||||
var secrets []string
|
var secrets []string
|
||||||
var secretsMu sync.Mutex
|
var secretsMu sync.Mutex
|
||||||
var secretsReplacer *strings.Replacer
|
var secretsReplacer *strings.Replacer
|
||||||
|
var userinfoRegexp *regexp.Regexp
|
||||||
|
|
||||||
func getReplacer() *strings.Replacer {
|
func getReplacer() *strings.Replacer {
|
||||||
secretsMu.Lock()
|
secretsMu.Lock()
|
||||||
@@ -40,14 +42,33 @@ func getReplacer() *strings.Replacer {
|
|||||||
secretsReplacer = strings.NewReplacer(oldnew...)
|
secretsReplacer = strings.NewReplacer(oldnew...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if userinfoRegexp == nil {
|
||||||
|
userinfoRegexp = regexp.MustCompile(`://[` + userinfo + `]+@`)
|
||||||
|
}
|
||||||
|
|
||||||
return secretsReplacer
|
return secretsReplacer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Uniform Resource Identifier (URI)
|
||||||
|
// https://datatracker.ietf.org/doc/html/rfc3986
|
||||||
|
const (
|
||||||
|
unreserved = `A-Za-z0-9-._~`
|
||||||
|
subdelims = `!$&'()*+,;=`
|
||||||
|
userinfo = unreserved + subdelims + `%:`
|
||||||
|
)
|
||||||
|
|
||||||
func SecretString(s string) string {
|
func SecretString(s string) string {
|
||||||
re := getReplacer()
|
re := getReplacer()
|
||||||
|
s = userinfoRegexp.ReplaceAllString(s, `://***@`)
|
||||||
return re.Replace(s)
|
return re.Replace(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func SecretWrite(w io.Writer, s string) (n int, err error) {
|
||||||
|
re := getReplacer()
|
||||||
|
s = userinfoRegexp.ReplaceAllString(s, `://***@`)
|
||||||
|
return re.WriteString(w, s)
|
||||||
|
}
|
||||||
|
|
||||||
func SecretWriter(w io.Writer) io.Writer {
|
func SecretWriter(w io.Writer) io.Writer {
|
||||||
return &secretWriter{w}
|
return &secretWriter{w}
|
||||||
}
|
}
|
||||||
@@ -57,27 +78,17 @@ type secretWriter struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *secretWriter) Write(b []byte) (int, error) {
|
func (s *secretWriter) Write(b []byte) (int, error) {
|
||||||
re := getReplacer()
|
return SecretWrite(s.w, string(b))
|
||||||
return re.WriteString(s.w, string(b))
|
|
||||||
}
|
|
||||||
|
|
||||||
type secretResponse struct {
|
|
||||||
w http.ResponseWriter
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *secretResponse) Header() http.Header {
|
|
||||||
return s.w.Header()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *secretResponse) Write(b []byte) (int, error) {
|
|
||||||
re := getReplacer()
|
|
||||||
return re.WriteString(s.w, string(b))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *secretResponse) WriteHeader(statusCode int) {
|
|
||||||
s.w.WriteHeader(statusCode)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func SecretResponse(w http.ResponseWriter) http.ResponseWriter {
|
func SecretResponse(w http.ResponseWriter) http.ResponseWriter {
|
||||||
return &secretResponse{w}
|
return &secretResponse{w}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type secretResponse struct {
|
||||||
|
http.ResponseWriter
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *secretResponse) Write(b []byte) (int, error) {
|
||||||
|
return SecretWrite(s.ResponseWriter, string(b))
|
||||||
|
}
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ func NewClient(rawURL string) (*Client, error) {
|
|||||||
} else if model == ModelMijia || model == ModelXiaobai {
|
} else if model == ModelMijia || model == ModelXiaobai {
|
||||||
username = "admin"
|
username = "admin"
|
||||||
password = query.Get("password")
|
password = query.Get("password")
|
||||||
} else if model == ModelXiaofang {
|
} else if model == ModelDafang || model == ModelXiaofang {
|
||||||
username = "admin"
|
username = "admin"
|
||||||
} else {
|
} else {
|
||||||
return nil, fmt.Errorf("xiaomi: unsupported model: %s", model)
|
return nil, fmt.Errorf("xiaomi: unsupported model: %s", model)
|
||||||
@@ -47,7 +47,7 @@ func NewClient(rawURL string) (*Client, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if model == ModelXiaofang {
|
if model == ModelDafang || model == ModelXiaofang {
|
||||||
err = xiaofangLogin(conn, query.Get("password"))
|
err = xiaofangLogin(conn, query.Get("password"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = conn.Close()
|
_ = conn.Close()
|
||||||
@@ -196,7 +196,7 @@ func (c *Client) StartMedia(video, audio string) error {
|
|||||||
c.WriteCommandJSON(cmdVideoStart, `{}`),
|
c.WriteCommandJSON(cmdVideoStart, `{}`),
|
||||||
)
|
)
|
||||||
|
|
||||||
case ModelXiaofang:
|
case ModelDafang, ModelXiaofang:
|
||||||
// 00010000 4943414d 95010400000000000000000600000000000000d20400005a07 - 90k bitrate
|
// 00010000 4943414d 95010400000000000000000600000000000000d20400005a07 - 90k bitrate
|
||||||
// 00010000 4943414d 95010400000000000000000600000000000000d20400001e07 - 30k bitrate
|
// 00010000 4943414d 95010400000000000000000600000000000000d20400001e07 - 30k bitrate
|
||||||
//var b byte
|
//var b byte
|
||||||
@@ -258,6 +258,8 @@ const (
|
|||||||
ModelXiaofang = "isa.camera.isc5"
|
ModelXiaofang = "isa.camera.isc5"
|
||||||
// ModelMijia support miss format for new fw and legacy format for old fw
|
// ModelMijia support miss format for new fw and legacy format for old fw
|
||||||
ModelMijia = "chuangmi.camera.v2"
|
ModelMijia = "chuangmi.camera.v2"
|
||||||
|
// ModelDafang support miss format for new fw and legacy format for old fw
|
||||||
|
ModelDafang = "isa.camera.df3"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Supported(model string) bool {
|
func Supported(model string) bool {
|
||||||
|
|||||||
Reference in New Issue
Block a user