diff --git a/README.md b/README.md
index 3a7c328..0dc5422 100644
--- a/README.md
+++ b/README.md
@@ -14,6 +14,8 @@ The node-onvif provides you with the APIs as follows:
* Device Management Service
* Media Service
* PTZ Service
+ * Search Service
+ * Replay Service
Besides, the node-onvif provides you with simple APIs that allow you to control ONVIF network cameras easily even if you are not familiar with the ONVIF specifications.
@@ -137,6 +139,14 @@ This package includes a sample application "[ONVIF Network Camera Manager](https
* [`getPresets(params[, callback])` method](#OnvifServicePtz-getPresets-method)
* [`gotoPreset(params[, callback])` method](#OnvifServicePtz-gotoPreset-method)
* [`removePreset(params[, callback])` method](#OnvifServicePtz-removePreset-method)
+* [`OnvifServiceSearch` object](#OnvifServiceSearch-object)
+ * [`getServiceCapabilities([callback])` method](#OnvifServiceSearch-getServiceCapabilities-method)
+ * [`getRecordingSummary([callback])` method](#OnvifServiceSearch-getRecordingSummary-method)
+ * [`findRecordings(params[, callback])` method](#OnvifServiceSearch-findRecordings-method)
+ * [`getRecordingSearchResults(params[, callback])` method](#OnvifServiceSearch-getRecordingSearchResults-method)
+* [`OnvifServiceReplay` object](#OnvifServiceReplay-object)
+ * [`getServiceCapabilities([callback])` method](#OnvifServiceReplay-getServiceCapabilities-method)
+ * [`getReplayUri(params[, callback])` method](#OnvifServiceReplay-getReplayUri-method)
* [References](#References)
* [Release Note](#Release-Note)
* [License](#License)
@@ -601,6 +611,8 @@ Property | | Type | Description
+- | `device` | Object | [`OnvifServiceDevice`](#OnvifServiceDevice-object) object
+- | `media` | Object | [`OnvifServiceMedia`](#OnvifServiceMedia-object) object
+- | `ptz` | Object | [`OnvifServicePtz`](#OnvifServicePtz-object) object
++- | `search` | Object | [`OnvifServiceSearch`](#OnvifServiceSearch-object) object
++- | `replay` | Object | [`OnvifServiceReplay`](#OnvifServiceReplay-object) object
These objects will be set when the initialization process is completed calling the [`init()`](#OnvifDevice-init-method) method. See the section "[ONVIF commands](#ONVIF-commands)" for details.
@@ -2225,6 +2237,127 @@ device.services.ptz.removePreset(params).then((result) => {
});
```
+---------------------------------------
+## `OnvifServiceSearch` object
+
+This object represents the [ONVIF Search Service](https://www.onvif.org/specs/srv/rsrch/ONVIF-RecordingSearch-Service-Spec.pdf).
+
+### getServiceCapabilities(*[callback]*) method
+
+This method sends a `GetServiceCapabilities` command.
+
+### getRecordingSummary(*[callback]*) method
+
+This method sends a `GetRecordingSummary` command.
+
+### findRecordings(*params[, callback]*) method
+
+This method sends a `FindRecordings` command. The 1st argument `params` must be a hash object consisting of the properties as follows:
+
+Property | | | Type | Required |Description
+:---------------|:-----------------------------|:--------|:--------|:---------|:----------
+`Scope` | | |Object | required | scope defines the dataset to consider for this search
++- | `IncludedSources` | | Array | optional | a list of sources that are included in the scope
++- | +- | `Type` | String | optional |
++- | +- | `Token` | String | required |
++- | `IncludedRecordings` | | Array | optional | a list of recordings that are included in the scope
++- | `RecordingInformationFilter` | | String | optional | an xpath expression used to specify what recordings to search
++- | `Extension` | | String | optional | extension point
+`MaxMatches` | | | Integer | optional | the search will be completed after this many matches
+`KeepAliveTime` | | | Integer | required | the time the search session will be kept alive after responding to this and subsequent requests
+
+```JavaScript
+let params = {
+ 'Scope': {
+ 'IncludedSources': [
+ {
+ 'Type': 'sourceType',
+ 'Token': 'sourceToken'
+ }
+ ],
+ 'IncludedRecordings': [
+ 'recording1'
+ ],
+ 'RecordingInformationFilter': 'filter',
+ 'Extension': 'extension',
+ },
+ 'MaxMatches': 3,
+ 'KeepAliveTime': 100
+};
+
+device.services.ptz.findRecordings(params).then((result) => {
+ console.log(JSON.stringify(result['data'], null, ' '));
+}).catch((error) => {
+ console.error(error);
+});
+```
+
+### getRecordingSearchResults(*params[, callback]*) method
+
+This method sends a `GetRecordingSearchResults` command. The 1st argument `params` must be a hash object consisting of the properties as follows:
+
+Property | Type | Required |Description
+:----------------|:--------|:---------|:----------
+`SearchToken` | String | required | the search session to get results from
+`MinResults` | Integer | optional | the minimum number of results to return in one response
+`MaxResults` | Integer | optional | the maximum number of results to return in one response
+`WaitTime` | Integer | optional | the maximum time before responding to the request
+
+```JavaScript
+let params = {
+ 'SearchToken': 'token',
+ 'MinResults': 3,
+ 'MaxResults': 14,
+ 'WaitTime': 50
+};
+
+device.services.ptz.findRecordings(params).then((result) => {
+ console.log(JSON.stringify(result['data'], null, ' '));
+}).catch((error) => {
+ console.error(error);
+});
+```
+
+---------------------------------------
+## `OnvifServiceReplay` object
+
+This object represents the [ONVIF Replay Service](https://www.onvif.org/specs/srv/replay/ONVIF-ReplayControl-Service-Spec.pdf).
+
+### getServiceCapabilities(*[callback]*) method
+
+This method sends a `GetServiceCapabilities` command.
+
+### getReplayUri(*params[, callback]*) method
+
+This method sends a `GetReplayUri` command. The 1st argument `params` must be a hash object consisting of the properties as follows:
+
+Property | | | Type | Required |Description
+:----------------|:------------|:-----------|:-------|:---------|:----------
+`StreamSetup` | | | Object | required | the connection parameters to be used for the stream
++- | `Stream` | | String | required | either RTP-Unicast, RTP-Multicast
++- | `Transport` | | Object | required |
++- | +- | `Protocol` | String | required | either UDP, TCP, RTSP, HTTP
++- | +- | `Tunnel` | Object | optional | **`TODO`** not implemented
+`RecordingToken` | | | String | required | identifier of the recording to be streamed
+
+```JavaScript
+let params = {
+ 'StreamSetup': {
+ 'Stream': 'RTP-Unicast',
+ 'Transport': {
+ 'Protocol': 'TCP'
+ },
+ },
+ 'RecordingToken': 'token'
+};
+
+device.services.ptz.findRecordings(params).then((result) => {
+ console.log(JSON.stringify(result['data'], null, ' '));
+}).catch((error) => {
+ console.error(error);
+});
+```
+
---------------------------------------
## References
@@ -2233,10 +2366,14 @@ This module is based on the [ONVIF specifications](http://www.onvif.org/Document
* [ONVIF Core Specification ver 16.06](http://www.onvif.org/specs/core/ONVIF-Core-Specification-v1606.pdf)
* [ONVIF Media Service Specification ver 16.06](http://www.onvif.org/specs/srv/media/ONVIF-Media-Service-Spec-v1606.pdf)
* [ONVIF PTZ Service Specification ver 2.6.1](http://www.onvif.org/specs/srv/ptz/ONVIF-PTZ-Service-Spec-v261.pdf)
+* [ONVIF Search Service Specification ver 18.12](https://www.onvif.org/specs/srv/rsrch/ONVIF-RecordingSearch-Service-Spec-v1812.pdf)
+* [ONVIF Replay Service Specification ver 17.06](https://www.onvif.org/specs/srv/replay/ONVIF-ReplayControl-Service-Spec-v1706.pdf)
* [ONVIF Profile S Specification ver 1.1.1](http://www.onvif.org/Portals/0/documents/op/ONVIF_Profile_%20S_Specification_v1-1-1.pdf)
* [ONVIF Device Management Service WSDL, ver 16.06](http://www.onvif.org/onvif/ver10/device/wsdl/devicemgmt.wsdl)
* [ONVIF Media Service WSDL, ver 2.6](http://www.onvif.org/onvif/ver10/media/wsdl/media.wsdl)
* [ONVIF PTZ Service WSDL, ver 16.06](http://www.onvif.org/onvif/ver20/ptz/wsdl/ptz.wsdl)
+* [ONVIF Search Service WSDL, ver 2.4.2](https://www.onvif.org/ver10/search.wsdl)
+* [ONVIF Replay Service WSDL, ver 18.06](https://www.onvif.org/ver10/replay.wsdl)
* [ONVIF Application Programmer's Guide ver 1.0](http://www.onvif.org/Portals/0/documents/WhitePapers/ONVIF_WG-APG-Application_Programmer%27s_Guide.pdf)
---------------------------------------
diff --git a/lib/modules/device.js b/lib/modules/device.js
index 29c0522..b32ec1d 100644
--- a/lib/modules/device.js
+++ b/lib/modules/device.js
@@ -15,6 +15,8 @@ const mOnvifServiceDevice = require('./service-device.js');
const mOnvifServiceMedia = require('./service-media.js');
const mOnvifServicePtz = require('./service-ptz.js');
const mOnvifServiceEvents = require('./service-events.js');
+const mOnvifServiceSearch = require('./service-search.js');
+const mOnvifServiceReplay = require('./service-replay.js');
const mOnvifHttpAuth = require('./http-auth.js');
/* ------------------------------------------------------------------
@@ -71,7 +73,9 @@ function OnvifDevice(params) {
'events': null,
'imaging': null,
'media': null,
- 'ptz': null
+ 'ptz': null,
+ 'search': null,
+ 'replay': null
};
this.profile_list = [];
@@ -439,6 +443,24 @@ OnvifDevice.prototype._getCapabilities = function () {
'pass': this.pass
});
}
+ let search = c['Extension'] && c['Extension']['Search'];
+ if (search && search['XAddr']) {
+ this.services.search = new mOnvifServiceSearch({
+ 'xaddr': this._getXaddr(search['XAddr']),
+ 'time_diff': this.time_diff,
+ 'user': this.user,
+ 'pass': this.pass
+ });
+ }
+ let replay = c['Extension'] && c['Extension']['Replay'];
+ if (replay && replay['XAddr']) {
+ this.services.replay = new mOnvifServiceReplay({
+ 'xaddr': this._getXaddr(replay['XAddr']),
+ 'time_diff': this.time_diff,
+ 'user': this.user,
+ 'pass': this.pass
+ });
+ }
resolve();
});
});
diff --git a/lib/modules/service-replay.js b/lib/modules/service-replay.js
new file mode 100644
index 0000000..8fd494e
--- /dev/null
+++ b/lib/modules/service-replay.js
@@ -0,0 +1,214 @@
+/* ------------------------------------------------------------------
+ * node-onvif - service-replay.js
+ *
+ * Copyright (c) 2018 - 2019, Gabriele Monaco, All rights reserved.
+ * Released under the MIT license
+ * Date: 2019-04-12
+ * ---------------------------------------------------------------- */
+'use strict';
+const mUrl = require('url');
+const mOnvifSoap = require('./soap.js');
+
+/* ------------------------------------------------------------------
+ * Constructor: OnvifServiceReplay(params)
+ * - params:
+ * - xaddr : URL of the entry point for the replay service
+ * (Required)
+ * - user : User name (Optional)
+ * - pass : Password (Optional)
+ * - time_diff: ms
+ * ---------------------------------------------------------------- */
+function OnvifServiceReplay(params) {
+ this.xaddr = '';
+ this.user = '';
+ this.pass = '';
+
+ let err_msg = '';
+
+ if(err_msg = mOnvifSoap.isInvalidValue(params, 'object')) {
+ throw new Error('The value of "params" was invalid: ' + err_msg);
+ }
+
+ if('xaddr' in params) {
+ if(err_msg = mOnvifSoap.isInvalidValue(params['xaddr'], 'string')) {
+ throw new Error('The "xaddr" property was invalid: ' + err_msg);
+ } else {
+ this.xaddr = params['xaddr'];
+ }
+ } else {
+ throw new Error('The "xaddr" property is required.');
+ }
+
+ if('user' in params) {
+ if(err_msg = mOnvifSoap.isInvalidValue(params['user'], 'string', true)) {
+ throw new Error('The "user" property was invalid: ' + err_msg);
+ } else {
+ this.user = params['user'] || '';
+ }
+ }
+
+ if('pass' in params) {
+ if(err_msg = mOnvifSoap.isInvalidValue(params['pass'], 'string', true)) {
+ throw new Error('The "pass" property was invalid: ' + err_msg);
+ } else {
+ this.pass = params['pass'] || '';
+ }
+ }
+
+ this.oxaddr = mUrl.parse(this.xaddr);
+ if(this.user) {
+ this.oxaddr.auth = this.user + ':' + this.pass;
+ }
+
+ this.time_diff = params['time_diff'];
+ this.name_space_attr_list = [
+ 'xmlns:trp="http://www.onvif.org/ver10/replay/wsdl"',
+ 'xmlns:tt="http://www.onvif.org/ver10/schema"'
+ ];
+};
+
+OnvifServiceReplay.prototype._createRequestSoap = function(body) {
+ let soap = mOnvifSoap.createRequestSoap({
+ 'body': body,
+ 'xmlns': this.name_space_attr_list,
+ 'diff': this.time_diff,
+ 'user': this.user,
+ 'pass': this.pass
+ });
+ return soap;
+};
+
+/* ------------------------------------------------------------------
+ * Method: setAuth(user, pass)
+ * ---------------------------------------------------------------- */
+OnvifServiceReplay.prototype.setAuth = function(user, pass) {
+ this.user = user || '';
+ this.pass = pass || '';
+ if(this.user) {
+ this.oxaddr.auth = this.user + ':' + this.pass;
+ } else {
+ this.oxaddr.auth = '';
+ }
+};
+
+/* ------------------------------------------------------------------
+ * Method: getServiceCapabilities([callback])
+ * ---------------------------------------------------------------- */
+OnvifServiceReplay.prototype.getServiceCapabilities = function(callback) {
+ let promise = new Promise((resolve, reject) => {
+ let soap_body = '';
+ let soap = this._createRequestSoap(soap_body);
+ mOnvifSoap.requestCommand(this.oxaddr, 'GetServiceCapabilities', soap).then((result) => {
+ try {
+ let d = result['data']['Capabilities'];
+ if(!Array.isArray(d)) {
+ result['data']['Capabilities'] = [d];
+ }
+ } catch(e) {}
+ resolve(result);
+ }).catch((error) => {
+ reject(error);
+ });
+ });
+ if(callback) {
+ promise.then((result) => {
+ callback(null, result);
+ }).catch((error) => {
+ callback(error);
+ });
+ } else {
+ return promise;
+ }
+};
+
+/* ------------------------------------------------------------------
+ * Method: getReplayUri(params[, callback])
+ * - params:
+ * - StreamSetup | Object | required | the connection parameters to be used for the stream
+ * - Stream | String | required | either RTP-Unicast, RTP-Multicast
+ * - Transport | Object | required |
+ * - Protocol | String | required | either UDP, TCP, RTSP, HTTP
+ * - Tunnel | Object | optional | TODO not implemented
+ * - RecordingToken | String | required | identifier of the recording to be streamed
+ *
+ * ---------------------------------------------------------------- */
+OnvifServiceReplay.prototype.getReplayUri = function(params, callback) {
+ let promise = new Promise((resolve, reject) => {
+ let err_msg = '';
+ if(err_msg = mOnvifSoap.isInvalidValue(params, 'object')) {
+ reject(new Error('The value of "params" was invalid: ' + err_msg));
+ return;
+ }
+
+ if(err_msg = mOnvifSoap.isInvalidValue(params['StreamSetup'], 'object')) {
+ reject(new Error('The "Scope" property was invalid: ' + err_msg));
+ return;
+ }
+
+ let stream = params['StreamSetup']['Stream']
+ if(err_msg = mOnvifSoap.isInvalidValue(stream, 'string')) {
+ reject(new Error('The "Stream" property was invalid: ' + err_msg));
+ return;
+ } else if(!stream.match(/^(RTP-Unicast|RTP-Multicast)$/)) {
+ reject(new Error('The "Stream" property was invalid: The value must be either "RTP-Unicast" or "RTP-Multicast".'));
+ return;
+ }
+
+ if(err_msg = mOnvifSoap.isInvalidValue(params['StreamSetup']['Transport'], 'object')) {
+ reject(new Error('The "Transport" property was invalid: ' + err_msg));
+ return;
+ }
+
+ let protocol = params['StreamSetup']['Transport']['Protocol']
+ if(err_msg = mOnvifSoap.isInvalidValue(protocol, 'string')) {
+ reject(new Error('The "Stream" property was invalid: ' + err_msg));
+ return;
+ } else if(!protocol.match(/^(UDP|TCP|RTSP|HTTP)$/)) {
+ reject(new Error('The "Stream" property was invalid: The value must be either "UDP", "TCP", "RTSP" or "HTTP".'));
+ return;
+ }
+
+ if('Tunnel' in params['StreamSetup']['Transport']) {
+ //TODO implement this
+ }
+
+ if(err_msg = mOnvifSoap.isInvalidValue(params['RecordingToken'], 'string')) {
+ reject(new Error('The "RecordingToken" property was invalid: ' + err_msg));
+ return;
+ }
+
+ let soap_body = '';
+ soap_body += '';
+ soap_body += '';
+ soap_body += '' + params['StreamSetup']['Stream'] + '';
+ soap_body += '';
+ soap_body += '' + params['StreamSetup']['Transport']['Protocol'] + '';
+ soap_body += '';
+ soap_body += '';
+ soap_body += '' + params['RecordingToken'] + '';
+ soap_body += '';
+ let soap = this._createRequestSoap(soap_body);
+ mOnvifSoap.requestCommand(this.oxaddr, 'GetReplayUri', soap).then((result) => {
+ try {
+ let d = result['data']['Uri'];
+ if(!Array.isArray(d)) {
+ result['data']['Uri'] = [d];
+ }
+ } catch(e) {}
+ resolve(result);
+ }).catch((error) => {
+ reject(error);
+ });
+ });
+ if(callback) {
+ promise.then((result) => {
+ callback(null, result);
+ }).catch((error) => {
+ callback(error);
+ });
+ } else {
+ return promise;
+ }
+};
+
+module.exports = OnvifServiceReplay;
diff --git a/lib/modules/service-search.js b/lib/modules/service-search.js
new file mode 100644
index 0000000..5d35b5e
--- /dev/null
+++ b/lib/modules/service-search.js
@@ -0,0 +1,374 @@
+/* ------------------------------------------------------------------
+ * node-onvif - service-search.js
+ *
+ * Copyright (c) 2018 - 2019, Gabriele Monaco, All rights reserved.
+ * Released under the MIT license
+ * Date: 2019-04-12
+ * ---------------------------------------------------------------- */
+'use strict';
+const mUrl = require('url');
+const mOnvifSoap = require('./soap.js');
+
+/* ------------------------------------------------------------------
+ * Constructor: OnvifServiceSearch(params)
+ * - params:
+ * - xaddr : URL of the entry point for the search service
+ * (Required)
+ * - user : User name (Optional)
+ * - pass : Password (Optional)
+ * - time_diff: ms
+ * ---------------------------------------------------------------- */
+function OnvifServiceSearch(params) {
+ this.xaddr = '';
+ this.user = '';
+ this.pass = '';
+
+ let err_msg = '';
+
+ if(err_msg = mOnvifSoap.isInvalidValue(params, 'object')) {
+ throw new Error('The value of "params" was invalid: ' + err_msg);
+ }
+
+ if('xaddr' in params) {
+ if(err_msg = mOnvifSoap.isInvalidValue(params['xaddr'], 'string')) {
+ throw new Error('The "xaddr" property was invalid: ' + err_msg);
+ } else {
+ this.xaddr = params['xaddr'];
+ }
+ } else {
+ throw new Error('The "xaddr" property is required.');
+ }
+
+ if('user' in params) {
+ if(err_msg = mOnvifSoap.isInvalidValue(params['user'], 'string', true)) {
+ throw new Error('The "user" property was invalid: ' + err_msg);
+ } else {
+ this.user = params['user'] || '';
+ }
+ }
+
+ if('pass' in params) {
+ if(err_msg = mOnvifSoap.isInvalidValue(params['pass'], 'string', true)) {
+ throw new Error('The "pass" property was invalid: ' + err_msg);
+ } else {
+ this.pass = params['pass'] || '';
+ }
+ }
+
+ this.oxaddr = mUrl.parse(this.xaddr);
+ if(this.user) {
+ this.oxaddr.auth = this.user + ':' + this.pass;
+ }
+
+ this.time_diff = params['time_diff'];
+ this.name_space_attr_list = [
+ 'xmlns:tse="http://www.onvif.org/ver10/search/wsdl"',
+ 'xmlns:tt="http://www.onvif.org/ver10/schema"'
+ ];
+};
+
+OnvifServiceSearch.prototype._createRequestSoap = function(body) {
+ let soap = mOnvifSoap.createRequestSoap({
+ 'body': body,
+ 'xmlns': this.name_space_attr_list,
+ 'diff': this.time_diff,
+ 'user': this.user,
+ 'pass': this.pass
+ });
+ return soap;
+};
+
+/* ------------------------------------------------------------------
+ * Method: setAuth(user, pass)
+ * ---------------------------------------------------------------- */
+OnvifServiceSearch.prototype.setAuth = function(user, pass) {
+ this.user = user || '';
+ this.pass = pass || '';
+ if(this.user) {
+ this.oxaddr.auth = this.user + ':' + this.pass;
+ } else {
+ this.oxaddr.auth = '';
+ }
+};
+
+/* ------------------------------------------------------------------
+ * Method: getServiceCapabilities([callback])
+ * ---------------------------------------------------------------- */
+OnvifServiceSearch.prototype.getServiceCapabilities = function(callback) {
+ let promise = new Promise((resolve, reject) => {
+ let soap_body = '';
+ let soap = this._createRequestSoap(soap_body);
+ mOnvifSoap.requestCommand(this.oxaddr, 'GetServiceCapabilities', soap).then((result) => {
+ try {
+ let d = result['data']['Capabilities'];
+ if(!Array.isArray(d)) {
+ result['data']['Capabilities'] = [d];
+ }
+ } catch(e) {}
+ resolve(result);
+ }).catch((error) => {
+ reject(error);
+ });
+ });
+ if(callback) {
+ promise.then((result) => {
+ callback(null, result);
+ }).catch((error) => {
+ callback(error);
+ });
+ } else {
+ return promise;
+ }
+};
+
+/* ------------------------------------------------------------------
+ * Method: getRecordingSummary([callback])
+ * ---------------------------------------------------------------- */
+OnvifServiceSearch.prototype.getRecordingSummary = function(callback) {
+ let promise = new Promise((resolve, reject) => {
+ let soap_body = '';
+ let soap = this._createRequestSoap(soap_body);
+ mOnvifSoap.requestCommand(this.oxaddr, 'GetRecordingSummary', soap).then((result) => {
+ try {
+ let d = result['data']['Summary'];
+ if(!Array.isArray(d)) {
+ result['data']['Summary'] = [d];
+ }
+ } catch(e) {}
+ resolve(result);
+ }).catch((error) => {
+ reject(error);
+ });
+ });
+ if(callback) {
+ promise.then((result) => {
+ callback(null, result);
+ }).catch((error) => {
+ callback(error);
+ });
+ } else {
+ return promise;
+ }
+};
+
+/* ------------------------------------------------------------------
+ * Method: findRecordings(params[, callback])
+ * - params:
+ * - Scope | Object | required | scope defines the dataset to consider for this search
+ * - IncludedSources | Array | optional | a list of sources that are included in the scope
+ * - Type | String | optional |
+ * - Token | String | required |
+ * - IncludedRecordings | Array | optional | a list of recordings that are included in the scope
+ * - RecordingInformationFilter | String | optional | an xpath expression used to specify what recordings to search
+ * - Extension | String | optional | extension point
+ * - MaxMatches | Integer | optional | the search will be completed after this many matches
+ * - KeepAliveTime | Integer | required | the time the search session will be kept alive after responding to this and subsequent requests
+ *
+ * ---------------------------------------------------------------- */
+OnvifServiceSearch.prototype.findRecordings = function(params, callback) {
+ let promise = new Promise((resolve, reject) => {
+ let err_msg = '';
+ if(err_msg = mOnvifSoap.isInvalidValue(params, 'object')) {
+ reject(new Error('The value of "params" was invalid: ' + err_msg));
+ return;
+ }
+
+ if(err_msg = mOnvifSoap.isInvalidValue(params['Scope'], 'object')) {
+ reject(new Error('The "Scope" property was invalid: ' + err_msg));
+ return;
+ }
+
+ let klist = ['IncludedSources', 'IncludedRecordings', 'RecordingInformationFilter', 'Extension'];
+ let tlist = ['array', 'array', 'string', 'string'];
+
+ for(let i=0; i';
+ soap_body += '';
+ if(params['Scope']['IncludedSources']){
+ params['Scope']['IncludedSources'].forEach((o) => {
+ soap_body += '';
+ soap_body += '' + o['Token'] + '';
+ if(o['Type']){
+ soap_body += '' + o['Type'] + '';
+ }
+ soap_body += '';
+ })
+ }
+ if(params['Scope']['IncludedRecordings']){
+ params['Scope']['IncludedRecordings'].forEach((s) => {
+ soap_body += '' + s + '';
+ })
+ }
+ if(params['Scope']['RecordingInformationFilter']){
+ soap_body += '' + params['Scope']['RecordingInformationFilter'] + '';
+ }
+ if(params['Scope']['Extension']){
+ soap_body += '' + params['Scope']['Extension'] + '';
+ }
+ soap_body += '';
+ if(params['MaxMatches']){
+ soap_body += '' + params['MaxMatches'] + '';
+ }
+ soap_body += 'PT'+ params['KeepAliveTime'] + 'S';
+ soap_body += '';
+ let soap = this._createRequestSoap(soap_body);
+ mOnvifSoap.requestCommand(this.oxaddr, 'FindRecordings', soap).then((result) => {
+ try {
+ let d = result['data']['SearchToken'];
+ if(!Array.isArray(d)) {
+ result['data']['SearchToken'] = [d];
+ }
+ } catch(e) {}
+ resolve(result);
+ }).catch((error) => {
+ reject(error);
+ });
+ });
+ if(callback) {
+ promise.then((result) => {
+ callback(null, result);
+ }).catch((error) => {
+ callback(error);
+ });
+ } else {
+ return promise;
+ }
+};
+
+/* ------------------------------------------------------------------
+ * Method: getRecordingSearchResults(params[, callback])
+ * - params:
+ * - SearchToken | String | required | the search session to get results from
+ * - MinResults | Integer | optional | the minimum number of results to return in one response
+ * - MaxResults | Integer | optional | the maximum number of results to return in one response
+ * - WaitTime | Integer | optional | the maximum time before responding to the request
+ *
+ * ---------------------------------------------------------------- */
+OnvifServiceSearch.prototype.getRecordingSearchResults = function(params, callback) {
+ let promise = new Promise((resolve, reject) => {
+ let err_msg = '';
+ if(err_msg = mOnvifSoap.isInvalidValue(params, 'object')) {
+ reject(new Error('The value of "params" was invalid: ' + err_msg));
+ return;
+ }
+
+ if(err_msg = mOnvifSoap.isInvalidValue(params['SearchToken'], 'string')) {
+ reject(new Error('The "SearchToken" property was invalid: ' + err_msg));
+ return;
+ }
+
+ if('MinResults' in params) {
+ if(err_msg = mOnvifSoap.isInvalidValue(params['MinResults'], 'integer')) {
+ reject(new Error('The "MinResults" property was invalid: ' + err_msg));
+ return;
+ }
+ }
+
+ if('MaxResults' in params) {
+ if(err_msg = mOnvifSoap.isInvalidValue(params['MaxResults'], 'integer')) {
+ reject(new Error('The "MaxResults" property was invalid: ' + err_msg));
+ return;
+ }
+ }
+
+ if('WaitTime' in params) {
+ if(err_msg = mOnvifSoap.isInvalidValue(params['WaitTime'], 'integer')) {
+ reject(new Error('The "WaitTime" property was invalid: ' + err_msg));
+ return;
+ }
+ }
+
+ let soap_body = '';
+ soap_body += '';
+ soap_body += '' + params['SearchToken'] + '';
+ if(params['MinResults']) {
+ soap_body += '' + params['MinResults'] + '';
+ }
+ if(params['MaxResults']) {
+ soap_body += '' + params['MaxResults'] + '';
+ }
+ if(params['WaitTime']) {
+ soap_body += 'PT' + params['WaitTime'] + 'S';
+ }
+ soap_body += '';
+ let soap = this._createRequestSoap(soap_body);
+ mOnvifSoap.requestCommand(this.oxaddr, 'GetRecordingSearchResults', soap).then((result) => {
+ try {
+ let d = result['data']['ResultList'];
+ if(!Array.isArray(d)) {
+ result['data']['ResultList'] = [d];
+ }
+ } catch(e) {}
+ resolve(result);
+ }).catch((error) => {
+ reject(error);
+ });
+ });
+ if(callback) {
+ promise.then((result) => {
+ callback(null, result);
+ }).catch((error) => {
+ callback(error);
+ });
+ } else {
+ return promise;
+ }
+};
+
+module.exports = OnvifServiceSearch;