Compare commits

...

22 Commits

Author SHA1 Message Date
Cedric Verstraeten
b67a72ba9a [release] v3.1.8 2024-01-30 13:26:44 +01:00
Cedric Verstraeten
8fc9bc264d feature: add camera friendly name to UI 2024-01-30 11:21:58 +01:00
Cedric Verstraeten
b2589f498d hot-fix: embed friendly name in recording when set 2024-01-30 10:56:31 +01:00
Cedric Verstraeten
b1ff5134f2 feature: add double encryption
we are now encrypting to Kerberos Hub by default, secondary encryption can be added through bring your own encryption keys.

all encryption can be turned on/off if required
2024-01-17 20:53:42 +01:00
Cedric Verstraeten
3551d02d50 feature: add ability to force TURN server 2024-01-17 09:44:24 +01:00
Cedric Verstraeten
4c413012a4 [release] v3.1.7 2024-01-16 13:02:41 +01:00
Cedric Verstraeten
74ea2f6cdd hot-fix: make sure webrtc candidates are assigned to the correct session 2024-01-16 12:55:31 +01:00
Cedric Verstraeten
2a7d9b62d4 warning: printing the work sub url 2024-01-16 10:49:40 +01:00
Cedric Verstraeten
21d81b94dd [release] v3.1.6 2024-01-16 09:47:07 +01:00
Cedric Verstraeten
091662ff26 hot-fix: support avigilon backchannel 2024-01-16 09:39:34 +01:00
Cedric Verstraeten
803e8f55ef correct webrtc audio buffer duration 2024-01-14 21:37:58 +01:00
Cedric Verstraeten
14d38ecf08 [release] v3.1.5 2024-01-12 15:28:48 +01:00
Cedric Verstraeten
34d945055b Update main.go 2024-01-12 11:49:44 +01:00
Cedric Verstraeten
8c44da8233 hide passwords in ui + skip empty decode frames 2024-01-12 11:47:08 +01:00
Cédric Verstraeten
a8b79947ef Update README.md 2024-01-12 09:53:38 +01:00
Cedric Verstraeten
7c653f809d upgrqde dependencies + move file (decap) 2024-01-11 23:05:46 +01:00
Cedric Verstraeten
49f1603f40 align more blocking methods 2024-01-11 22:43:16 +01:00
Cedric Verstraeten
b4369ea932 improve non-blocking approve for agents tend to restart for some strange reason 2024-01-11 22:35:56 +01:00
Cedric Verstraeten
83ba7baa4b [release] v3.1.4
- hot-fix: preserve width and height of both main and sub stream
2024-01-10 17:06:49 +01:00
Cedric Verstraeten
9339ae30fd [release] v3.1.3 2024-01-10 16:30:20 +01:00
Cedric Verstraeten
c18f2bd445 remove file logger 2024-01-10 16:29:37 +01:00
Cedric Verstraeten
319876bbb0 hot-fix: onvif pull message might be empty 2024-01-10 16:28:40 +01:00
30 changed files with 351 additions and 137 deletions

View File

@@ -30,7 +30,7 @@ Kerberos Agent is an isolated and scalable video (surveillance) management agent
- An IP camera which supports a RTSP H264 or H265 encoded stream,
- (or) a USB camera, Raspberry Pi camera or other camera, that [you can transform to a valid RTSP H264 or H265 stream](https://github.com/kerberos-io/camera-to-rtsp).
- Any hardware (ARMv6, ARMv7, ARM64, AMD) that can run a binary or container, for example: a Raspberry Pi, NVidia Jetson, Intel NUC, a VM, Bare metal machine or a full blown Kubernetes cluster.
- Any hardware (ARMv6, ARMv7, ARM64, AMD64) that can run a binary or container, for example: a Raspberry Pi, NVidia Jetson, Intel NUC, a VM, Bare metal machine or a full blown Kubernetes cluster.
## :video_camera: Is my camera working?
@@ -109,7 +109,7 @@ This repository contains everything you'll need to know about our core product,
- Low memory and CPU usage.
- Simplified and modern user interface.
- Multi architecture (ARMv7, ARMv8, amd64, etc).).
- Multi architecture (ARMv6, ARMv7, ARM64, AMD64)
- Multi stream, for example recording in H265, live streaming and motion detection in H264.
- Multi camera support: IP Cameras (H264 and H265), USB cameras and Raspberry Pi Cameras [through a RTSP proxy](https://github.com/kerberos-io/camera-to-rtsp).
- Single camera per instance (e.g. one container per camera).
@@ -222,6 +222,7 @@ Next to attaching the configuration file, it is also possible to override the co
| `AGENT_MQTT_USERNAME` | Username of the MQTT broker. | "" |
| `AGENT_MQTT_PASSWORD` | Password of the MQTT broker. | "" |
| `AGENT_STUN_URI` | When using WebRTC, you'll need to provide a STUN server. | "stun:turn.kerberos.io:8443" |
| `AGENT_FORCE_TURN` | Force using a TURN server, by generating relay candidates only. | "false" |
| `AGENT_TURN_URI` | When using WebRTC, you'll need to provide a TURN server. | "turn:turn.kerberos.io:8443" |
| `AGENT_TURN_USERNAME` | TURN username used for WebRTC. | "username1" |
| `AGENT_TURN_PASSWORD` | TURN password used for WebRTC. | "password1" |

View File

@@ -103,6 +103,7 @@
"mqtt_username": "",
"mqtt_password": "",
"stunuri": "stun:turn.kerberos.io:8443",
"turn_force": "false",
"turnuri": "turn:turn.kerberos.io:8443",
"turn_username": "username1",
"turn_password": "password1",

View File

@@ -9,8 +9,8 @@ go 1.20
require (
github.com/InVisionApp/conjungo v1.1.0
github.com/appleboy/gin-jwt/v2 v2.9.1
github.com/bluenviron/gortsplib/v4 v4.6.3
github.com/bluenviron/mediacommon v1.7.0
github.com/bluenviron/gortsplib/v4 v4.7.1
github.com/bluenviron/mediacommon v1.7.1
github.com/cedricve/go-onvif v0.0.0-20200222191200-567e8ce298f6
github.com/dropbox/dropbox-sdk-go-unofficial/v6 v6.0.5
github.com/eclipse/paho.mqtt.golang v1.4.3
@@ -36,9 +36,9 @@ require (
github.com/swaggo/swag v1.16.2
github.com/tevino/abool v1.2.0
github.com/yapingcat/gomedia v0.0.0-20240106100545-1b855b02fa0d
github.com/zaf/g711 v0.0.0-20240103222607-9fe83013ade9
github.com/zaf/g711 v1.4.0
go.mongodb.org/mongo-driver v1.13.1
gopkg.in/DataDog/dd-trace-go.v1 v1.58.1
gopkg.in/DataDog/dd-trace-go.v1 v1.59.0
gopkg.in/natefinch/lumberjack.v2 v2.2.1
)
@@ -71,7 +71,7 @@ require (
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-openapi/jsonpointer v0.20.2 // indirect
github.com/go-openapi/jsonreference v0.20.4 // indirect
github.com/go-openapi/spec v0.20.13 // indirect
github.com/go-openapi/spec v0.20.14 // indirect
github.com/go-openapi/swag v0.22.7 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
@@ -105,7 +105,7 @@ require (
github.com/philhofer/fwd v1.1.2 // indirect
github.com/pion/datachannel v1.5.5 // indirect
github.com/pion/dtls/v2 v2.2.9 // indirect
github.com/pion/ice/v2 v2.3.11 // indirect
github.com/pion/ice/v2 v2.3.12 // indirect
github.com/pion/interceptor v0.1.25 // indirect
github.com/pion/logging v0.2.2 // indirect
github.com/pion/mdns v0.0.9 // indirect
@@ -136,10 +136,10 @@ require (
go4.org/intern v0.0.0-20230525184215-6c62f75575cb // indirect
go4.org/unsafe/assume-no-moving-gc v0.0.0-20231121144256-b99613f794b6 // indirect
golang.org/x/arch v0.7.0 // indirect
golang.org/x/crypto v0.17.0 // indirect
golang.org/x/crypto v0.18.0 // indirect
golang.org/x/mod v0.14.0 // indirect
golang.org/x/net v0.19.0 // indirect
golang.org/x/oauth2 v0.15.0 // indirect
golang.org/x/net v0.20.0 // indirect
golang.org/x/oauth2 v0.16.0 // indirect
golang.org/x/sync v0.6.0 // indirect
golang.org/x/sys v0.16.0 // indirect
golang.org/x/text v0.14.0 // indirect

View File

@@ -64,10 +64,10 @@ github.com/appleboy/gofight/v2 v2.1.2 h1:VOy3jow4vIK8BRQJoC/I9muxyYlJ2yb9ht2hZoS
github.com/appleboy/gofight/v2 v2.1.2/go.mod h1:frW+U1QZEdDgixycTj4CygQ48yLTUhplt43+Wczp3rw=
github.com/beevik/etree v1.3.0 h1:hQTc+pylzIKDb23yYprodCWWTt+ojFfUZyzU09a/hmU=
github.com/beevik/etree v1.3.0/go.mod h1:aiPf89g/1k3AShMVAzriilpcE4R/Vuor90y83zVZWFc=
github.com/bluenviron/gortsplib/v4 v4.6.3 h1:/FgUhxe/DGFkmwHNGNnw7NhcuZeSwnxCzYHDbyAtMjo=
github.com/bluenviron/gortsplib/v4 v4.6.3/go.mod h1:UqdkRR5YvKHP/wHEQQySJFKJm6tIZcftdP7cNszIZ1g=
github.com/bluenviron/mediacommon v1.7.0 h1:1j+mSw+oHDG6zXjv/tE8xxWR3G8yheMxqx76k9wJ0dE=
github.com/bluenviron/mediacommon v1.7.0/go.mod h1:Ij/kE1LEucSjryNBVTyPL/gBI0d6/Css3f5PyrM957w=
github.com/bluenviron/gortsplib/v4 v4.7.1 h1:ZiPHjnIsdPDfPGZgfBr2n2xCFZlvmc/5zEqdoJUa1vU=
github.com/bluenviron/gortsplib/v4 v4.7.1/go.mod h1:3+IYh85PgIPLHr4D5z7GnRvpu/ogSHMDhsYW/CjrD8E=
github.com/bluenviron/mediacommon v1.7.1 h1:7Lm2b8M9gUk3Ben1w+OPwadAeYseIBscwgdiL+aLtfw=
github.com/bluenviron/mediacommon v1.7.1/go.mod h1:Ij/kE1LEucSjryNBVTyPL/gBI0d6/Css3f5PyrM957w=
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM=
github.com/bytedance/sonic v1.10.2 h1:GQebETVBxYB7JGWJtLBi07OVzWwt+8dWA00gEVW2ZFE=
@@ -151,8 +151,8 @@ github.com/go-openapi/jsonpointer v0.20.2 h1:mQc3nmndL8ZBzStEo3JYF8wzmeWffDH4VbX
github.com/go-openapi/jsonpointer v0.20.2/go.mod h1:bHen+N0u1KEO3YlmqOjTT9Adn1RfD91Ar825/PuiRVs=
github.com/go-openapi/jsonreference v0.20.4 h1:bKlDxQxQJgwpUSgOENiMPzCTBVuc7vTdXSSgNeAhojU=
github.com/go-openapi/jsonreference v0.20.4/go.mod h1:5pZJyJP2MnYCpoeoMAql78cCHauHj0V9Lhc506VOpw4=
github.com/go-openapi/spec v0.20.13 h1:XJDIN+dLH6vqXgafnl5SUIMnzaChQ6QTo0/UPMbkIaE=
github.com/go-openapi/spec v0.20.13/go.mod h1:8EOhTpBoFiask8rrgwbLC3zmJfz4zsCUueRuPM6GNkw=
github.com/go-openapi/spec v0.20.14 h1:7CBlRnw+mtjFGlPDRZmAMnq35cRzI91xj03HVyUi/Do=
github.com/go-openapi/spec v0.20.14/go.mod h1:8EOhTpBoFiask8rrgwbLC3zmJfz4zsCUueRuPM6GNkw=
github.com/go-openapi/swag v0.22.7 h1:JWrc1uc/P9cSomxfnsFSVWoE1FW6bNbrVPmpQYpCcR8=
github.com/go-openapi/swag v0.22.7/go.mod h1:Gl91UqO+btAM0plGGxHqJcQZ1ZTy6jbmridBTsDy8A0=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
@@ -356,8 +356,9 @@ github.com/pion/datachannel v1.5.5/go.mod h1:iMz+lECmfdCMqFRhXhcA/219B0SQlbpoR2V
github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s=
github.com/pion/dtls/v2 v2.2.9 h1:K+D/aVf9/REahQvqk6G5JavdrD8W1PWDKC11UlwN7ts=
github.com/pion/dtls/v2 v2.2.9/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s=
github.com/pion/ice/v2 v2.3.11 h1:rZjVmUwyT55cmN8ySMpL7rsS8KYsJERsrxJLLxpKhdw=
github.com/pion/ice/v2 v2.3.11/go.mod h1:hPcLC3kxMa+JGRzMHqQzjoSj3xtE9F+eoncmXLlCL4E=
github.com/pion/ice/v2 v2.3.12 h1:NWKW2b3+oSZS3klbQMIEWQ0i52Kuo0KBg505a5kQv4s=
github.com/pion/ice/v2 v2.3.12/go.mod h1:hPcLC3kxMa+JGRzMHqQzjoSj3xtE9F+eoncmXLlCL4E=
github.com/pion/interceptor v0.1.25 h1:pwY9r7P6ToQ3+IF0bajN0xmk/fNw/suTgaTdlwTDmhc=
github.com/pion/interceptor v0.1.25/go.mod h1:wkbPYAak5zKsfpVDYMtEfWEy8D4zL+rpxCxPImLOg3Y=
github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY=
@@ -481,8 +482,8 @@ github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/zaf/g711 v0.0.0-20240103222607-9fe83013ade9 h1:Fm9BWdkpn+ABEQJJlWjYvKQMhbuOuPGpXLlQDApD0mg=
github.com/zaf/g711 v0.0.0-20240103222607-9fe83013ade9/go.mod h1:eCDXt3dSp/kYYAoooba7ukD/Q75jvAaS4WOMr0l1Roo=
github.com/zaf/g711 v1.4.0 h1:XZYkjjiAg9QTBnHqEg37m2I9q3IIDv5JRYXs2N8ma7c=
github.com/zaf/g711 v1.4.0/go.mod h1:eCDXt3dSp/kYYAoooba7ukD/Q75jvAaS4WOMr0l1Roo=
github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs=
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
go.mongodb.org/mongo-driver v1.13.1 h1:YIc7HTYsKndGK4RFzJ3covLz1byri52x0IoMB0Pt/vk=
@@ -522,8 +523,8 @@ golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45
golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -605,16 +606,16 @@ golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ=
golang.org/x/net v0.13.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.15.0 h1:s8pnnxNVzjWyrvYdFUQq5llS1PX2zhPXmccZv99h7uQ=
golang.org/x/oauth2 v0.15.0/go.mod h1:q48ptWNTY5XWf+JNten23lcvHpLJ0ZSxF5ttTHKVCAM=
golang.org/x/oauth2 v0.16.0 h1:aDkGMBSYxElaoP81NpoUoz2oo2R2wHdZpGToUxfyQrQ=
golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -862,8 +863,8 @@ google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/DataDog/dd-trace-go.v1 v1.58.1 h1:zhVNyN5V9G7LVuDh44q3wkcbQwtjIsmmUCieayojNYo=
gopkg.in/DataDog/dd-trace-go.v1 v1.58.1/go.mod h1:SmnEjjV9ZQr4MWRSUYEpoPyNtmtRK5J6UuJdAma+Yxw=
gopkg.in/DataDog/dd-trace-go.v1 v1.59.0 h1:W1Bfpc5+m6UdQeZDJg7GczerO2m9KmDw93yGOefRU2c=
gopkg.in/DataDog/dd-trace-go.v1 v1.59.0/go.mod h1:7zSfmC8eQQ/37+e5ID+gBX7v+MUa+1XgN6HzxLNF0mo=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

View File

@@ -25,7 +25,6 @@ import (
"github.com/bluenviron/gortsplib/v4/pkg/format/rtph265"
"github.com/bluenviron/gortsplib/v4/pkg/format/rtplpcm"
"github.com/bluenviron/gortsplib/v4/pkg/format/rtpmpeg4audio"
"github.com/bluenviron/gortsplib/v4/pkg/format/rtpsimpleaudio"
"github.com/bluenviron/mediacommon/pkg/codecs/h264"
"github.com/bluenviron/mediacommon/pkg/codecs/h265"
"github.com/bluenviron/mediacommon/pkg/codecs/mpeg4audio"
@@ -63,7 +62,7 @@ type Golibrtsp struct {
AudioG711Index int8
AudioG711Media *description.Media
AudioG711Forma *format.G711
AudioG711Decoder *rtpsimpleaudio.Decoder
AudioG711Decoder *rtplpcm.Decoder
HasBackChannel bool
AudioG711IndexBackChannel int8
@@ -497,10 +496,18 @@ func (g *Golibrtsp) Start(ctx context.Context, streamType string, queue *packets
if errSPS == nil {
// Get width
g.Streams[g.VideoH264Index].Width = sps.Width()
configuration.Config.Capture.IPCamera.Width = sps.Width()
if streamType == "main" {
configuration.Config.Capture.IPCamera.Width = sps.Width()
} else if streamType == "sub" {
configuration.Config.Capture.IPCamera.SubWidth = sps.Width()
}
// Get height
g.Streams[g.VideoH264Index].Height = sps.Height()
configuration.Config.Capture.IPCamera.Height = sps.Height()
if streamType == "main" {
configuration.Config.Capture.IPCamera.Height = sps.Height()
} else if streamType == "sub" {
configuration.Config.Capture.IPCamera.SubHeight = sps.Height()
}
// Get FPS
g.Streams[g.VideoH264Index].FPS = sps.FPS()
g.VideoH264Forma.SPS = nalu

View File

@@ -71,6 +71,10 @@ func HandleRecordStream(queue *packets.Queue, configDirectory string, configurat
startRecording := now
timestamp := now
if config.FriendlyName != "" {
config.Name = config.FriendlyName
}
// For continuous and motion based recording we will use a single file.
var file *os.File
@@ -619,7 +623,9 @@ func Base64Image(captureDevice *Capture, communication *models.Communication) st
// We'll try to have a keyframe, if not we'll return an empty string.
var encodedImage string
for {
// Try for 3 times in a row.
count := 0
for count < 3 {
if queue != nil && cursor != nil && rtspClient != nil {
pkt, err := cursor.ReadPacket()
if err == nil {
@@ -632,8 +638,10 @@ func Base64Image(captureDevice *Capture, communication *models.Communication) st
bytes, _ := utils.ImageToBytes(&img)
encodedImage = base64.StdEncoding.EncodeToString(bytes)
break
} else {
count++
continue
}
break
}
} else {
break
@@ -660,15 +668,22 @@ func JpegImage(captureDevice *Capture, communication *models.Communication) imag
// We'll try to have a keyframe, if not we'll return an empty string.
var image image.YCbCr
for {
// Try for 3 times in a row.
count := 0
for count < 3 {
if queue != nil && cursor != nil && rtspClient != nil {
pkt, err := cursor.ReadPacket()
if err == nil {
if !pkt.IsKeyFrame {
continue
}
image, _ = (*rtspClient).DecodePacket(pkt)
break
image, err = (*rtspClient).DecodePacket(pkt)
if err != nil {
count++
continue
} else {
break
}
}
} else {
break

View File

@@ -395,6 +395,16 @@ loop:
hasBackChannel = "true"
}
hub_encryption := "false"
if config.HubEncryption == "true" {
hub_encryption = "true"
}
e2e_encryption := "false"
if config.Encryption != nil && config.Encryption.Enabled == "true" {
e2e_encryption = "true"
}
// We will formated the uptime to a human readable format
// this will be used on Kerberos Hub: Uptime -> 1 day and 2 hours.
uptimeFormatted := uptimeStart.Format("2006-01-02 15:04:05")
@@ -411,6 +421,8 @@ loop:
var object = fmt.Sprintf(`{
"key" : "%s",
"hub_encryption": "%s",
"e2e_encryption": "%s",
"version" : "3.0.0",
"release" : "%s",
"cpuid" : "%s",
@@ -447,12 +459,11 @@ loop:
"docker" : true,
"kios" : false,
"raspberrypi" : false
}`, config.Key, system.Version, system.CPUId, username, key, name, isEnterprise, system.Hostname, system.Architecture, system.TotalMemory, system.UsedMemory, system.FreeMemory, system.ProcessUsedMemory, macs, ips, "0", "0", "0", uptimeString, boottimeString, config.HubSite, onvifEnabled, onvifZoom, onvifPanTilt, onvifPresets, onvifPresetsList, onvifEventsList, cameraConnected, hasBackChannel)
}`, config.Key, hub_encryption, e2e_encryption, system.Version, system.CPUId, username, key, name, isEnterprise, system.Hostname, system.Architecture, system.TotalMemory, system.UsedMemory, system.FreeMemory, system.ProcessUsedMemory, macs, ips, "0", "0", "0", uptimeString, boottimeString, config.HubSite, onvifEnabled, onvifZoom, onvifPanTilt, onvifPresets, onvifPresetsList, onvifEventsList, cameraConnected, hasBackChannel)
// Get the private key to encrypt the data using symmetric encryption: AES.
HubEncryption := config.HubEncryption
privateKey := config.HubPrivateKey
if HubEncryption == "true" && privateKey != "" {
if hub_encryption == "true" && privateKey != "" {
// Encrypt the data using AES.
encrypted, err := encryption.AesEncrypt([]byte(object), privateKey)
if err != nil {

View File

@@ -188,7 +188,7 @@ func RunAgent(configDirectory string, configuration *models.Configuration, commu
time.Sleep(time.Second * 3)
return status
}
log.Log.Info("components.Kerberos.RunAgent(): opened RTSP sub stream: " + rtspUrl)
log.Log.Info("components.Kerberos.RunAgent(): opened RTSP sub stream: " + subRtspUrl)
// Get the video streams from the RTSP server.
videoSubStreams, err = rtspSubClient.GetVideoStreams()
@@ -206,42 +206,8 @@ func RunAgent(configDirectory string, configuration *models.Configuration, commu
height := videoSubStream.Height
// Set config values as well
configuration.Config.Capture.IPCamera.Width = width
configuration.Config.Capture.IPCamera.Height = height
}
if cameraSettings.RTSP != rtspUrl ||
cameraSettings.SubRTSP != subRtspUrl ||
cameraSettings.Width != width ||
cameraSettings.Height != height {
// TODO: this condition is used to reset the decoder when the camera settings change.
// The main idea is that you only set the decoder once, and then reuse it on each restart (no new memory allocation).
// However the stream settings of the camera might have been changed, and so the decoder might need to be reloaded.
// .... Not used for the moment ....
if cameraSettings.RTSP != "" && cameraSettings.SubRTSP != "" && cameraSettings.Initialized {
//decoder.Close()
//if subStreamEnabled {
// subDecoder.Close()
//}
}
// At some routines we will need to decode the image.
// Make sure its properly locked as we only have a single decoder.
log.Log.Info("components.Kerberos.RunAgent(): camera settings changed, reloading decoder")
//capture.GetVideoDecoder(decoder, streams)
//if subStreamEnabled {
// capture.GetVideoDecoder(subDecoder, subStreams)
//}
cameraSettings.RTSP = rtspUrl
cameraSettings.SubRTSP = subRtspUrl
cameraSettings.Width = width
cameraSettings.Height = height
cameraSettings.Initialized = true
} else {
log.Log.Info("components.Kerberos.RunAgent(): camera settings did not change, keeping decoder")
configuration.Config.Capture.IPCamera.SubWidth = width
configuration.Config.Capture.IPCamera.SubHeight = height
}
// We are creating a queue to store the RTSP frames in, these frames will be
@@ -348,9 +314,20 @@ func RunAgent(configDirectory string, configuration *models.Configuration, commu
// Here we are cleaning up everything!
if configuration.Config.Offline != "true" {
communication.HandleUpload <- "stop"
select {
case communication.HandleUpload <- "stop":
log.Log.Info("components.Kerberos.RunAgent(): stopping upload")
case <-time.After(1 * time.Second):
log.Log.Info("components.Kerberos.RunAgent(): stopping upload timed out")
}
}
select {
case communication.HandleStream <- "stop":
log.Log.Info("components.Kerberos.RunAgent(): stopping stream")
case <-time.After(1 * time.Second):
log.Log.Info("components.Kerberos.RunAgent(): stopping stream timed out")
}
communication.HandleStream <- "stop"
// We use the steam channel to stop both main and sub stream.
//if subStreamEnabled {
// communication.HandleSubStream <- "stop"
@@ -442,8 +419,12 @@ func ControlAgent(communication *models.Communication) {
// After 15 seconds without activity this is thrown..
if occurence == 3 {
log.Log.Info("components.Kerberos.ControlAgent(): Restarting machinery because of blocking mainstream.")
communication.HandleBootstrap <- "restart"
time.Sleep(2 * time.Second)
select {
case communication.HandleBootstrap <- "restart":
log.Log.Info("components.Kerberos.ControlAgent(): Restarting machinery because of blocking substream.")
case <-time.After(1 * time.Second):
log.Log.Info("components.Kerberos.ControlAgent(): Restarting machinery because of blocking substream timed out")
}
occurence = 0
}
@@ -464,9 +445,12 @@ func ControlAgent(communication *models.Communication) {
// After 15 seconds without activity this is thrown..
if occurenceSub == 3 {
log.Log.Info("components.Kerberos.ControlAgent(): Restarting machinery because of blocking substream.")
communication.HandleBootstrap <- "restart"
time.Sleep(2 * time.Second)
select {
case communication.HandleBootstrap <- "restart":
log.Log.Info("components.Kerberos.ControlAgent(): Restarting machinery because of blocking substream.")
case <-time.After(1 * time.Second):
log.Log.Info("components.Kerberos.ControlAgent(): Restarting machinery because of blocking substream timed out")
}
occurenceSub = 0
}
}
@@ -603,7 +587,12 @@ func GetDays(c *gin.Context, configDirectory string, configuration *models.Confi
// @Success 200 {object} models.APIResponse
func StopAgent(c *gin.Context, communication *models.Communication) {
log.Log.Info("components.Kerberos.StopAgent(): sending signal to stop agent, this will os.Exit(0).")
communication.HandleBootstrap <- "stop"
select {
case communication.HandleBootstrap <- "stop":
log.Log.Info("components.Kerberos.StopAgent(): Stopping machinery.")
case <-time.After(1 * time.Second):
log.Log.Info("components.Kerberos.StopAgent(): Stopping machinery timed out")
}
c.JSON(200, gin.H{
"stopped": true,
})
@@ -618,7 +607,12 @@ func StopAgent(c *gin.Context, communication *models.Communication) {
// @Success 200 {object} models.APIResponse
func RestartAgent(c *gin.Context, communication *models.Communication) {
log.Log.Info("components.Kerberos.RestartAgent(): sending signal to restart agent.")
communication.HandleBootstrap <- "restart"
select {
case communication.HandleBootstrap <- "restart":
log.Log.Info("components.Kerberos.RestartAgent(): Restarting machinery.")
case <-time.After(1 * time.Second):
log.Log.Info("components.Kerberos.RestartAgent(): Restarting machinery timed out")
}
c.JSON(200, gin.H{
"restarted": true,
})

View File

@@ -386,6 +386,9 @@ func OverrideWithEnvironmentVariables(configuration *models.Configuration) {
case "AGENT_STUN_URI":
configuration.Config.STUNURI = value
break
case "AGENT_FORCE_TURN":
configuration.Config.ForceTurn = value
break
case "AGENT_TURN_URI":
configuration.Config.TURNURI = value
break
@@ -485,7 +488,9 @@ func SaveConfig(configDirectory string, config models.Config, configuration *mod
if communication.CameraConnected {
select {
case communication.HandleBootstrap <- "restart":
default:
log.Log.Info("config.main.SaveConfig(): update config, restart agent.")
case <-time.After(1 * time.Second):
log.Log.Info("config.main.SaveConfig(): update config, restart agent.")
}
}

View File

@@ -76,7 +76,6 @@ func ConfigureLogrus(level string, output string, timezone *time.Location) {
logLevel = logrus.ErrorLevel
} else if level == "debug" {
logLevel = logrus.DebugLevel
logrus.SetReportCaller(true)
} else if level == "fatal" {
logLevel = logrus.FatalLevel
} else if level == "warning" {

View File

@@ -33,6 +33,7 @@ type Config struct {
MQTTUsername string `json:"mqtt_username" bson:"mqtt_username"`
MQTTPassword string `json:"mqtt_password" bson:"mqtt_password"`
STUNURI string `json:"stunuri" bson:"stunuri"`
ForceTurn string `json:"turn_force" bson:"turn_force"`
TURNURI string `json:"turnuri" bson:"turnuri"`
TURNUsername string `json:"turn_username" bson:"turn_username"`
TURNPassword string `json:"turn_password" bson:"turn_password"`
@@ -72,11 +73,14 @@ type Capture struct {
// IPCamera configuration, such as the RTSP url of the IPCamera and the FPS.
// Also includes ONVIF integration
type IPCamera struct {
RTSP string `json:"rtsp"`
Width int `json:"width"`
Height int `json:"height"`
FPS string `json:"fps"`
RTSP string `json:"rtsp"`
SubRTSP string `json:"sub_rtsp"`
SubWidth int `json:"sub_width"`
SubHeight int `json:"sub_height"`
SubFPS string `json:"sub_fps"`
ONVIF string `json:"onvif,omitempty" bson:"onvif"`
ONVIFXAddr string `json:"onvif_xaddr" bson:"onvif_xaddr"`
ONVIFUsername string `json:"onvif_username" bson:"onvif_username"`

View File

@@ -27,31 +27,13 @@ func PackageMQTTMessage(configuration *Configuration, msg Message) ([]byte, erro
msg.DeviceId = msg.Payload.DeviceId
msg.Timestamp = time.Now().Unix()
// We'll hide the message (by default in latest version)
// We will encrypt using the Kerberos Hub private key if set.
/*msg.Hidden = false
if configuration.Config.HubPrivateKey != "" {
msg.Hidden = true
pload := msg.Payload
// Pload to base64
data, err := json.Marshal(pload)
if err != nil {
msg.Hidden = false
} else {
k := configuration.Config.Encryption.SymmetricKey
encryptedValue, err := encryption.AesEncrypt(data, k)
if err == nil {
data := base64.StdEncoding.EncodeToString(encryptedValue)
msg.Payload.HiddenValue = data
msg.Payload.Value = make(map[string]interface{})
}
}
}*/
// Configuration
config := configuration.Config
// Next to hiding the message, we can also encrypt it using your own private key.
// Which is not stored in a remote environment (hence you are the only one owning it).
msg.Encrypted = false
if configuration.Config.Encryption != nil && configuration.Config.Encryption.Enabled == "true" {
if config.Encryption != nil && config.Encryption.Enabled == "true" {
msg.Encrypted = true
}
msg.PublicKey = ""
@@ -85,19 +67,47 @@ func PackageMQTTMessage(configuration *Configuration, msg Message) ([]byte, erro
rsaKey, _ := key.(*rsa.PrivateKey)
// Create a 16bit key random
k := configuration.Config.Encryption.SymmetricKey
if config.Encryption != nil && config.Encryption.SymmetricKey != "" {
k := config.Encryption.SymmetricKey
encryptedValue, err := encryption.AesEncrypt(data, k)
if err == nil {
data := base64.StdEncoding.EncodeToString(encryptedValue)
// Sign the encrypted value
signature, err := encryption.SignWithPrivateKey([]byte(data), rsaKey)
if err == nil {
base64Signature := base64.StdEncoding.EncodeToString(signature)
msg.Payload.EncryptedValue = data
msg.Payload.Signature = base64Signature
msg.Payload.Value = make(map[string]interface{})
}
}
}
}
}
// We'll hide the message (by default in latest version)
// We will encrypt using the Kerberos Hub private key if set.
msg.Hidden = false
if config.HubEncryption == "true" && config.HubPrivateKey != "" {
msg.Hidden = true
}
if msg.Hidden {
pload := msg.Payload
// Pload to base64
data, err := json.Marshal(pload)
if err != nil {
msg.Hidden = false
} else {
k := config.HubPrivateKey
encryptedValue, err := encryption.AesEncrypt(data, k)
if err == nil {
data := base64.StdEncoding.EncodeToString(encryptedValue)
// Sign the encrypted value
signature, err := encryption.SignWithPrivateKey([]byte(data), rsaKey)
if err == nil {
base64Signature := base64.StdEncoding.EncodeToString(signature)
msg.Payload.EncryptedValue = data
msg.Payload.Signature = base64Signature
msg.Payload.Value = make(map[string]interface{})
}
msg.Payload.HiddenValue = data
msg.Payload.EncryptedValue = ""
msg.Payload.Signature = ""
msg.Payload.Value = make(map[string]interface{})
}
}
}

View File

@@ -1104,7 +1104,9 @@ func GetEventMessages(dev *onvif.Device, pullPointAddress string) ([]ONVIFEvents
for _, message := range pullMessagesResponse.NotificationMessage {
log.Log.Debug("onvif.main.GetEventMessages(pullMessages): " + string(message.Topic.TopicKinds))
log.Log.Debug("onvif.main.GetEventMessages(pullMessages): " + string(message.Message.Message.Data.SimpleItem[0].Name) + " " + string(message.Message.Message.Data.SimpleItem[0].Value))
if len(message.Message.Message.Data.SimpleItem) > 0 {
log.Log.Debug("onvif.main.GetEventMessages(pullMessages): " + string(message.Message.Message.Data.SimpleItem[0].Name) + " " + string(message.Message.Message.Data.SimpleItem[0].Value))
}
if message.Topic.TopicKinds == "tns1:Device/Trigger/Relay" {
if len(message.Message.Message.Data.SimpleItem) > 0 {
if message.Message.Message.Data.SimpleItem[0].Name == "LogicalState" {

View File

@@ -166,9 +166,33 @@ func MQTTListenerHandler(mqttClient mqtt.Client, hubKey string, configDirectory
// We will receive all messages from our hub, so we'll need to filter to the relevant device.
if message.Mid != "" && message.Timestamp != 0 && message.DeviceId == configuration.Config.Key {
// Messages might be encrypted, if so we'll
// need to decrypt them.
var payload models.Payload
// Messages might be hidden, if so we'll need to decrypt them using the Kerberos Hub private key.
if message.Hidden && configuration.Config.HubEncryption == "true" {
hiddenValue := message.Payload.HiddenValue
if len(hiddenValue) > 0 {
privateKey := configuration.Config.HubPrivateKey
if privateKey != "" {
data, err := base64.StdEncoding.DecodeString(hiddenValue)
if err != nil {
return
}
visibleValue, err := encryption.AesDecrypt(data, privateKey)
if err != nil {
log.Log.Error("routers.mqtt.main.MQTTListenerHandler(): error decrypting message: " + err.Error())
return
}
json.Unmarshal(visibleValue, &payload)
message.Payload = payload
} else {
log.Log.Error("routers.mqtt.main.MQTTListenerHandler(): error decrypting message, no private key provided.")
}
}
}
// Messages might be end-to-end encrypted, if so we'll need to decrypt them,
// using our own keys.
if message.Encrypted && configuration.Config.Encryption != nil && configuration.Config.Encryption.Enabled == "true" {
encryptedValue := message.Payload.EncryptedValue
if len(encryptedValue) > 0 {
@@ -352,16 +376,26 @@ func HandleRequestConfig(mqttClient mqtt.Client, hubKey string, payload models.P
json.Unmarshal(jsonData, &configPayload)
if configPayload.Timestamp != 0 {
// Get Config from the device
// Get Config from the device
key := configuration.Config.Key
name := configuration.Config.Name
if configuration.Config.FriendlyName != "" {
name = configuration.Config.FriendlyName
}
if key != "" && name != "" {
// Copy the config, as we don't want to share the encryption part.
deepCopy := configuration.Config
// We need a fix for the width and height if a substream.
// The ROI requires the width and height of the sub stream.
if configuration.Config.Capture.IPCamera.SubRTSP != "" {
deepCopy.Capture.IPCamera.Width = configuration.Config.Capture.IPCamera.SubWidth
deepCopy.Capture.IPCamera.Height = configuration.Config.Capture.IPCamera.SubHeight
}
var configMap map[string]interface{}
inrec, _ := json.Marshal(deepCopy)
json.Unmarshal(inrec, &configMap)

View File

@@ -161,6 +161,8 @@ logreader:
if err == nil {
bytes, _ := utils.ImageToBytes(&img)
encodedImage = base64.StdEncoding.EncodeToString(bytes)
} else {
continue
}
} else {
log.Log.Error("routers.websocket.main.ForwardSDStream():" + err.Error())

View File

@@ -135,6 +135,11 @@ func InitializeWebRTCConnection(configuration *models.Configuration, communicati
api := pionWebRTC.NewAPI(pionWebRTC.WithMediaEngine(mediaEngine))
policy := pionWebRTC.ICETransportPolicyAll
if config.ForceTurn == "true" {
policy = pionWebRTC.ICETransportPolicyRelay
}
peerConnection, err := api.NewPeerConnection(
pionWebRTC.Configuration{
ICEServers: []pionWebRTC.ICEServer{
@@ -147,7 +152,7 @@ func InitializeWebRTCConnection(configuration *models.Configuration, communicati
Credential: w.TurnServersCredential,
},
},
//ICETransportPolicy: pionWebRTC.ICETransportPolicyRelay, // This will force a relay server, we might make this configurable.
ICETransportPolicy: policy,
},
)
@@ -222,6 +227,8 @@ func InitializeWebRTCConnection(configuration *models.Configuration, communicati
candateBinary, err := json.Marshal(candateJSON)
if err == nil {
valueMap["candidate"] = string(candateBinary)
valueMap["sdp"] = []byte(base64.StdEncoding.EncodeToString([]byte(answer.SDP)))
valueMap["session_id"] = handshake.SessionID
} else {
log.Log.Info("webrtc.main.InitializeWebRTCConnection(): something went wrong while marshalling candidate: " + err.Error())
}
@@ -250,6 +257,7 @@ func InitializeWebRTCConnection(configuration *models.Configuration, communicati
// Create a config map
valueMap := make(map[string]interface{})
valueMap["sdp"] = []byte(base64.StdEncoding.EncodeToString([]byte(answer.SDP)))
valueMap["session_id"] = handshake.SessionID
log.Log.Info("webrtc.main.InitializeWebRTCConnection(): Send SDP answer")
// We'll send the candidate to the hub
@@ -326,7 +334,8 @@ func WriteToTrack(livestreamCursor *packets.QueueCursor, configuration *models.C
var cursorError error
var pkt packets.Packet
var previousTime time.Duration
var previousTimeVideo time.Duration
var previousTimeAudio time.Duration
start := false
receivedKeyFrame := false
@@ -336,8 +345,6 @@ func WriteToTrack(livestreamCursor *packets.QueueCursor, configuration *models.C
for cursorError == nil {
pkt, cursorError = livestreamCursor.ReadPacket()
bufferDuration := pkt.Time - previousTime
previousTime = pkt.Time
if config.Capture.ForwardWebRTC != "true" && peerConnectionCount == 0 {
start = false
@@ -385,6 +392,11 @@ func WriteToTrack(livestreamCursor *packets.QueueCursor, configuration *models.C
//}
if pkt.IsVideo {
// Calculate the difference
bufferDuration := pkt.Time - previousTimeVideo
previousTimeVideo = pkt.Time
// Start at the first keyframe
if pkt.IsKeyFrame {
start = true
@@ -401,8 +413,13 @@ func WriteToTrack(livestreamCursor *packets.QueueCursor, configuration *models.C
}
}
} else if pkt.IsAudio {
// Calculate the difference
bufferDuration := pkt.Time - previousTimeAudio
previousTimeAudio = pkt.Time
// We will send the audio
sample := pionMedia.Sample{Data: pkt.Data, Duration: pkt.Time}
sample := pionMedia.Sample{Data: pkt.Data, Duration: bufferDuration}
if err := audioTrack.WriteSample(sample); err != nil && err != io.ErrClosedPipe {
log.Log.Error("webrtc.main.WriteToTrack(): something went wrong while writing sample: " + err.Error())
}

View File

@@ -80,6 +80,7 @@
"description_general": "Allgemeine Einstellungen für den Kerberos Agent",
"key": "Schlüssel",
"camera_name": "Kamera Name",
"camera_friendly_name": "Kamera Anzeigename",
"timezone": "Zeitzone",
"select_timezone": "Zeitzone auswählen",
"advanced_configuration": "Erweiterte Konfiguration",
@@ -145,6 +146,8 @@
"turn_server": "TURN Server",
"turn_username": "Benutzername",
"turn_password": "Passwort",
"force_turn": "Erzwinge TURN",
"force_turn_description": "Erzwinge die Verwendung von TURN",
"stun_turn_forward": "Weiterleiten und transkodieren",
"stun_turn_description_forward": "Optiemierungen und Verbesserungen der TURN/STUN Kommunikation.",
"stun_turn_webrtc": "Weiterleiten an WebRTC Schnittstelle",
@@ -185,6 +188,8 @@
"description_persistence": "Die möglichkeit zur Speicherung der Daten an einem Zentralen Ort ist der Beginn einer effektiven Videoüberwachung. Es kann zwischen",
"description2_persistence": ", oder einem Drittanbieter gewählt werden.",
"select_persistence": "Speicherort auswählen",
"kerberoshub_encryption": "Encryption",
"kerberoshub_encryption_description": "All traffic from/to Kerberos Hub will encrypted using AES-256.",
"kerberoshub_proxyurl": "Kerberos Hub Proxy URL",
"kerberoshub_description_proxyurl": "Der Proxy Endpunkt zum hochladen der Aufnahmen.",
"kerberoshub_apiurl": "Kerberos Hub API URL",

View File

@@ -80,6 +80,7 @@
"description_general": "General settings for your Kerberos Agent",
"key": "Key",
"camera_name": "Camera name",
"camera_friendly_name": "Friendly name",
"timezone": "Timezone",
"select_timezone": "Select a timezone",
"advanced_configuration": "Advanced configuration",
@@ -145,6 +146,8 @@
"turn_server": "TURN server",
"turn_username": "Username",
"turn_password": "Password",
"force_turn": "Force TURN",
"force_turn_description": "Force TURN usage, even when STUN is available.",
"stun_turn_forward": "Forwarding and transcoding",
"stun_turn_description_forward": "Optimisations and enhancements for TURN/STUN communication.",
"stun_turn_webrtc": "Forwarding to WebRTC broker",
@@ -185,6 +188,8 @@
"description_persistence": "Having the ability to store your recordings is the beginning of everything. You can choose between our",
"description2_persistence": ", or a 3rd party provider",
"select_persistence": "Select a persistence",
"kerberoshub_encryption": "Encryption",
"kerberoshub_encryption_description": "All traffic from/to Kerberos Hub will encrypted using AES-256.",
"kerberoshub_proxyurl": "Kerberos Hub Proxy URL",
"kerberoshub_description_proxyurl": "The Proxy endpoint for uploading your recordings.",
"kerberoshub_apiurl": "Kerberos Hub API URL",

View File

@@ -80,6 +80,7 @@
"description_general": "General settings for your Kerberos Agent",
"key": "Key",
"camera_name": "Camera name",
"camera_friendly_name": "Camera friendly name",
"timezone": "Timezone",
"select_timezone": "Select a timezone",
"advanced_configuration": "Advanced configuration",
@@ -145,6 +146,8 @@
"turn_server": "TURN server",
"turn_username": "Username",
"turn_password": "Password",
"force_turn": "Force TURN",
"force_turn_description": "Force TURN usage, even when STUN is available.",
"stun_turn_forward": "Forwarding and transcoding",
"stun_turn_description_forward": "Optimisations and enhancements for TURN/STUN communication.",
"stun_turn_webrtc": "Forwarding to WebRTC broker",
@@ -185,6 +188,8 @@
"description_persistence": "Having the ability to store your recordings is the beginning of everything. You can choose between our",
"description2_persistence": ", or a 3rd party provider",
"select_persistence": "Select a persistence",
"kerberoshub_encryption": "Encryption",
"kerberoshub_encryption_description": "All traffic from/to Kerberos Hub will encrypted using AES-256.",
"kerberoshub_proxyurl": "Kerberos Hub Proxy URL",
"kerberoshub_description_proxyurl": "The Proxy endpoint for uploading your recordings.",
"kerberoshub_apiurl": "Kerberos Hub API URL",

View File

@@ -79,6 +79,7 @@
"description_general": "Paramètres généraux pour votre Agent Kerberos",
"key": "Clé",
"camera_name": "Nom de la caméra",
"camera_friendly_name": "Nom convivial de la caméra",
"timezone": "Fuseau horaire",
"select_timezone": "Sélectionner un fuseau horaire",
"advanced_configuration": "Configuration avancée",
@@ -144,6 +145,8 @@
"turn_server": "Serveur TURN",
"turn_username": "Nom d'utilisateur",
"turn_password": "Mot de passe",
"force_turn": "Forcer l'utilisation de TURN",
"force_turn_description": "Forcer l'utilisation de TURN au lieu de STUN",
"stun_turn_forward": "Redirection et transcodage",
"stun_turn_description_forward": "Optimisations et améliorations pour la communication TURN/STUN.",
"stun_turn_webrtc": "Redirection pour l'agent WebRTC",
@@ -184,6 +187,8 @@
"description_persistence": "Avoir la possibilité de stocker vos enregistrements est le commencement de tout. Vous pouvez choisir entre notre",
"description2_persistence": " ou auprès d'un fournisseur tiers",
"select_persistence": "Sélectionner une persistance",
"kerberoshub_encryption": "Encryption",
"kerberoshub_encryption_description": "All traffic from/to Kerberos Hub will encrypted using AES-256.",
"kerberoshub_proxyurl": "URL du proxy Kerberos Hub",
"kerberoshub_description_proxyurl": "Le point de terminaison du proxy pour téléverser vos enregistrements.",
"kerberoshub_apiurl": "URL de l'API Kerberos Hub",

View File

@@ -80,6 +80,7 @@
"description_general": "आपके Kerberos एजेंट के लिए सामान्य सेटिंग्स",
"key": "की",
"camera_name": "कैमरे का नाम",
"camera_friendly_name": "कैमरे का नाम",
"timezone": "समय क्षेत्र",
"select_timezone": "समयक्षेत्र चुनें",
"advanced_configuration": "एडवांस कॉन्फ़िगरेशन",
@@ -145,6 +146,8 @@
"turn_server": "TURN server",
"turn_username": "उपयोगकर्ता नाम",
"turn_password": "पासवर्ड",
"force_turn": "Force TURN",
"force_turn_description": "Force TURN usage, even when STUN is available.",
"stun_turn_forward": "फोरवर्डींग और ट्रांसकोडिंग",
"stun_turn_description_forward": "TURN/STUN संचार के लिए अनुकूलन और संवर्द्धन।",
"stun_turn_webrtc": "WebRTC ब्रोकर को फोरवर्डींग किया जा रहा है",
@@ -185,6 +188,8 @@
"description_persistence": "अपनी रिकॉर्डिंग संग्रहीत करने की क्षमता होना हर चीज़ की शुरुआत है। ",
"description2_persistence": ", या कोई तृतीय पक्ष प्रदाता",
"select_persistence": "एक दृढ़ता का चयन करें",
"kerberoshub_encryption": "Encryption",
"kerberoshub_encryption_description": "All traffic from/to Kerberos Hub will encrypted using AES-256.",
"kerberoshub_proxyurl": "Kerberos हब प्रॉक्सी URL",
"kerberoshub_description_proxyurl": "आपकी रिकॉर्डिंग अपलोड करने के लिए प्रॉक्सी एंडपॉइंट।",
"kerberoshub_apiurl": "Kerberos हब API URL",

View File

@@ -80,6 +80,7 @@
"description_general": "Impostazioni generali del Kerberos Agent",
"key": "Chiave",
"camera_name": "Nome videocamera",
"camera_friendly_name": "Nome amichevole videocamera",
"timezone": "Fuso orario",
"select_timezone": "Seleziona un fuso orario",
"advanced_configuration": "Configurazione avanzata",
@@ -145,6 +146,8 @@
"turn_server": "TURN server",
"turn_username": "Username",
"turn_password": "Password",
"force_turn": "Forza TURN",
"force_turn_description": "Forza l'uso di TURN per lo streaming in diretta.",
"stun_turn_forward": "Inoltro e transcodifica",
"stun_turn_description_forward": "Ottimizzazioni e miglioramenti per la comunicazione TURN/STUN.",
"stun_turn_webrtc": "Inoltro al broker WebRTC",
@@ -185,6 +188,8 @@
"description_persistence": "La possibilità di poter salvare le tue registrazioni rappresenta l'inizio di tutto. Puoi scegliere tra il nostro",
"description2_persistence": ", oppure un provider di terze parti",
"select_persistence": "Seleziona una persistenza",
"kerberoshub_encryption": "Encryption",
"kerberoshub_encryption_description": "All traffic from/to Kerberos Hub will encrypted using AES-256.",
"kerberoshub_proxyurl": "URL Proxy Kerberos Hub",
"kerberoshub_description_proxyurl": "Endpoint del Proxy per l'upload delle registrazioni.",
"kerberoshub_apiurl": "API URL Kerberos Hub",

View File

@@ -80,6 +80,7 @@
"description_general": "Kerberos エージェントの一般設定",
"key": "鍵",
"camera_name": "カメラ名",
"camera_friendly_name": "カメラのフレンドリー名",
"timezone": "タイムゾーン",
"select_timezone": "タイムゾーンを選択",
"advanced_configuration": "詳細設定",
@@ -145,6 +146,8 @@
"turn_server": "TURNサーバー",
"turn_username": "ユーザー名",
"turn_password": "パスワード",
"force_turn": "Force TURN",
"force_turn_description": "Force TURN usage, even when STUN is available.",
"stun_turn_forward": "転送とトランスコーディング",
"stun_turn_description_forward": "TURN/STUN 通信の最適化と機能強化。",
"stun_turn_webrtc": "WebRTC ブローカーへの転送",
@@ -185,6 +188,8 @@
"description_persistence": "録音を保存する機能を持つことは、すべての始まりです。",
"description2_persistence": "、またはサードパーティのプロバイダ",
"select_persistence": "永続性を選択",
"kerberoshub_encryption": "Encryption",
"kerberoshub_encryption_description": "All traffic from/to Kerberos Hub will encrypted using AES-256.",
"kerberoshub_proxyurl": "Kerberos ハブ プロキシ URL",
"kerberoshub_description_proxyurl": "記録をアップロードするためのプロキシ エンドポイント。",
"kerberoshub_apiurl": "ケルベロス ハブ API URL",

View File

@@ -80,6 +80,7 @@
"description_general": "Algemene instellingen voor jouw Kerberos Agent",
"key": "Key",
"camera_name": "Camera naam",
"camera_friendly_name": "Camera vriendelijke naam",
"timezone": "Tijdzone",
"select_timezone": "Selecteer uw tijdzone",
"advanced_configuration": "Geavanceerde instellingen",
@@ -146,6 +147,8 @@
"turn_server": "TURN server",
"turn_username": "Gebruikersnaam",
"turn_password": "Wachtwoord",
"force_turn": "Verplicht TURN",
"force_turn_description": "Verplicht TURN connectie, ook al is er een STUN connectie mogelijk.",
"stun_turn_forward": "Doorsturen en transcoden",
"stun_turn_description_forward": "Optimalisatie en verbetering voor TURN/STUN communicatie.",
"stun_turn_webrtc": "Doorsturen naar een WebRTC broker",
@@ -186,6 +189,8 @@
"description_persistence": "De mogelijkheid om jouw opnames op te slaan is het begin van alles. Je kan kiezen tussen ons",
"description2_persistence": ", of een 3rd party provider",
"select_persistence": "Selecteer een opslagmethode",
"kerberoshub_encryption": "Encryption",
"kerberoshub_encryption_description": "All traffic from/to Kerberos Hub will encrypted using AES-256.",
"kerberoshub_proxyurl": "Kerberos Hub Proxy URL",
"kerberoshub_description_proxyurl": "De Proxy url voor het opladen van jouw opnames.",
"kerberoshub_apiurl": "Kerberos Hub API URL",

View File

@@ -80,6 +80,7 @@
"description_general": "General settings for your Kerberos Agent",
"key": "Key",
"camera_name": "Camera name",
"camera_friendly_name": "Camera friendly name",
"timezone": "Timezone",
"select_timezone": "Select a timezone",
"advanced_configuration": "Advanced configuration",
@@ -145,6 +146,8 @@
"turn_server": "TURN server",
"turn_username": "Username",
"turn_password": "Password",
"force_turn": "Force TURN",
"force_turn_description": "Force TURN usage, even when STUN is available.",
"stun_turn_forward": "Forwarding and transcoding",
"stun_turn_description_forward": "Optimisations and enhancements for TURN/STUN communication.",
"stun_turn_webrtc": "Forwarding to WebRTC broker",
@@ -185,6 +188,8 @@
"description_persistence": "Having the ability to store your recordings is the beginning of everything. You can choose between our",
"description2_persistence": ", or a 3rd party provider",
"select_persistence": "Select a persistence",
"kerberoshub_encryption": "Encryption",
"kerberoshub_encryption_description": "All traffic from/to Kerberos Hub will encrypted using AES-256.",
"kerberoshub_proxyurl": "Kerberos Hub Proxy URL",
"kerberoshub_description_proxyurl": "The Proxy endpoint for uploading your recordings.",
"kerberoshub_apiurl": "Kerberos Hub API URL",

View File

@@ -80,6 +80,7 @@
"description_general": "Configurações gerais para seu agente Kerberos",
"key": "Chave",
"camera_name": "Nome da câmera",
"camera_friendly_name": "Nome amigável da câmera",
"timezone": "Fuso horário",
"select_timezone": "Selecione a timezone",
"advanced_configuration": "Configurações avançadas",
@@ -145,6 +146,8 @@
"turn_server": "Servidor TURN",
"turn_username": "Usuario",
"turn_password": "Senha",
"force_turn": "Forçar TURN",
"force_turn_description": "Forçar o uso de TURN em vez de STUN.",
"stun_turn_forward": "Encaminhamento e transcodificação",
"stun_turn_description_forward": "Otimizações e melhorias para a comunicação TURN/STUN.",
"stun_turn_webrtc": "Encaminhamento para broker WebRTC",
@@ -185,6 +188,8 @@
"description_persistence": "Ter a capacidade de armazenar suas gravações é o começo de tudo. Você pode escolher entre nossos",
"description2_persistence": ", ou um provedor terceirizado",
"select_persistence": "Selecione um provedor de armazenamento",
"kerberoshub_encryption": "Encryption",
"kerberoshub_encryption_description": "All traffic from/to Kerberos Hub will encrypted using AES-256.",
"kerberoshub_proxyurl": "Url proxy para Kerberos Hub",
"kerberoshub_description_proxyurl": "O endpoint Proxy para enviar suas gravações.",
"kerberoshub_apiurl": "Url de API do Kerberos Hub",

View File

@@ -80,6 +80,7 @@
"description_general": "Общие настройки Kerberos Agent",
"key": "Ключ",
"camera_name": "Название камеры",
"camera_friendly_name": "Дружественное название камеры",
"timezone": "Часовой пояс",
"select_timezone": "Выберите часовой пояс",
"advanced_configuration": "Расширенные настройки",
@@ -145,6 +146,8 @@
"turn_server": "TURN сервер",
"turn_username": "Имя пользователя",
"turn_password": "Пароль",
"force_turn": "Force TURN",
"force_turn_description": "Force TURN usage, even when STUN is available.",
"stun_turn_forward": "Переадресация и транскодирование",
"stun_turn_description_forward": "Оптимизация и усовершенствование связи TURN/STUN.",
"stun_turn_webrtc": "Переадресация на WebRTC-брокера",
@@ -185,6 +188,8 @@
"description_persistence": "Возможность хранения записей - это начало всего. Вы можете выбрать один из наших вариантов",
"description2_persistence": ", или стороннего провайдера",
"select_persistence": "Выберите хранилище",
"kerberoshub_encryption": "Encryption",
"kerberoshub_encryption_description": "All traffic from/to Kerberos Hub will encrypted using AES-256.",
"kerberoshub_proxyurl": "Kerberos Hub Proxy URL",
"kerberoshub_description_proxyurl": "Конечная точка Proxy для загрузки записей.",
"kerberoshub_apiurl": "Kerberos Hub API URL",

View File

@@ -80,6 +80,7 @@
"description_general": "Kerberos Agent 常规设置",
"key": "Key",
"camera_name": "相机名称",
"camera_friendly_name": "相机友好名称",
"timezone": "时区",
"select_timezone": "选择时区",
"advanced_configuration": "高级配置",
@@ -145,6 +146,8 @@
"turn_server": "TURN 服务",
"turn_username": "账户",
"turn_password": "密码",
"force_turn": "Force TURN",
"force_turn_description": "Force TURN usage, even when STUN is available.",
"stun_turn_forward": "转发和转码",
"stun_turn_description_forward": "TURN/STUN 通信的优化和增强。",
"stun_turn_webrtc": "转发到 WebRTC 代理",
@@ -185,6 +188,8 @@
"description_persistence": "能够存储您的录像是一切的开始。您可以在我们的",
"description2_persistence": ", 或第三方提供商之间进行选择。",
"select_persistence": "选择持久化存储",
"kerberoshub_encryption": "Encryption",
"kerberoshub_encryption_description": "All traffic from/to Kerberos Hub will encrypted using AES-256.",
"kerberoshub_proxyurl": "Kerberos Hub 代理 URL",
"kerberoshub_description_proxyurl": "用于上传您录像的代理端点",
"kerberoshub_apiurl": "Kerberos Hub API URL",

View File

@@ -100,7 +100,7 @@ class App extends React.Component {
</div>
)}
<div id="page-root">
<Sidebar logo={logo} title="Kerberos Agent" version="v3.1.1" mobile>
<Sidebar logo={logo} title="Kerberos Agent" version="v3.1.8" mobile>
<Profilebar
username={username}
email="support@kerberos.io"

View File

@@ -824,6 +824,15 @@ class Settings extends React.Component {
}
/>
<Input
noPadding
label={t('settings.overview.camera_friendly_name')}
defaultValue={config.friendly_name}
onChange={(value) =>
this.onUpdateField('', 'friendly_name', value, config)
}
/>
<Dropdown
isRadio
icon="world"
@@ -1088,6 +1097,20 @@ class Settings extends React.Component {
this.onUpdateField('', 'turn_password', value, config)
}
/>
<br />
<div className="toggle-wrapper">
<Toggle
on={config.turn_force === 'true'}
disabled={false}
onClick={(event) =>
this.onUpdateToggle('', 'turn_force', event, config)
}
/>
<div>
<span>{t('settings.streaming.force_turn')}</span>
<p>{t('settings.streaming.force_turn_description')}</p>
</div>
</div>
</BlockBody>
<BlockFooter>
<Button
@@ -1129,7 +1152,8 @@ class Settings extends React.Component {
}
/>
<Input
noPadding
type="password"
iconright="activity"
label={t('settings.persistence.kerberoshub_publickey')}
placeholder={t(
'settings.persistence.kerberoshub_description_publickey'
@@ -1140,7 +1164,8 @@ class Settings extends React.Component {
}
/>
<Input
noPadding
type="password"
iconright="activity"
label={t('settings.persistence.kerberoshub_privatekey')}
placeholder={t(
'settings.persistence.kerberoshub_description_privatekey'
@@ -1161,6 +1186,27 @@ class Settings extends React.Component {
this.onUpdateField('', 'hub_site', value, config)
}
/>
<br />
<div className="toggle-wrapper">
<Toggle
on={config.hub_encryption === 'true'}
disabled={false}
onClick={(event) =>
this.onUpdateToggle('', 'hub_encryption', event, config)
}
/>
<div>
<span>
{t('settings.persistence.kerberoshub_encryption')}
</span>
<p>
{t(
'settings.persistence.kerberoshub_encryption_description'
)}
</p>
</div>
</div>
</BlockBody>
<BlockFooter>
<Button
@@ -1336,7 +1382,8 @@ class Settings extends React.Component {
</div>
<Input
noPadding
type="password"
iconright="activity"
label={t('settings.overview.encryption_fingerprint')}
value={config.encryption.fingerprint}
onChange={(value) =>
@@ -1349,7 +1396,8 @@ class Settings extends React.Component {
}
/>
<Input
noPadding
type="password"
iconright="activity"
label={t('settings.overview.encryption_privatekey')}
value={config.encryption.private_key}
onChange={(value) =>
@@ -1362,7 +1410,8 @@ class Settings extends React.Component {
}
/>
<Input
noPadding
type="password"
iconright="activity"
label={t('settings.overview.encryption_symmetrickey')}
value={config.encryption.symmetric_key}
onChange={(value) =>
@@ -2296,7 +2345,8 @@ class Settings extends React.Component {
}
/>
<Input
noPadding
type="password"
iconright="activity"
label={t(
'settings.persistence.kerberosvault_accesskey'
)}
@@ -2316,7 +2366,8 @@ class Settings extends React.Component {
}
/>
<Input
noPadding
type="password"
iconright="activity"
label={t(
'settings.persistence.kerberosvault_secretkey'
)}