From 3a50b3678d132f301fe53de1be7ba8054665c4e4 Mon Sep 17 00:00:00 2001
From: Alex Cortelyou <1689668+acortelyou@users.noreply.github.com>
Date: Mon, 23 Dec 2024 23:43:39 -0800
Subject: [PATCH 1/4] Extend onvif server to support Unifi Protect
---
internal/onvif/init.go | 13 ++++++
pkg/onvif/server.go | 100 ++++++++++++++++++++++++++++++++++++-----
2 files changed, 103 insertions(+), 10 deletions(-)
diff --git a/internal/onvif/init.go b/internal/onvif/init.go
index 014c5e18..b8b4fca6 100644
--- a/internal/onvif/init.go
+++ b/internal/onvif/init.go
@@ -70,6 +70,10 @@ func onvifDeviceService(w http.ResponseWriter, r *http.Request) {
// important for Hass: Media section
res = onvif.GetCapabilitiesResponse(r.Host)
+ case onvif.ActionGetServices:
+ // important for Unifi: Media section
+ res = onvif.GetServicesResponse(r.Host)
+
case onvif.ActionGetSystemDateAndTime:
// important for Hass
res = onvif.GetSystemDateAndTimeResponse()
@@ -95,8 +99,13 @@ func onvifDeviceService(w http.ResponseWriter, r *http.Request) {
case onvif.ActionGetProfiles:
// important for Hass: H264 codec, width, height
+ // important for Unifi: framerate, bitrate, quality
res = onvif.GetProfilesResponse(streams.GetAll())
+ case onvif.ActionGetVideoSources:
+ // important for Unifi: framerate, resolution
+ res = onvif.GetVideoSourcesResponse(streams.GetAll())
+
case onvif.ActionGetStreamUri:
host, _, err := net.SplitHostPort(r.Host)
if err != nil {
@@ -107,6 +116,10 @@ func onvifDeviceService(w http.ResponseWriter, r *http.Request) {
uri := "rtsp://" + host + ":" + rtsp.Port + "/" + onvif.FindTagValue(b, "ProfileToken")
res = onvif.GetStreamUriResponse(uri)
+ case onvif.ActionGetSnapshotUri:
+ uri := "http://" + r.Host + "/api/frame.jpeg?src=" + onvif.FindTagValue(b, "ProfileToken")
+ res = onvif.GetSnapshotUriResponse(uri)
+
default:
http.Error(w, "unsupported action", http.StatusBadRequest)
log.Debug().Msgf("[onvif] unsupported request:\n%s", b)
diff --git a/pkg/onvif/server.go b/pkg/onvif/server.go
index f8f2883c..df53dfab 100644
--- a/pkg/onvif/server.go
+++ b/pkg/onvif/server.go
@@ -16,6 +16,7 @@ const (
ActionGetServiceCapabilities = "GetServiceCapabilities"
ActionGetProfiles = "GetProfiles"
ActionGetStreamUri = "GetStreamUri"
+ ActionGetSnapshotUri = "GetSnapshotUri"
ActionSystemReboot = "SystemReboot"
ActionGetServices = "GetServices"
@@ -65,6 +66,32 @@ func GetCapabilitiesResponse(host string) string {
`
}
+func GetServicesResponse(host string) string {
+ return `
+
+
+
+
+ http://www.onvif.org/ver10/device/wsdl
+ http://` + host + `/onvif/device_service
+
+ 2
+ 5
+
+
+
+ http://www.onvif.org/ver10/media/wsdl
+ http://` + host + `/onvif/media_service
+
+ 2
+ 5
+
+
+
+
+`
+}
+
func GetSystemDateAndTimeResponse() string {
loc := time.Now()
utc := loc.UTC()
@@ -142,7 +169,7 @@ func GetServiceCapabilitiesResponse() string {
-
+
@@ -171,14 +198,27 @@ func GetProfilesResponse(names []string) string {
for i, name := range names {
buf.WriteString(`
- ` + name + `
-
- H264
-
- 1920
- 1080
-
-
+ ` + name + `
+
+ ` + name + `
+ H264
+
+ 1920
+ 1080
+
+
+ 29.97003
+ 1
+ 5000
+
+ 4
+ PT1000S
+
+
+ ` + name + `
+ ` + strconv.Itoa(i) + `
+
+
`)
}
@@ -190,15 +230,55 @@ func GetProfilesResponse(names []string) string {
return buf.String()
}
+
+func GetVideoSourcesResponse(names []string) string {
+ buf := bytes.NewBuffer(nil)
+ buf.WriteString(`
+
+
+ `)
+
+ for i, _ := range names {
+ buf.WriteString(`
+
+ 29.97003
+
+ 1920
+ 1080
+
+ `)
+ }
+
+ buf.WriteString(`
+
+
+`)
+
+ return buf.String()
+}
+
func GetStreamUriResponse(uri string) string {
return `
- ` + uri + `
+ ` + uri + `
`
}
+
+func GetSnapshotUriResponse(uri string) string {
+ return `
+
+
+
+
+ ` + uri + `
+
+
+
+`
+}
From 159d9425a732eedef06a9dd797ec6a284339a1b6 Mon Sep 17 00:00:00 2001
From: Alex Cortelyou <1689668+acortelyou@users.noreply.github.com>
Date: Tue, 24 Dec 2024 11:08:18 -0800
Subject: [PATCH 2/4] Remove non-essential fields
---
pkg/onvif/server.go | 4 ----
1 file changed, 4 deletions(-)
diff --git a/pkg/onvif/server.go b/pkg/onvif/server.go
index df53dfab..e2d56556 100644
--- a/pkg/onvif/server.go
+++ b/pkg/onvif/server.go
@@ -208,11 +208,8 @@ func GetProfilesResponse(names []string) string {
29.97003
- 1
5000
- 4
- PT1000S
` + name + `
@@ -241,7 +238,6 @@ func GetVideoSourcesResponse(names []string) string {
for i, _ := range names {
buf.WriteString(`
- 29.97003
1920
1080
From b8303b9a22e1727b9a4db8979b6177f5e13dd35c Mon Sep 17 00:00:00 2001
From: Alex Cortelyou <1689668+acortelyou@users.noreply.github.com>
Date: Sun, 29 Dec 2024 16:16:49 -0800
Subject: [PATCH 3/4] Remove optional fields, normalize indentation
---
pkg/onvif/server.go | 66 ++++++++++++++++++++++-----------------------
1 file changed, 32 insertions(+), 34 deletions(-)
diff --git a/pkg/onvif/server.go b/pkg/onvif/server.go
index e2d56556..bc3f8ffe 100644
--- a/pkg/onvif/server.go
+++ b/pkg/onvif/server.go
@@ -46,23 +46,23 @@ func GetRequestAction(b []byte) string {
func GetCapabilitiesResponse(host string) string {
return `
-
-
-
-
- http://` + host + `/onvif/device_service
-
-
- http://` + host + `/onvif/media_service
-
- false
- false
- true
-
-
-
-
-
+
+
+
+
+ http://` + host + `/onvif/device_service
+
+
+ http://` + host + `/onvif/media_service
+
+ false
+ false
+ true
+
+
+
+
+
`
}
@@ -197,31 +197,29 @@ func GetProfilesResponse(names []string) string {
for i, name := range names {
buf.WriteString(`
-
- ` + name + `
-
+
+ ` + name + `
+
` + name + `
- H264
-
- 1920
+ H264
+
+ 1920
1080
-
- 29.97003
- 5000
+
-
+
` + name + `
` + strconv.Itoa(i) + `
- `)
+ `)
}
buf.WriteString(`
-
-
+
+
`)
return buf.String()
@@ -233,11 +231,11 @@ func GetVideoSourcesResponse(names []string) string {
buf.WriteString(`
- `)
+ `)
for i, _ := range names {
buf.WriteString(`
-
+
1920
1080
@@ -246,8 +244,8 @@ func GetVideoSourcesResponse(names []string) string {
}
buf.WriteString(`
-
-
+
+
`)
return buf.String()
From cf88bf9c23e7196cec60dc62644f12b2f20d8083 Mon Sep 17 00:00:00 2001
From: Alex Cortelyou <1689668+acortelyou@users.noreply.github.com>
Date: Sun, 29 Dec 2024 16:22:49 -0800
Subject: [PATCH 4/4] Remove inaccurate comments
---
internal/onvif/init.go | 3 ---
1 file changed, 3 deletions(-)
diff --git a/internal/onvif/init.go b/internal/onvif/init.go
index b8b4fca6..e5ed9a7c 100644
--- a/internal/onvif/init.go
+++ b/internal/onvif/init.go
@@ -71,7 +71,6 @@ func onvifDeviceService(w http.ResponseWriter, r *http.Request) {
res = onvif.GetCapabilitiesResponse(r.Host)
case onvif.ActionGetServices:
- // important for Unifi: Media section
res = onvif.GetServicesResponse(r.Host)
case onvif.ActionGetSystemDateAndTime:
@@ -99,11 +98,9 @@ func onvifDeviceService(w http.ResponseWriter, r *http.Request) {
case onvif.ActionGetProfiles:
// important for Hass: H264 codec, width, height
- // important for Unifi: framerate, bitrate, quality
res = onvif.GetProfilesResponse(streams.GetAll())
case onvif.ActionGetVideoSources:
- // important for Unifi: framerate, resolution
res = onvif.GetVideoSourcesResponse(streams.GetAll())
case onvif.ActionGetStreamUri: