ruby_onvif_client 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +3 -0
- data/lib/ruby_onvif_client/action.rb +31 -0
- data/lib/ruby_onvif_client/client.rb +44 -0
- data/lib/ruby_onvif_client/device_discovery.rb +36 -0
- data/lib/ruby_onvif_client/device_management/get_capabilities.rb +118 -0
- data/lib/ruby_onvif_client/device_management/get_device_information.rb +30 -0
- data/lib/ruby_onvif_client/device_management/get_network_interfaces.rb +131 -0
- data/lib/ruby_onvif_client/device_management/get_network_protocols.rb +32 -0
- data/lib/ruby_onvif_client/device_management/get_system_date_and_time.rb +60 -0
- data/lib/ruby_onvif_client/device_management/get_users.rb +32 -0
- data/lib/ruby_onvif_client/device_management/set_network_interfaces.rb +83 -0
- data/lib/ruby_onvif_client/device_management/set_system_date_and_time.rb +48 -0
- data/lib/ruby_onvif_client/device_management/set_system_factory_default.rb +21 -0
- data/lib/ruby_onvif_client/device_management/system_reboot.rb +25 -0
- data/lib/ruby_onvif_client/device_management.rb +10 -0
- data/lib/ruby_onvif_client/media/get_audio_encoder_configuration.rb +48 -0
- data/lib/ruby_onvif_client/media/get_audio_encoder_configuration_options.rb +57 -0
- data/lib/ruby_onvif_client/media/get_audio_encoder_configurations.rb +49 -0
- data/lib/ruby_onvif_client/media/get_audio_source_configurations.rb +32 -0
- data/lib/ruby_onvif_client/media/get_stream_uri.rb +58 -0
- data/lib/ruby_onvif_client/media/get_video_encoder_configuration.rb +104 -0
- data/lib/ruby_onvif_client/media/get_video_encoder_configuration_options.rb +95 -0
- data/lib/ruby_onvif_client/media/get_video_source_configuration.rb +55 -0
- data/lib/ruby_onvif_client/media/get_video_source_configurations.rb +40 -0
- data/lib/ruby_onvif_client/media.rb +10 -0
- data/lib/ruby_onvif_client/message.rb +41 -0
- data/lib/ruby_onvif_client/path.rb +5 -0
- data/lib/ruby_onvif_client/service.rb +37 -0
- data/lib/ruby_onvif_client.rb +3 -0
- data/ruby-onvif-client.gemspec +20 -0
- 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,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,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
|
+
|