Files
go2rtc/pkg/onvif/server.go
2025-01-03 13:19:40 +03:00

251 lines
8.9 KiB
Go

package onvif
import (
"bytes"
"regexp"
"time"
)
const ServiceGetServiceCapabilities = "GetServiceCapabilities"
const (
DeviceGetCapabilities = "GetCapabilities"
DeviceGetDeviceInformation = "GetDeviceInformation"
DeviceGetDiscoveryMode = "GetDiscoveryMode"
DeviceGetDNS = "GetDNS"
DeviceGetHostname = "GetHostname"
DeviceGetNetworkDefaultGateway = "GetNetworkDefaultGateway"
DeviceGetNetworkInterfaces = "GetNetworkInterfaces"
DeviceGetNetworkProtocols = "GetNetworkProtocols"
DeviceGetNTP = "GetNTP"
DeviceGetScopes = "GetScopes"
DeviceGetServices = "GetServices"
DeviceGetSystemDateAndTime = "GetSystemDateAndTime"
DeviceSystemReboot = "SystemReboot"
)
const (
MediaGetAudioEncoderConfigurations = "GetAudioEncoderConfigurations"
MediaGetAudioSources = "GetAudioSources"
MediaGetAudioSourceConfigurations = "GetAudioSourceConfigurations"
MediaGetProfile = "GetProfile"
MediaGetProfiles = "GetProfiles"
MediaGetSnapshotUri = "GetSnapshotUri"
MediaGetStreamUri = "GetStreamUri"
MediaGetVideoEncoderConfigurations = "GetVideoEncoderConfigurations"
MediaGetVideoSources = "GetVideoSources"
MediaGetVideoSourceConfiguration = "GetVideoSourceConfiguration"
MediaGetVideoSourceConfigurations = "GetVideoSourceConfigurations"
)
func GetRequestAction(b []byte) string {
// <soap-env:Body><ns0:GetCapabilities xmlns:ns0="http://www.onvif.org/ver10/device/wsdl">
// <v:Body><GetSystemDateAndTime xmlns="http://www.onvif.org/ver10/device/wsdl" /></v:Body>
re := regexp.MustCompile(`Body[^<]+<([^ />]+)`)
m := re.FindSubmatch(b)
if len(m) != 2 {
return ""
}
if i := bytes.IndexByte(m[1], ':'); i > 0 {
return string(m[1][i+1:])
}
return string(m[1])
}
func GetCapabilitiesResponse(host string) []byte {
e := NewEnvelope()
e.Append(`<tds:GetCapabilitiesResponse>
<tds:Capabilities>
<tt:Device>
<tt:XAddr>http://`, host, `/onvif/device_service</tt:XAddr>
</tt:Device>
<tt:Media>
<tt:XAddr>http://`, host, `/onvif/media_service</tt:XAddr>
<tt:StreamingCapabilities>
<tt:RTPMulticast>false</tt:RTPMulticast>
<tt:RTP_TCP>false</tt:RTP_TCP>
<tt:RTP_RTSP_TCP>true</tt:RTP_RTSP_TCP>
</tt:StreamingCapabilities>
</tt:Media>
</tds:Capabilities>
</tds:GetCapabilitiesResponse>`)
return e.Bytes()
}
func GetServicesResponse(host string) []byte {
e := NewEnvelope()
e.Append(`<tds:GetServicesResponse>
<tds:Service>
<tds:Namespace>http://www.onvif.org/ver10/device/wsdl</tds:Namespace>
<tds:XAddr>http://`, host, `/onvif/device_service</tds:XAddr>
<tds:Version><tt:Major>2</tt:Major><tt:Minor>5</tt:Minor></tds:Version>
</tds:Service>
<tds:Service>
<tds:Namespace>http://www.onvif.org/ver10/media/wsdl</tds:Namespace>
<tds:XAddr>http://`, host, `/onvif/media_service</tds:XAddr>
<tds:Version><tt:Major>2</tt:Major><tt:Minor>5</tt:Minor></tds:Version>
</tds:Service>
</tds:GetServicesResponse>`)
return e.Bytes()
}
func GetSystemDateAndTimeResponse() []byte {
loc := time.Now()
utc := loc.UTC()
e := NewEnvelope()
e.Appendf(`<tds:GetSystemDateAndTimeResponse>
<tds:SystemDateAndTime>
<tt:DateTimeType>NTP</tt:DateTimeType>
<tt:DaylightSavings>true</tt:DaylightSavings>
<tt:TimeZone>
<tt:TZ>%s</tt:TZ>
</tt:TimeZone>
<tt:UTCDateTime>
<tt:Time><tt:Hour>%d</tt:Hour><tt:Minute>%d</tt:Minute><tt:Second>%d</tt:Second></tt:Time>
<tt:Date><tt:Year>%d</tt:Year><tt:Month>%d</tt:Month><tt:Day>%d</tt:Day></tt:Date>
</tt:UTCDateTime>
<tt:LocalDateTime>
<tt:Time><tt:Hour>%d</tt:Hour><tt:Minute>%d</tt:Minute><tt:Second>%d</tt:Second></tt:Time>
<tt:Date><tt:Year>%d</tt:Year><tt:Month>%d</tt:Month><tt:Day>%d</tt:Day></tt:Date>
</tt:LocalDateTime>
</tds:SystemDateAndTime>
</tds:GetSystemDateAndTimeResponse>`,
GetPosixTZ(loc),
utc.Hour(), utc.Minute(), utc.Second(), utc.Year(), utc.Month(), utc.Day(),
loc.Hour(), loc.Minute(), loc.Second(), loc.Year(), loc.Month(), loc.Day(),
)
return e.Bytes()
}
func GetDeviceInformationResponse(manuf, model, firmware, serial string) []byte {
e := NewEnvelope()
e.Append(`<tds:GetDeviceInformationResponse>
<tds:Manufacturer>`, manuf, `</tds:Manufacturer>
<tds:Model>`, model, `</tds:Model>
<tds:FirmwareVersion>`, firmware, `</tds:FirmwareVersion>
<tds:SerialNumber>`, serial, `</tds:SerialNumber>
<tds:HardwareId>1.00</tds:HardwareId>
</tds:GetDeviceInformationResponse>`)
return e.Bytes()
}
func GetMediaServiceCapabilitiesResponse() []byte {
e := NewEnvelope()
e.Append(`<trt:GetServiceCapabilitiesResponse>
<trt:Capabilities SnapshotUri="true" Rotation="false" VideoSourceMode="false" OSD="false" TemporaryOSDText="false" EXICompression="false">
<trt:StreamingCapabilities RTPMulticast="false" RTP_TCP="false" RTP_RTSP_TCP="true" NonAggregateControl="false" NoRTSPStreaming="false" />
</trt:Capabilities>
</trt:GetServiceCapabilitiesResponse>`)
return e.Bytes()
}
func GetProfilesResponse(names []string) []byte {
e := NewEnvelope()
e.Append(`<trt:GetProfilesResponse>
`)
for _, name := range names {
appendProfile(e, "Profiles", name)
}
e.Append(`</trt:GetProfilesResponse>`)
return e.Bytes()
}
func GetProfileResponse(name string) []byte {
e := NewEnvelope()
e.Append(`<trt:GetProfileResponse>
`)
appendProfile(e, "Profile", name)
e.Append(`</trt:GetProfileResponse>`)
return e.Bytes()
}
func appendProfile(e *Envelope, tag, name string) {
e.Append(`<trt:`, tag, ` token="`, name, `" fixed="true">
<tt:Name>`, name, `</tt:Name>
<tt:VideoSourceConfiguration token="`, name, `">
<tt:Name>VSC</tt:Name>
<tt:SourceToken>`, name, `</tt:SourceToken>
<tt:Bounds x="0" y="0" width="1920" height="1080"></tt:Bounds>
</tt:VideoSourceConfiguration>
<tt:VideoEncoderConfiguration token="vec">
<tt:Name>VEC</tt:Name>
<tt:Encoding>H264</tt:Encoding>
<tt:Resolution><tt:Width>1920</tt:Width><tt:Height>1080</tt:Height></tt:Resolution>
</tt:VideoEncoderConfiguration>
</trt:`, tag, `>
`)
}
func GetVideoSourceConfigurationResponse(name string) []byte {
e := NewEnvelope()
e.Append(`<trt:GetVideoSourceConfigurationResponse>
<trt:Configuration token="`, name, `">
<tt:Name>VSC</tt:Name>
<tt:SourceToken>`, name, `</tt:SourceToken>
<tt:Bounds x="0" y="0" width="1920" height="1080"></tt:Bounds>
</trt:Configuration>
</trt:GetVideoSourceConfigurationResponse>`)
return e.Bytes()
}
func GetVideoSourcesResponse(names []string) []byte {
e := NewEnvelope()
e.Append(`<trt:GetVideoSourcesResponse>
`)
for _, name := range names {
e.Append(`<trt:VideoSources token="`, name, `">
<tt:Framerate>30.000000</tt:Framerate>
<tt:Resolution><tt:Width>1920</tt:Width><tt:Height>1080</tt:Height></tt:Resolution>
</trt:VideoSources>
`)
}
e.Append(`</trt:GetVideoSourcesResponse>`)
return e.Bytes()
}
func GetStreamUriResponse(uri string) []byte {
e := NewEnvelope()
e.Append(`<trt:GetStreamUriResponse><trt:MediaUri><tt:Uri>`, uri, `</tt:Uri></trt:MediaUri></trt:GetStreamUriResponse>`)
return e.Bytes()
}
func GetSnapshotUriResponse(uri string) []byte {
e := NewEnvelope()
e.Append(`<trt:GetSnapshotUriResponse><trt:MediaUri><tt:Uri>`, uri, `</tt:Uri></trt:MediaUri></trt:GetSnapshotUriResponse>`)
return e.Bytes()
}
func StaticResponse(operation string) []byte {
switch operation {
case DeviceGetSystemDateAndTime:
return GetSystemDateAndTimeResponse()
}
e := NewEnvelope()
e.Append(responses[operation])
b := e.Bytes()
if operation == DeviceGetNetworkInterfaces {
println()
}
return b
}
var responses = map[string]string{
DeviceGetDiscoveryMode: `<tds:GetDiscoveryModeResponse><tds:DiscoveryMode>Discoverable</tds:DiscoveryMode></tds:GetDiscoveryModeResponse>`,
DeviceGetDNS: `<tds:GetDNSResponse><tds:DNSInformation /></tds:GetDNSResponse>`,
DeviceGetHostname: `<tds:GetHostnameResponse><tds:HostnameInformation /></tds:GetHostnameResponse>`,
DeviceGetNetworkDefaultGateway: `<tds:GetNetworkDefaultGatewayResponse><tds:NetworkGateway /></tds:GetNetworkDefaultGatewayResponse>`,
DeviceGetNTP: `<tds:GetNTPResponse><tds:NTPInformation /></tds:GetNTPResponse>`,
DeviceSystemReboot: `<tds:SystemRebootResponse><tds:Message>OK</tds:Message></tds:SystemRebootResponse>`,
DeviceGetNetworkInterfaces: `<tds:GetNetworkInterfacesResponse />`,
DeviceGetNetworkProtocols: `<tds:GetNetworkProtocolsResponse />`,
DeviceGetScopes: `<tds:GetScopesResponse>
<tds:Scopes><tt:ScopeDef>Fixed</tt:ScopeDef><tt:ScopeItem>onvif://www.onvif.org/name/go2rtc</tt:ScopeItem></tds:Scopes>
<tds:Scopes><tt:ScopeDef>Fixed</tt:ScopeDef><tt:ScopeItem>onvif://www.onvif.org/location/github</tt:ScopeItem></tds:Scopes>
<tds:Scopes><tt:ScopeDef>Fixed</tt:ScopeDef><tt:ScopeItem>onvif://www.onvif.org/Profile/Streaming</tt:ScopeItem></tds:Scopes>
<tds:Scopes><tt:ScopeDef>Fixed</tt:ScopeDef><tt:ScopeItem>onvif://www.onvif.org/type/Network_Video_Transmitter</tt:ScopeItem></tds:Scopes>
</tds:GetScopesResponse>`,
}