Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
a470895
Change code such that one can specify a NIC on which to bind - rather…
jimudall Feb 12, 2019
3088cef
Implement setNetworkInterfaces method
jimudall Feb 27, 2019
d45ee86
Some cameras don't like the top-level namespace. So change to grotty…
jimudall Feb 27, 2019
9ad0609
Implement some ONVIF methods currently unavailable in public version …
jimudall Feb 28, 2019
ba81918
Change documentation for new methods I've added
jimudall Mar 1, 2019
495dbe2
Add methods to add VideoSourceConfiguration to profile
jimudall Mar 8, 2019
8517805
Remove deprecated new Buffer() call
jimudall Mar 20, 2019
59a9a72
When a startProbe is cancelled, there could still be a pending Timeou…
jimudall Mar 27, 2019
12df6d3
edit addVideoEncoderConfiguration method
jimudall Apr 8, 2019
a4f495f
We were not returning the 'fixed' attribute on the profiles
jimudall Apr 17, 2019
608fa1a
Was ot converting string to boolean
jimudall Apr 17, 2019
f311174
Add new methods to remove video source and video encoder configurations
jimudall May 10, 2019
96a1736
SetVideoEncoderConfiguration: Some cameras don't like implicit names…
jimudall May 15, 2019
d08697d
GAG!!! One camera returns the wrong response. In the bowels of this…
jimudall May 15, 2019
2d2718c
Clean up error object
jimudall May 22, 2019
0d026d8
Change error message. The NIC could NOT exist, OR it could be unplu…
jimudall Jun 14, 2019
6a67d86
when sending GetSystemDateAndTime, omit username/password
jimudall Sep 7, 2021
d884316
Don't send authorization credentials on GetCapabilities SOAP request
jimudall Sep 7, 2021
f7e1aaa
If we can't getSystemDateAndTime from device, then abort
jimudall Sep 10, 2021
ef40584
add media 2 ONVIF methods
jimudall Sep 20, 2021
8334230
Store the date/time from the camera on successful GetSystemDateAndTime
jimudall Sep 23, 2021
69ca1f3
Wasn't returning govlength on H264 encoders
jimudall Nov 9, 2021
bed71be
Wasn't converting GOVlength to integer from string
jimudall Nov 12, 2021
7dc0dc6
Print more details when setting video encoder fails
jimudall Nov 15, 2021
ef369bc
Implement methods to manage OSD
jimudall Nov 17, 2021
22d70f6
Implemente GetOSDOptions
jimudall Nov 23, 2021
97a1beb
Implemente setOSD
jimudall Nov 23, 2021
6d74f37
Debug OSD methods
jimudall Nov 25, 2021
36fca26
Some cameras use the wrong namespace on OSD configuration
jimudall Dec 15, 2021
9739c5c
Add missing node modules
jimudall Jan 19, 2022
00064d5
Ignore package lock file
jimudall Jan 19, 2022
5126216
Regular express for verifying timezone ala posix 1003.1 was wrong. J…
jimudall Mar 8, 2022
0a09ee9
Add new isONVIF method. THis just asks the device for the date/time
jimudall Apr 20, 2022
6701d2d
Make _getProfiles a public method
jimudall Apr 26, 2022
c0a8c35
Add new methods to manage audio configuration
jimudall Jun 29, 2022
876c524
setAudioConfiguration requires parameters that are optional in the sp…
jimudall Jul 20, 2022
1026f2c
Add timeout to HTTP requests so non-compliant devices don't permanent…
jimudall Aug 16, 2022
7e81362
Add ability to enable/disable DHCP on IP configuration
jimudall Nov 3, 2022
282665c
When making IP address dynamic - don't includ MANUAL IP elemement
jimudall Nov 3, 2022
767772d
Add unparsed response from GetSystemDateAndTime and save in the devic…
jimudall Apr 4, 2023
cb9713d
OOPS! I wasn't providing the EncodingInterval in the encoder
jimudall Jun 5, 2023
45d7266
Add methods to enable logging of all SOAP messages
jimudall Jun 15, 2023
9ac483c
OOPS! I wasn't logging the response - but rather the request again
jimudall Jun 15, 2023
c7c6c4c
Fix: Upgrade xml2js package
jimudall Jul 18, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,4 @@ Temporary Items

test
node_modules
package-lock.json
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ This package includes a sample application "[ONVIF Network Camera Manager](https
* [`getCurrentProfile()` method](#OnvifDevice-getCurrentProfile-method)
* [`getProfileList()` method](#OnvifDevice-getProfileList-method)
* [`changeProfile(index|token)` method](#OnvifDevice-changeProfile-method)
* [`addVideoSourceConfiguration(index|token)` method](#OnvifDevice-addVideoSource-method)
* [`addVideoEncoderConfiguration(index|token)` method](#OnvifDevice-addVideoEncoder-method)
* [`getUdpStreamUrl()` method](#OnvifDevice-getUdpStreamUrl-method)
* [`fetchSnapshot(callback)` method](#OnvifDevice-fetchSnapshot-method)
* [`ptzMove(params[, callback])` method](#OnvifDevice-ptzMove-method)
Expand All @@ -63,6 +65,7 @@ This package includes a sample application "[ONVIF Network Camera Manager](https
* [`getCapabilities([callback])` method](#OnvifServiceDevice-getCapabilities-method)
* [`getWsdlUrl([callback])` method](#OnvifServiceDevice-getWsdlUrl-method)
* [`getDiscoveryMode([callback])` method](#OnvifServiceDevice-getDiscoveryMode-method)
* [`setDiscoveryMode(mode,[callback])` method](#OnvifServiceDevice-setDiscoveryMode-method)
* [`getScopes([callback])` method](#OnvifServiceDevice-getScopes-method)
* [`setScopes(params[, callback])` method](#OnvifServiceDevice-setScopes-method)
* [`addScopes(params[, callback])` method](#OnvifServiceDevice-addScopes-method)
Expand Down Expand Up @@ -137,6 +140,7 @@ 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)
* [`OnvifServiceImaging` object](#OnvifServiceImaging-object)
* [References](#References)
* [Release Note](#Release-Note)
* [License](#License)
Expand Down Expand Up @@ -600,6 +604,7 @@ Property | | Type | Description
`services` | | Object |
+- | `device` | Object | [`OnvifServiceDevice`](#OnvifServiceDevice-object) object
+- | `media` | Object | [`OnvifServiceMedia`](#OnvifServiceMedia-object) object
+- | `imaging`| Object | [`OnvifServiceImaging`](#OnvifServiceImaging-object) object
+- | `ptz` | Object | [`OnvifServicePtz`](#OnvifServicePtz-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.
Expand Down Expand Up @@ -812,7 +817,13 @@ This sample code will output the result like this:
- Before: 1280 x 720
- After: 320 x 180
```
#### <a id="OnvifDevice-addVideoSource-method">addVideoSourceConfiguration(*index|token*)</a>

TBD

#### <a id="OnvifDevice-addVideoEncoder-method">addVideoEncoderConfiguration(*index|token*)</a>

TBD
#### <a id="OnvifDevice-getUdpStreamUrl-method">getUdpStreamUrl()</a>

This method returns the UDP Stream URL. Though the URL can be obtained from the result of the [`getCurrentProfile()`](#OnvifDevice-getCurrentProfile-method) method as well, this method makes that easy.
Expand Down Expand Up @@ -1052,6 +1063,10 @@ This method sends a `GetWsdlUrl` command.

This method sends a `GetDiscoveryMode` command.

### <a id="OnvifServiceDevice-setDiscoveryMode-method">setDiscoveryMode(*[callback]*) method</a>

This method sends a `setDiscoveryMode` command. The 1st argument `mode` MUST be either 'Discoverable' or 'NonDiscoverable'

### <a id="OnvifServiceDevice-getScopes-method">getScopes(*[callback]*) method</a>

This method sends a `GetScopes` command.
Expand Down Expand Up @@ -1201,6 +1216,10 @@ return device.services.device.setDNS(params).then((result) => {

This method sends a `GetNetworkProtocols` command.

### <a id="OnvifServiceDevice-setNetworkInterfaces-method">setNetworkInterfaces(*params[,callback]*) method</a>

This method sends a `GetNetworkProtocols` command.

### <a id="OnvifServiceDevice-getNetworkProtocols-method">getNetworkProtocols(*[callback]*) method</a>

This method sends a `GetNetworkProtocols` command.
Expand Down
98 changes: 87 additions & 11 deletions lib/modules/device.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const mEventEmitter = require('events').EventEmitter;
const mOnvifServiceDevice = require('./service-device.js');
const mOnvifServiceMedia = require('./service-media.js');
const mOnvifServicePtz = require('./service-ptz.js');
const mOnvifServiceImaging = require('./service-imaging.js');
const mOnvifServiceEvents = require('./service-events.js');
const mOnvifHttpAuth = require('./http-auth.js');

Expand All @@ -38,7 +39,10 @@ function OnvifDevice(params) {
this.user = '';
this.pass = '';
this.keepAddr = false;
this.onvifCompliant = 'no';
this.isAddressable = true;
this.lastResponse = null; // for debug
this.lastError = null;

if (('xaddr' in params) && typeof (params['xaddr']) === 'string') {
this.xaddr = params['xaddr'];
Expand Down Expand Up @@ -348,7 +352,16 @@ OnvifDevice.prototype.init = function (callback) {
}).then(() => {
return this._getDeviceInformation();
}).then(() => {
return this._mediaGetProfiles();
return this._getVideoSources();
}).then(() => {
if (!Array.isArray(this.video_sources))
return this.getProfiles();
else {
this.isMultiCameraDevice = true
return(new Promise((res,rej) => {
res(null)
}))
}
}).then(() => {
return this._mediaGetStreamURI();
}).then(() => {
Expand All @@ -357,6 +370,38 @@ OnvifDevice.prototype.init = function (callback) {
let info = this.getInformation();
resolve(info);
}).catch((error) => {

// If we can't even talk to this guy, then abort - but mark the guy as unaddressable
if (this.lastError.toString().search(/Network Error/i) >= 0){
this.isAddressable = false;
}
reject(error);
});
});
if (this._isValidCallback(callback)) {
promise.then((info) => {
callback(null, info);
}).catch((error) => {
callback(error);
});
} else {
return promise;
}
};

/* ------------------------------------------------------------------
* Method: isONVIF([callback])
* ---------------------------------------------------------------- */
OnvifDevice.prototype.isONVIF = function (callback) {
let promise = new Promise((resolve, reject) => {
this._getSystemDateAndTime().then(() => {
resolve(null)
}).catch((error) => {

// If we can't even talk to this guy, then abort - but mark the guy as unaddressable
if (this.lastError.toString().search(/Network Error/i) >= 0){
this.isAddressable = false;
}
reject(error);
});
});
Expand All @@ -375,13 +420,19 @@ OnvifDevice.prototype.init = function (callback) {
OnvifDevice.prototype._getSystemDateAndTime = function () {
let promise = new Promise((resolve, reject) => {
this.services.device.getSystemDateAndTime((error, result) => {
// Ignore the error becase some devices do not support
// the GetSystemDateAndTime command and the error does
// not cause any trouble.
if (!error) {
this.lastError = error;
this.lastResponse = result;

// If no error, then use result to calculate the time difference between us
// That delta will be used in NONCE creation for subsequent authorized calls
if (!error){
this.time_diff = this.services.device.getTimeDiff();
}
resolve();
this.date_time = this.services.device.getDateTime()
this.date_time_unparsed = result.converted.Body.GetSystemDateAndTimeResponse.SystemDateAndTime
this.onvifCompliant = 'yes'
resolve()
} else
reject(error)
});
});
return promise;
Expand All @@ -391,11 +442,13 @@ OnvifDevice.prototype._getSystemDateAndTime = function () {
OnvifDevice.prototype._getCapabilities = function () {
let promise = new Promise((resolve, reject) => {
this.services.device.getCapabilities((error, result) => {
this.lastError = error;
this.lastResponse = result;
if (error) {
reject(new Error('Failed to initialize the device: ' + error.toString()));
return;
}
this.onvifCompliant = 'yes'
let c = result['data']['GetCapabilitiesResponse']['Capabilities'];
if (!c) {
reject(new Error('Failed to initialize the device: No capabilities were found.'));
Expand All @@ -412,14 +465,12 @@ OnvifDevice.prototype._getCapabilities = function () {
}
let imaging = c['Imaging'];
if (imaging && imaging['XAddr']) {
/*
this.services.imaging = new mOnvifServiceImaging({
'xaddr' : imaging['XAddr'],
'time_diff': this.time_diff,
'user' : this.user,
'pass' : this.pass
});
*/
}
let media = c['Media'];
if (media && media['XAddr']) {
Expand All @@ -445,10 +496,28 @@ OnvifDevice.prototype._getCapabilities = function () {
return promise;
};

// GetVideoSources (Access Class: READ_SYSTEM)
OnvifDevice.prototype._getVideoSources = function () {
let promise = new Promise((resolve, reject) => {
this.services.media.getVideoSources((error, result) => {
this.lastError = error;
this.lastResponse = result;
if (error) {
reject(new Error('Failed to initialize the device: ' + error.toString()));
} else {
this.video_sources = result['data']['GetVideoSourcesResponse']['VideoSources'];
resolve();
}
});
});
return promise;
};
// GetDeviceInformation (Access Class: READ_SYSTEM)
OnvifDevice.prototype._getDeviceInformation = function () {
let promise = new Promise((resolve, reject) => {
this.services.device.getDeviceInformation((error, result) => {
this.lastError = error;
this.lastResponse = result;
if (error) {
reject(new Error('Failed to initialize the device: ' + error.toString()));
} else {
Expand All @@ -461,9 +530,10 @@ OnvifDevice.prototype._getDeviceInformation = function () {
};

// Media::GetProfiles (Access Class: READ_MEDIA)
OnvifDevice.prototype._mediaGetProfiles = function () {
OnvifDevice.prototype.getProfiles = function () {
let promise = new Promise((resolve, reject) => {
this.services.media.getProfiles((error, result) => {
this.lastError = error;
this.lastResponse = result;
if (error) {
reject(new Error('Failed to initialize the device: ' + error.toString()));
Expand All @@ -478,6 +548,7 @@ OnvifDevice.prototype._mediaGetProfiles = function () {
profiles.forEach((p) => {
let profile = {
'token': p['$']['token'],
'fixed': p['$']['fixed'].toLowerCase() == 'true',
'name': p['Name'],
'snapshot': '',
'stream': {
Expand Down Expand Up @@ -525,6 +596,7 @@ OnvifDevice.prototype._mediaGetProfiles = function () {
}
if (p['VideoEncoderConfiguration']) {
profile['video']['encoder'] = {
'encoding': p['VideoEncoderConfiguration']['Encoding'],
'token': p['VideoEncoderConfiguration']['$']['token'],
'name': p['VideoEncoderConfiguration']['Name'],
'resolution': {
Expand All @@ -534,7 +606,9 @@ OnvifDevice.prototype._mediaGetProfiles = function () {
'quality': parseInt(p['VideoEncoderConfiguration']['Quality'], 10),
'framerate': parseInt(p['VideoEncoderConfiguration']['RateControl']['FrameRateLimit'], 10),
'bitrate': parseInt(p['VideoEncoderConfiguration']['RateControl']['BitrateLimit'], 10),
'encoding': p['VideoEncoderConfiguration']['Encoding']
'encodinginterval': parseInt(p['VideoEncoderConfiguration']['RateControl']['EncodingInterval'], 10),
'encoding': p['VideoEncoderConfiguration']['Encoding'],
'govlength': p['VideoEncoderConfiguration']['H264'] ? parseInt(p['VideoEncoderConfiguration']['H264']['GovLength'],10) : null
};
}
if (p['AudioSourceConfiguration']) {
Expand Down Expand Up @@ -604,6 +678,7 @@ OnvifDevice.prototype._mediaGetStreamURI = function () {
'Protocol': protocol
};
this.services.media.getStreamUri(params, (error, result) => {
this.lastError = error;
this.lastResponse = result;
if (!error) {
let uri = result['data']['GetStreamUriResponse']['MediaUri']['Uri'];
Expand Down Expand Up @@ -637,6 +712,7 @@ OnvifDevice.prototype._mediaGetSnapshotUri = function () {
if (profile) {
let params = { 'ProfileToken': profile['token'] };
this.services.media.getSnapshotUri(params, (error, result) => {
this.lastError = error;
this.lastResponse = result;
if (!error) {
try {
Expand Down
2 changes: 1 addition & 1 deletion lib/modules/http-auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ OnvifHttpAuth.prototype._createAuthReqHeaderValue = function(o) {
};

OnvifHttpAuth.prototype._createCnonce = function(digit) {
let nonce = new Buffer(digit);
let nonce = Buffer.alloc(digit);
for(let i=0; i<digit; i++){
nonce.writeUInt8(Math.floor(Math.random() * 256), i);
}
Expand Down
Loading