ruby_onvif_client 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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