diff --git a/device.go b/device.go index c481246..9356c60 100644 --- a/device.go +++ b/device.go @@ -215,6 +215,49 @@ func (d *Device) GetSnapshotUri(profileToken string) (string, error) { return "", nil } +func (d *Device) GetVideoSources() ([]onvifmodel.VideoSource, error) { + err := d.check() + if err != nil { + return nil, err + } + resp, err := media_sdk.Call_GetVideoSources(d.ctx, d.device, media.GetVideoSources{}) + if err != nil { + return nil, err + } + return resp.VideoSources, nil +} +func (d *Device) GetVideoSourceConfigurations() ([]onvifmodel.VideoSourceConfiguration, error) { + err := d.check() + if err != nil { + return nil, err + } + resp, err := media_sdk.Call_GetVideoSourceConfigurations(d.ctx, d.device, media.GetVideoSourceConfigurations{}) + if err != nil { + return nil, err + } + return resp.Configurations, nil +} + +func (d *Device) RelateVideoSource(profileToken, videoSourceToken string) error { + err := d.check() + if err != nil { + return err + } + profileResp, err := media_sdk.Call_GetProfile(d.ctx, d.device, media.GetProfile{ProfileToken: onvifmodel.ReferenceToken(profileToken)}) + if err != nil { + return err + } + profile := profileResp.Profile + profile.VideoSourceConfiguration.SourceToken = onvifmodel.ReferenceToken(videoSourceToken) + // profile.VideoSourceConfiguration.Name = onvifmodel.Name(videoSourceToken) + _, serr := media_sdk.Call_SetVideoSourceConfiguration(d.ctx, d.device, media.SetVideoSourceConfiguration{Configuration: profile.VideoSourceConfiguration, ForcePersistence: xsd.Boolean(true)}) + if serr != nil { + return serr + } + _, aerr := media_sdk.Call_AddVideoSourceConfiguration(d.ctx, d.device, media.AddVideoSourceConfiguration{ProfileToken: onvifmodel.ReferenceToken(profileToken), ConfigurationToken: profile.VideoSourceConfiguration.Token}) + return aerr +} + func (d *Device) GetProfiles() ([]onvifmodel.Profile, error) { err := d.check() if err != nil { @@ -226,6 +269,17 @@ func (d *Device) GetProfiles() ([]onvifmodel.Profile, error) { } return resp.Profiles, nil } +func (d *Device) GetVideoEncoderConfigurations() ([]onvifmodel.VideoEncoderConfiguration, error) { + err := d.check() + if err != nil { + return nil, err + } + resp, err := media_sdk.Call_GetVideoEncoderConfigurations(d.ctx, d.device, media.GetVideoEncoderConfigurations{}) + if err != nil { + return nil, err + } + return resp.Configurations, nil +} func (d *Device) GetDeviceInformation() (interface{}, error) { err := d.check() diff --git a/device_test.go b/device_test.go index 156ba17..ce8ad19 100644 --- a/device_test.go +++ b/device_test.go @@ -5,9 +5,17 @@ import ( "testing" "time" + "os" + "git.pyer.club/kingecg/goonvif/onvif" ) +func TestMain(m *testing.M) { + os.Setenv("DEBUG", "DEBUG") + result := m.Run() + os.Unsetenv("DEBUG") + os.Exit(result) +} func TestListInterfaces(t *testing.T) { ifaces, err := listLocalNetworkInterfaces() if err != nil { @@ -114,7 +122,7 @@ func TestGetStreamUri(t *testing.T) { }, } - uri, err := d.GetStreamUriUdp("") + uri, err := d.GetStreamUriUdp("Profile_1") if err != nil { t.Errorf("Expected no error, got %v", err) return @@ -146,3 +154,77 @@ func TestZoom(t *testing.T) { t.Fatal(err) } } + +func TestGetProfiles(t *testing.T) { + d := NewDevice(onvif.DeviceParams{ + Xaddr: "192.168.12.52", + Username: "dctdev", + Password: "dacenT2017", + }) + response, err := d.GetCapabilities() + if err != nil { + t.Errorf("Expected no error, got %v", err) + } + + t.Log(response) + profiles, err := d.GetProfiles() + if err != nil { + t.Fatal(err) + } + t.Log(profiles) +} + +func TestGetVideoSource(t *testing.T) { + d := NewDevice(onvif.DeviceParams{ + Xaddr: "192.168.12.52", + Username: "dctdev", + Password: "dacenT2017", + }) + videoSource, err := d.GetVideoSources() + if err != nil { + t.Fatal(err) + } + t.Log(videoSource) //"VideoSource_1" +} + +func TestGetVideoSourceConfigurations(t *testing.T) { + d := NewDevice(onvif.DeviceParams{ + Xaddr: "192.168.12.52", + Username: "dctdev", + Password: "dacenT2017", + }) + videoSource, err := d.GetVideoSourceConfigurations() + if err != nil { + t.Fatal(err) + } + t.Log(videoSource) +} + +func TestRelateVideoSource(t *testing.T) { + d := NewDevice(onvif.DeviceParams{ + Xaddr: "192.168.12.52", + Username: "dctdev", + Password: "dacenT2017", + }) + if err := d.RelateVideoSource("Profile_1", "VideoSource_1"); err != nil { + t.Fatal(err) + } + p, err := d.GetProfiles() + if err != nil { + t.Fatal(err) + } + t.Log(p) +} + +func TestGetVideoEncoders(t *testing.T) { + d := NewDevice(onvif.DeviceParams{ + Xaddr: "192.168.12.52", + Username: "dctdev", + Password: "dacenT2017", + }) + encoders, err := d.GetVideoEncoderConfigurations() + if err != nil { + t.Fatal(err) + } + t.Log(encoders) +} diff --git a/onvif/media/types.go b/onvif/media/types.go index a3613b5..58c89db 100644 --- a/onvif/media/types.go +++ b/onvif/media/types.go @@ -43,7 +43,7 @@ type GetVideoSources struct { } type GetVideoSourcesResponse struct { - VideoSources onvif.VideoSource + VideoSources []onvif.VideoSource } type GetAudioSources struct { @@ -255,7 +255,7 @@ type GetVideoSourceConfigurations struct { } type GetVideoSourceConfigurationsResponse struct { - Configurations onvif.VideoSourceConfiguration + Configurations []onvif.VideoSourceConfiguration } type GetVideoEncoderConfigurations struct { @@ -263,7 +263,7 @@ type GetVideoEncoderConfigurations struct { } type GetVideoEncoderConfigurationsResponse struct { - Configurations onvif.VideoEncoderConfiguration + Configurations []onvif.VideoEncoderConfiguration } type GetAudioSourceConfigurations struct { diff --git a/onvif/sdk/doc.go b/onvif/sdk/doc.go index 46ba894..fe59b54 100644 --- a/onvif/sdk/doc.go +++ b/onvif/sdk/doc.go @@ -37,13 +37,16 @@ func ReadAndParse(ctx context.Context, httpReply *http.Response, reply interface return errors.Annotate(err, "read") } else { - if httpReply.StatusCode != http.StatusOK { + if httpReply.StatusCode != http.StatusOK || os.Getenv("DEBUG") == "DEBUG" { doc := etree.NewDocument() doc.ReadFromBytes(b) doc.Indent(2) xmlstr, _ := doc.WriteToString() - Logger.Error().Str("msg", xmlstr).Msg("XMLDOC") - return errors.New("unexpected status code") + if httpReply.StatusCode != http.StatusOK { + Logger.Error().Str("msg", xmlstr).Msg("XMLDOC") + return errors.New("unexpected status code") + } + } err = xml.Unmarshal(b, reply) return errors.Annotate(err, "decode") diff --git a/onvif/xsd/onvif/onvif.go b/onvif/xsd/onvif/onvif.go index 521ea84..5245387 100644 --- a/onvif/xsd/onvif/onvif.go +++ b/onvif/xsd/onvif/onvif.go @@ -346,7 +346,7 @@ type Profile struct { Fixed bool `xml:"fixed,attr"` Name Name VideoSourceConfiguration VideoSourceConfiguration - AudioSourceConfiguration AudioSourceConfiguration + AudioSourceConfiguration *AudioSourceConfiguration VideoEncoderConfiguration VideoEncoderConfiguration AudioEncoderConfiguration AudioEncoderConfiguration VideoAnalyticsConfiguration VideoAnalyticsConfiguration @@ -357,16 +357,16 @@ type Profile struct { type VideoSourceConfiguration struct { ConfigurationEntity - ViewMode string `xml:"ViewMode,attr"` - SourceToken ReferenceToken `xml:"onvif:SourceToken"` - Bounds IntRectangle `xml:"onvif:Bounds"` - Extension VideoSourceConfigurationExtension `xml:"onvif:Extension"` + ViewMode string `xml:"ViewMode,attr"` + SourceToken ReferenceToken `xml:"onvif:SourceToken"` + Bounds IntRectangle `xml:"onvif:Bounds"` + Extension *VideoSourceConfigurationExtension `xml:"onvif:Extension"` } type ConfigurationEntity struct { Token ReferenceToken `xml:"token,attr"` - Name Name `xml:"onvif:Name"` - UseCount int `xml:"onvif:UseCount"` + Name xsd.String `xml:"onvif:Name"` + UseCount xsd.Int `xml:"onvif:UseCount"` } type VideoSourceConfigurationExtension struct { diff --git a/result.xml b/result.xml index 04195e8..7fdccd7 100644 --- a/result.xml +++ b/result.xml @@ -35,19 +35,233 @@ xmlns:tr2="http://www.onvif.org/ver20/media/wsdl" xmlns:axt="http://www.onvif.org/ver20/analytics"> - - - env:Receiver - - ter:ActionNotSupported - - ter:InvalidOperation - - - - - Optional Action Not Implemented - - + + + mainStream + + VideoSource_1 + 2 + VideoSource_1 + + + + AudioSourceConfig + 2 + AudioSourceChannel + + + VideoEncoder_1 + 1 + H264 + + 1920 + 1080 + + 5.000000 + + 15 + 1 + 256 + + + 25 + Main + + + + IPv4 + 0.0.0.0 + + 8600 + 128 + false + + PT5S + + + AudioEncoderConfig + 2 + G711 + 64 + 8 + + + IPv4 + 0.0.0.0 + + 8602 + 128 + false + + PT5S + + + VideoAnalyticsName + 2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + PTZ + 2 + PTZNODETOKEN + + http://www.onvif.org/ver10/tptz/PanTiltSpaces/VelocityGenericSpace + + http://www.onvif.org/ver10/tptz/ZoomSpaces/VelocityGenericSpace + PT300S + + + + AudioOutputConfigName + 2 + AudioOutputToken + www.onvif.org/ver20/HalfDuplex/Auto + 10 + + + AudioDecoderConfig + 2 + + + + + subStream + + VideoSource_1 + 2 + VideoSource_1 + + + + AudioSourceConfig + 2 + AudioSourceChannel + + + VideoEncoder_2 + 1 + H264 + + 640 + 360 + + 3.000000 + + 18 + 1 + 128 + + + 50 + Main + + + + IPv4 + 0.0.0.0 + + 8606 + 128 + false + + PT5S + + + AudioEncoderConfig + 2 + G711 + 64 + 8 + + + IPv4 + 0.0.0.0 + + 8602 + 128 + false + + PT5S + + + VideoAnalyticsName + 2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + PTZ + 2 + PTZNODETOKEN + + http://www.onvif.org/ver10/tptz/PanTiltSpaces/VelocityGenericSpace + + http://www.onvif.org/ver10/tptz/ZoomSpaces/VelocityGenericSpace + PT300S + + + + AudioOutputConfigName + 2 + AudioOutputToken + www.onvif.org/ver20/HalfDuplex/Auto + 10 + + + AudioDecoderConfig + 2 + + + + \ No newline at end of file