ruby_onvif_client 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +3 -0
  3. data/lib/ruby_onvif_client/action.rb +31 -0
  4. data/lib/ruby_onvif_client/client.rb +44 -0
  5. data/lib/ruby_onvif_client/device_discovery.rb +36 -0
  6. data/lib/ruby_onvif_client/device_management/get_capabilities.rb +118 -0
  7. data/lib/ruby_onvif_client/device_management/get_device_information.rb +30 -0
  8. data/lib/ruby_onvif_client/device_management/get_network_interfaces.rb +131 -0
  9. data/lib/ruby_onvif_client/device_management/get_network_protocols.rb +32 -0
  10. data/lib/ruby_onvif_client/device_management/get_system_date_and_time.rb +60 -0
  11. data/lib/ruby_onvif_client/device_management/get_users.rb +32 -0
  12. data/lib/ruby_onvif_client/device_management/set_network_interfaces.rb +83 -0
  13. data/lib/ruby_onvif_client/device_management/set_system_date_and_time.rb +48 -0
  14. data/lib/ruby_onvif_client/device_management/set_system_factory_default.rb +21 -0
  15. data/lib/ruby_onvif_client/device_management/system_reboot.rb +25 -0
  16. data/lib/ruby_onvif_client/device_management.rb +10 -0
  17. data/lib/ruby_onvif_client/media/get_audio_encoder_configuration.rb +48 -0
  18. data/lib/ruby_onvif_client/media/get_audio_encoder_configuration_options.rb +57 -0
  19. data/lib/ruby_onvif_client/media/get_audio_encoder_configurations.rb +49 -0
  20. data/lib/ruby_onvif_client/media/get_audio_source_configurations.rb +32 -0
  21. data/lib/ruby_onvif_client/media/get_stream_uri.rb +58 -0
  22. data/lib/ruby_onvif_client/media/get_video_encoder_configuration.rb +104 -0
  23. data/lib/ruby_onvif_client/media/get_video_encoder_configuration_options.rb +95 -0
  24. data/lib/ruby_onvif_client/media/get_video_source_configuration.rb +55 -0
  25. data/lib/ruby_onvif_client/media/get_video_source_configurations.rb +40 -0
  26. data/lib/ruby_onvif_client/media.rb +10 -0
  27. data/lib/ruby_onvif_client/message.rb +41 -0
  28. data/lib/ruby_onvif_client/path.rb +5 -0
  29. data/lib/ruby_onvif_client/service.rb +37 -0
  30. data/lib/ruby_onvif_client.rb +3 -0
  31. data/ruby-onvif-client.gemspec +20 -0
  32. metadata +143 -0
@@ -0,0 +1,21 @@
1
+ require_relative '../action'
2
+
3
+ module ONVIF
4
+ module DeviceManagementAction
5
+ class SetSystemFactoryDefault < Action
6
+ # default_type = 'Hard' // 'Hard', 'Soft' FactoryDefault
7
+ def run default_type, cb
8
+ message = Message.new namespaces: {:'xmlns:sch' => 'http://www.onvif.org/ver10/schema'}
9
+ message.body = ->(xml) do
10
+ xml.wsdl(:SetSystemFactoryDefault) do
11
+ xml.wsdl :FactoryDefault, default_type
12
+ end
13
+ end
14
+ send_message message do |success, result|
15
+ #????
16
+ callback cb, success, result
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,25 @@
1
+ require_relative '../action'
2
+
3
+ module ONVIF
4
+ module DeviceManagementAction
5
+ class SystemReboot < Action
6
+ def run cb
7
+ message = Message.new
8
+ message.body = ->(xml) do
9
+ xml.wsdl(:SystemReboot)
10
+ end
11
+ send_message message do |success, result|
12
+ if success
13
+ xml_doc = Nokogiri::XML(result[:content])
14
+ msg = {
15
+ msg: value(xml_doc, '//tds:Message')
16
+ }
17
+ callback cb, success, msg
18
+ else
19
+ callback cb, success, result
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,10 @@
1
+ require_relative 'service'
2
+ Dir.chdir __dir__ do
3
+ require_dir 'device_management'
4
+ end
5
+
6
+ module ONVIF
7
+ class DeviceManagement < Service
8
+ end
9
+ end
10
+
@@ -0,0 +1,48 @@
1
+ require_relative '../action'
2
+
3
+ module ONVIF
4
+ module MediaAction
5
+ class GetAudioEncoderConfiguration < Action
6
+ # c_token 的结构
7
+ # c_token //[ReferenceToken] Token of the requested audio encoder configuration.
8
+ #
9
+ def run c_token, cb
10
+ message = Message.new
11
+ message.body = ->(xml) do
12
+ xml.wsdl(:GetAudioEncoderConfiguration) do
13
+ xml.wsdl :ConfigurationToken, c_token
14
+ end
15
+ end
16
+ send_message message do |success, result|
17
+ if success
18
+ xml_doc = Nokogiri::XML(result[:content])
19
+ success_result = {
20
+ configuration: {
21
+ name: value(xml_doc, '//tt:name'),
22
+ use_count: value(xml_doc, '//tt:UseCount'),
23
+ token: attribute(xml_doc, 'token'),
24
+ encoding: value(xml_doc, '//tt:Encoding'),
25
+ bitrate: value(xml_doc, '//tt:Bitrate'),
26
+ sample_rate: value(xml_doc, '//tt:SampleRate'),
27
+ multicast: {
28
+ address: {
29
+ type: value(xml_doc, '//tt:Type'),
30
+ ipv4_address: value(xml_doc, '//tt:IPv4Address'),
31
+ ipv6_address: value(xml_doc, '//tt:IPv6Address')
32
+ },
33
+ port: value(xml_doc, "//tt:Port"),
34
+ ttl: value(xml_doc, "//tt:TTL"),
35
+ auto_start: value(xml_doc, "//tt:AutoStart")
36
+ },
37
+ session_timeout: value(xml_doc, '//tt:SessionTimeout')
38
+ }
39
+ }
40
+ callback cb, success, success_result
41
+ else
42
+ callback cb, success, result
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,57 @@
1
+ require_relative '../action'
2
+
3
+ module ONVIF
4
+ module MediaAction
5
+ class GetAudioEncoderConfigurationOptions < Action
6
+ # options 的结构
7
+ # {
8
+ # c_token: "xxxxxxx", //[ReferenceToken] Optional audio encoder configuration token that specifies an existing configuration that the options are intended for.
9
+ # p_token: "xxxxxxx" //[ReferenceToken] Optional ProfileToken that specifies an existing media profile that the options shall be compatible with.
10
+ # }
11
+ def run options, cb
12
+ message = Message.new
13
+ message.body = ->(xml) do
14
+ xml.wsdl(:GetAudioEncoderConfigurationOptions) do
15
+ xml.wsdl :ConfigurationToken, options["c_token"]
16
+ xml.wsdl :ProfileToken, options["p_token"]
17
+ end
18
+ end
19
+ send_message message do |success, result|
20
+ if success
21
+ xml_doc = Nokogiri::XML(result[:content])
22
+ node_options = []
23
+ xml_doc.xpath('//trt:Options//tt:Options').each do |node|
24
+ this_options = {encoding: value(node, 'tt:Encoding')}
25
+ bitrate = node.at_xpath("tt:BitrateList")
26
+ unless bitrate.nil?
27
+ bitrate_list = []
28
+ node.xpath('tt:BitrateList//tt:Items').each do |item|
29
+ bitrate_list << {
30
+ items: item.content
31
+ }
32
+ end
33
+ this_options["bitrate_list"] = bitrate_list
34
+ end
35
+ sample_rate = node.at_xpath("tt:SampleRateList")
36
+ unless sample_rate.nil?
37
+ sample_rate_list = []
38
+ node.xpath('tt:SampleRateList//tt:Items').each do |item|
39
+ sample_rate_list << {
40
+ items: item.content
41
+ }
42
+ end
43
+ this_options["sample_rate_list"] = sample_rate_list
44
+ end
45
+
46
+
47
+ node_options << this_options
48
+ end
49
+ callback cb, success, node_options
50
+ else
51
+ callback cb, success, result
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,49 @@
1
+ require_relative '../action'
2
+
3
+ module ONVIF
4
+ module MediaAction
5
+ class GetAudioEncoderConfigurations < Action
6
+ def run cb
7
+ message = Message.new
8
+ message.body = ->(xml) do
9
+ xml.wsdl(:GetAudioEncoderConfigurations)
10
+ end
11
+ send_message message do |success, result|
12
+ if success
13
+ xml_doc = Nokogiri::XML(result[:content])
14
+ configurations = []
15
+ xml_doc.xpath('//trt:Configurations').each do |node|
16
+ bounds = node.xpath('tt:Bounds')
17
+ multicast = node.xpath('tt:Multicast')
18
+ address = multicast.xpath('tt:Address')
19
+ configuration = {
20
+ name: value(node, 'tt:Name'),
21
+ use_count: value(node, 'tt:UseCount'),
22
+ token: attribute(node, 'token'),
23
+ encoding: value(node, 'tt:Encoding'),
24
+ bitrate: value(node, 'tt:Bitrate'),
25
+ sample_rate: value(node, 'tt:SampleRate'),
26
+
27
+ multicast: {
28
+ address: {
29
+ type: value(address, 'tt:Type'),
30
+ ipv4_address: value(address, 'tt:IPv4Address'),
31
+ ipv6_address: value(address, 'tt:IPv6Address')
32
+ },
33
+ port: value(multicast, "tt:Port"),
34
+ ttl: value(multicast, "tt:TTL"),
35
+ auto_start: value(multicast, "tt:AutoStart")
36
+ },
37
+ session_timeout: value(node, 'tt:SessionTimeout')
38
+ }
39
+ configurations << configuration
40
+ end
41
+ callback cb, success, configurations
42
+ else
43
+ callback cb, success, result
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,32 @@
1
+ require_relative '../action'
2
+
3
+ module ONVIF
4
+ module MediaAction
5
+ class GetAudioSourceConfigurations < Action
6
+ def run cb
7
+ message = Message.new
8
+ message.body = ->(xml) do
9
+ xml.wsdl(:GetAudioSourceConfigurations)
10
+ end
11
+ send_message message do |success, result|
12
+ if success
13
+ xml_doc = Nokogiri::XML(result[:content])
14
+ configurations = []
15
+ xml_doc.xpath('//trt:Configurations').each do |node|
16
+ configuration = {
17
+ name: value(node, 'tt:Name'),
18
+ use_count: value(node, 'tt:UseCount'),
19
+ token: attribute(node, 'token'),
20
+ source_token: value(xml_doc, '//tt:SourceToken')
21
+ }
22
+ configurations << configuration
23
+ end
24
+ callback cb, success, configurations
25
+ else
26
+ callback cb, success, result
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,58 @@
1
+ require_relative '../action'
2
+
3
+ module ONVIF
4
+ module MediaAction
5
+ class GetStreamUri < Action
6
+ # options 的结构
7
+ # {
8
+ # stream_setup: {
9
+ # stream: 'RTP-Unicast', //'RTP-Unicast', 'RTP-Multicast'
10
+ # transport: {
11
+ # protocol: 'UDP', //'UDP', 'TCP', 'RTSP', 'HTTP'
12
+ # tunnel:{
13
+ # protocol: 'TCP', //'UDP', 'TCP', 'RTSP', 'HTTP'
14
+ # }
15
+ # }
16
+ # }
17
+ # profile_token: "xxxxxxx" // [ReferenceToken]
18
+ # }
19
+ def run options, cb
20
+ message = Message.new namespaces: {:'xmlns:sch' => 'http://www.onvif.org/ver10/schema'}
21
+ message.body = ->(xml) do
22
+ xml.wsdl(:GetStreamUri) do
23
+ xml.wsdl(:StreamSetup) do
24
+ xml.sch :Stream, options["stream_setup"]["stream"]
25
+ xml.sch :Transport do
26
+ xml.sch :Protocol, options["stream_setup"]["transport"]["protocol"]
27
+ xml.sch :Tunnel do
28
+ tunnel = options["stream_setup"]["transport"]["tunnel"]
29
+ unless tunnel.nil?
30
+ xml.sch :Protocol,options["stream_setup"]["transport"]["tunnel"]["protocol"]
31
+ xml.sch :Tunnel,options["stream_setup"]["transport"]["tunnel"]["tunnel"]
32
+ end
33
+ end
34
+ end
35
+ end
36
+ xml.wsdl :ProfileToken, options["profile_token"]
37
+ end
38
+ end
39
+ send_message message do |success, result|
40
+ if success
41
+ xml_doc = Nokogiri::XML(result[:content])
42
+ media_uri = {
43
+ media_uri: {
44
+ uri: value(xml_doc, '//tt:Uri'),
45
+ invalid_after_connect: value(xml_doc, '//tt:InvalidAfterConnect'),
46
+ invalid_after_reboot: value(xml_doc, '//tt:InvalidAfterReboot'),
47
+ timeout: value(xml_doc, '//tt:Timeout')
48
+ }
49
+ }
50
+ callback cb, success, media_uri
51
+ else
52
+ callback cb, success, result
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,104 @@
1
+ require_relative '../action'
2
+
3
+ module ONVIF
4
+ module MediaAction
5
+ class GetVideoEncoderConfiguration < Action
6
+ # c_token 的结构 // [ReferenceToken] Token of the requested video encoder configuration.
7
+ def run c_token, cb
8
+ message = Message.new
9
+ message.body = ->(xml) do
10
+ xml.wsdl(:GetVideoEncoderConfiguration) do
11
+ xml.wsdl :ConfigurationToken, c_token
12
+ end
13
+ end
14
+ send_message message do |success, result|
15
+ if success
16
+ xml_doc = Nokogiri::XML(result[:content])
17
+ cfr = xml_doc.at_xpath("//trt:Configuration")
18
+ rcl = xml_doc.at_xpath("//tt:RateControl")
19
+ configuration = {
20
+ name: value(xml_doc, "//tt:Name"),
21
+ use_count: value(xml_doc, "//tt:UseCount"),
22
+ token: attribute(cfr,"token"),
23
+ encoding: value(xml_doc, "//tt:Encoding"),
24
+ resolution: {
25
+ width: value(_get_node(xml_doc, "//tt:Resolution"), "//tt:Width"),
26
+ height: value(_get_node(xml_doc, "//tt:Resolution"), "//tt:Height")
27
+ },
28
+ quality: value(xml_doc, "//tt:Quality"),
29
+ rateControl: {
30
+ frame_rate_limit: value(rcl, "tt:FrameRateLimit"),
31
+ encoding_interval: value(rcl, "tt:EncodingInterval"),
32
+ bitrate_limit: value(rcl, "tt:BitrateLimit")
33
+ },
34
+ mpeg4: {
35
+ gov_length: value(_get_node(xml_doc, "//tt:MPEG4"), "//tt:GovLength"),
36
+ mpeg4_profile: value(_get_node(xml_doc, "//tt:MPEG4"), "//tt:Mpeg4Profile")
37
+ },
38
+ h264: {
39
+ gov_length: value(_get_node(xml_doc, "//tt:H264"), "//tt:GovLength"),
40
+ h264_profile: value(_get_node(xml_doc, "//tt:H264"), "//tt:H264Profile")
41
+ },
42
+ multicast: {
43
+ address: {
44
+ type: value(_get_node(xml_doc, "//tt:Multicast//tt:Address"), '//tt:Type'),
45
+ ipv4_address: value(_get_node(xml_doc, "//tt:Multicast//tt:Address"), '//tt:IPv4Address'),
46
+ ipv6_address: value(_get_node(xml_doc, "//tt:Multicast//tt:Address"), '//tt:IPv6Address')
47
+ },
48
+ port: value(_get_node(xml_doc, "//tt:Multicast"), "tt:Port"),
49
+ ttl: value(_get_node(xml_doc, "//tt:Multicast"), "tt:TTL"),
50
+ auto_start: value(_get_node(xml_doc, "//tt:Multicast"), "tt:AutoStart")
51
+ },
52
+ session_timeout: value(xml_doc, "//tt:SessionTimeout")
53
+ }
54
+
55
+ callback cb, success, configuration
56
+ else
57
+ callback cb, success, result
58
+ end
59
+ end
60
+ end
61
+ def _get_profiles_supported xml_doc, parent_name
62
+ this_node = xml_doc.at_xpath(parent_name)
63
+ result_val = []
64
+ this_node.each do |node|
65
+ result_val << node.content
66
+ end
67
+ return result_val
68
+ end
69
+ def _get_node parent_node, node_name
70
+ parent_node.at_xpath(node_name)
71
+ end
72
+
73
+ def _get_each_val xml_doc, parent_name
74
+ result_val = []
75
+ xml_doc.each do |node|
76
+ result_val << _get_width_height(node, parent_name)
77
+ end
78
+ return result_val
79
+ end
80
+
81
+ def _get_min_max xml_doc, parent_name
82
+ this_node = xml_doc
83
+ unless parent_name.nil?
84
+ this_node = xml_doc.at_xpath(parent_name)
85
+ end
86
+ return {
87
+ min: value(this_node, "tt:Min"),
88
+ max: value(this_node, "tt:Max")
89
+ }
90
+ end
91
+
92
+ def _get_width_height xml_doc, parent_name
93
+ this_node = xml_doc
94
+ unless parent_name.nil?
95
+ this_node = xml_doc.at_xpath(parent_name)
96
+ end
97
+ return {
98
+ width: value(this_node, "tt:Width"),
99
+ height: value(this_node, "tt:Height")
100
+ }
101
+ end
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,95 @@
1
+ require_relative '../action'
2
+
3
+ module ONVIF
4
+ module MediaAction
5
+ class GetVideoEncoderConfigurationOptions < Action
6
+ # options 的结构
7
+ # {
8
+ # c_token: "xxxxxxx", //[ReferenceToken] Optional audio encoder configuration token that specifies an existing configuration that the options are intended for.
9
+ # p_token: "xxxxxxx" //[ReferenceToken] Optional ProfileToken that specifies an existing media profile that the options shall be compatible with.
10
+ # }
11
+ def run options, cb
12
+ message = Message.new
13
+ message.body = ->(xml) do
14
+ xml.wsdl(:GetVideoEncoderConfigurationOptions) do
15
+ xml.wsdl :ConfigurationToken, options["c_token"]
16
+ xml.wsdl :ProfileToken, options["p_token"]
17
+ end
18
+ end
19
+ send_message message do |success, result|
20
+ if success
21
+ xml_doc = Nokogiri::XML(result[:content])
22
+ options = {
23
+ quality_range: _get_min_max(_get_node(xml_doc, "//tt:QualityRange")),
24
+ jpeg: {
25
+ resolutions_available: _get_each_val(_get_node(xml_doc, "//tt:JPEG"), "//tt:ResolutionsAvailable"),
26
+ frame_rate_range: _get_min_max(_get_node(xml_doc, "//tt:JPEG"), "//tt:FrameRateRange"),
27
+ rncoding_interval_range: _get_min_max(_get_node(xml_doc, "//tt:JPEG"), "//tt:FrameRateRange")
28
+ },
29
+ mpeg4: {
30
+ resolutions_available: _get_each_val(_get_node(xml_doc, "//tt:MPEG4"), "//tt:ResolutionsAvailable"),
31
+ gov_length_range: _get_min_max(_get_node(xml_doc, "//tt:MPEG4"), "//tt:GovLengthRange"),
32
+ frame_rate_range: _get_min_max(_get_node(xml_doc, "//tt:MPEG4"), "//tt:FrameRateRange"),
33
+ rncoding_interval_range: _get_min_max(_get_node(xml_doc, "//tt:MPEG4"), "//tt:EncodingIntervalRange"),
34
+ mpeg4_profiles_supported: _get_profiles_supported(_get_node(xml_doc, "//tt:MPEG4"), "//tt:Mpeg4ProfilesSupported")
35
+ },
36
+ h264: {
37
+ resolutions_available: _get_each_val(_get_node(xml_doc, "//tt:h264"), "//tt:ResolutionsAvailable"),
38
+ gov_length_range: _get_min_max(_get_node(xml_doc, "//tt:h264"), "//tt:GovLengthRange"),
39
+ frame_rate_range: _get_min_max(_get_node(xml_doc, "//tt:h264"), "//tt:FrameRateRange"),
40
+ rncoding_interval_range: _get_min_max(_get_node(xml_doc, "//tt:h264"), "//tt:EncodingIntervalRange"),
41
+ h264_profiles_supported: _get_profiles_supported(_get_node(xml_doc, "//tt:h264"), "//tt:H264ProfilesSupported")
42
+ },
43
+ extension: ""
44
+ }
45
+
46
+ callback cb, success, options
47
+ else
48
+ callback cb, success, result
49
+ end
50
+ end
51
+ end
52
+ def _get_profiles_supported xml_doc, parent_name
53
+ this_node = xml_doc.at_xpath(parent_name)
54
+ result_val = []
55
+ this_node.each do |node|
56
+ result_val << node.content
57
+ end
58
+ return result_val
59
+ end
60
+ def _get_node parent_node, node_name
61
+ parent_node.at_xpath(node_name)
62
+ end
63
+
64
+ def _get_each_val xml_doc, parent_name
65
+ result_val = []
66
+ xml_doc.each do |node|
67
+ result_val << _get_width_height(node, parent_name)
68
+ end
69
+ return result_val
70
+ end
71
+
72
+ def _get_min_max xml_doc, parent_name
73
+ this_node = xml_doc
74
+ unless parent_name.nil?
75
+ this_node = xml_doc.at_xpath(parent_name)
76
+ end
77
+ return {
78
+ min: value(this_node, "tt:Min"),
79
+ max: value(this_node, "tt:Max")
80
+ }
81
+ end
82
+
83
+ def _get_width_height xml_doc, parent_name
84
+ this_node = xml_doc
85
+ unless parent_name.nil?
86
+ this_node = xml_doc.at_xpath(parent_name)
87
+ end
88
+ return {
89
+ width: value(this_node, "tt:Width"),
90
+ height: value(this_node, "tt:Height")
91
+ }
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,55 @@
1
+ require_relative '../action'
2
+
3
+ module ONVIF
4
+ module MediaAction
5
+ class GetVideoSourceConfiguration < Action
6
+ # c_token 的结构
7
+ # c_token //[ReferenceToken] Token of the requested audio encoder configuration.
8
+ #
9
+ def run c_token, cb
10
+ message = Message.new
11
+ message.body = ->(xml) do
12
+ xml.wsdl(:GetVideoSourceConfiguration) do
13
+ xml.wsdl :ConfigurationToken, c_token
14
+ end
15
+ end
16
+ send_message message do |success, result|
17
+ if success
18
+ xml_doc = Nokogiri::XML(result[:content])
19
+ xml_doc = Nokogiri::XML(result[:content])
20
+ configurations = []
21
+ xml_doc.xpath('//trt:Configurations').each do |node|
22
+ bounds = node.xpath('tt:Bounds')
23
+ multicast = node.xpath('tt:Multicast')
24
+ address = multicast.xpath('tt:Address')
25
+ configuration = {
26
+ name: value(node, 'tt:Name'),
27
+ use_count: value(node, 'tt:UseCount'),
28
+ token: attribute(node, 'token'),
29
+ encoding: value(node, 'tt:Encoding'),
30
+ bitrate: value(node, 'tt:Bitrate'),
31
+ sample_rate: value(node, 'tt:SampleRate'),
32
+
33
+ multicast: {
34
+ address: {
35
+ type: value(address, 'tt:Type'),
36
+ ipv4_address: value(address, 'tt:IPv4Address'),
37
+ ipv6_address: value(address, 'tt:IPv6Address')
38
+ },
39
+ port: value(multicast, "tt:Port"),
40
+ ttl: value(multicast, "tt:TTL"),
41
+ auto_start: value(multicast, "tt:AutoStart")
42
+ },
43
+ session_timeout: value(node, 'tt:SessionTimeout')
44
+ }
45
+ configurations << configuration
46
+ end
47
+ callback cb, success, configurations
48
+ else
49
+ callback cb, success, result
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,40 @@
1
+ require_relative '../action'
2
+
3
+ module ONVIF
4
+ module MediaAction
5
+ class GetVideoSourceConfigurations < Action
6
+ def run cb
7
+ message = Message.new
8
+ message.body = ->(xml) do
9
+ xml.wsdl(:GetVideoSourceConfigurations)
10
+ end
11
+ send_message message do |success, result|
12
+ if success
13
+ xml_doc = Nokogiri::XML(result[:content])
14
+ configurations = []
15
+ xml_doc.xpath('//trt:Configurations').each do |node|
16
+ bounds = node.at_xpath('tt:Bounds')
17
+ configuration = {
18
+ name: value(node, 'tt:Name'),
19
+ use_count: value(node, 'tt:UseCount'),
20
+ token: attribute(node, 'token'),
21
+ source_token: value(node, 'tt:SourceToken'),
22
+ bounds: {
23
+ x: attribute(bounds, "x"),
24
+ y: attribute(bounds, "y"),
25
+ width: attribute(bounds, "width"),
26
+ height: attribute(bounds, "height")
27
+ },
28
+ extension: ""
29
+ }
30
+ configurations << configuration
31
+ end
32
+ callback cb, success, configurations
33
+ else
34
+ callback cb, success, result
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,10 @@
1
+ require_relative 'service'
2
+ Dir.chdir __dir__ do
3
+ require_dir 'media'
4
+ end
5
+
6
+ module ONVIF
7
+ class Media < Service
8
+ end
9
+ end
10
+
@@ -0,0 +1,41 @@
1
+ require 'nokogiri'
2
+ require "builder"
3
+ require "akami"
4
+
5
+ module ONVIF
6
+ class Message
7
+ attr_writer :body
8
+
9
+ def initialize options = {}
10
+ @options = {
11
+ username: 'admin',
12
+ password: 'admin',
13
+ namespaces: {}
14
+ }.merge(options)
15
+
16
+ @namespaces = {
17
+ :'xmlns:soap' => "http://www.w3.org/2003/05/soap-envelope",
18
+ :'xmlns:wsdl' => "http://www.onvif.org/ver10/device/wsdl"
19
+ }.merge(@options[:namespaces])
20
+ end
21
+
22
+ def header
23
+ wsse = Akami.wsse
24
+ wsse.credentials(@options[:username], @options[:password])
25
+ wsse.created_at = Time.now
26
+ wsse.to_xml
27
+ end
28
+
29
+ def to_s
30
+ Builder::XmlMarkup.new(indent: 4).soap(:Envelope, @namespaces) do |xml|
31
+ xml.soap(:Header) do
32
+ xml << header
33
+ end
34
+ xml.soap(:Body) do
35
+ @body.call(xml) if @body.class == Proc
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+
@@ -0,0 +1,5 @@
1
+ def require_dir dir
2
+ Dir[File.join(dir, '*.rb')].each do |file|
3
+ require_relative file
4
+ end
5
+ end