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: