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] 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 + ` + + + +` +}