Source: imaging.js

  1. /**
  2. * @namespace cam
  3. * @description Media section for Cam class
  4. * @author Andrew D.Laptev <a.d.laptev@gmail.com>
  5. * @licence MIT
  6. */
  7. module.exports = function(Cam) {
  8. const linerase = require('./utils').linerase;
  9. /**
  10. * @typedef {object} Cam~ImagingSettings
  11. * @property {number} brightness
  12. * @property {number} colorSaturation
  13. * @property {object} focus
  14. * @property {string} focus.autoFocusMode
  15. * @property {number} sharpness
  16. */
  17. /**
  18. * @callback Cam~GetImagingSettingsCallback
  19. * @property {?Error} error
  20. * @property {Cam~ImagingSettings} status
  21. */
  22. /**
  23. * Get the ImagingConfiguration for the requested VideoSource (default - the activeSource)
  24. * @param {object} [options]
  25. * @param {string} [options.token] {@link Cam#activeSource.profileToken}
  26. * @param {Cam~GetImagingSettingsCallback} callback
  27. */
  28. Cam.prototype.getImagingSettings = function(options, callback) {
  29. if (typeof callback === 'undefined') {
  30. callback = options;
  31. options = {};
  32. }
  33. this._request({
  34. service: 'imaging'
  35. , body: this._envelopeHeader() +
  36. '<GetImagingSettings xmlns="http://www.onvif.org/ver20/imaging/wsdl" >' +
  37. '<VideoSourceToken xmlns="http://www.onvif.org/ver20/imaging/wsdl" >' + ( options.token || this.activeSource.sourceToken ) + '</VideoSourceToken>' +
  38. '</GetImagingSettings>' +
  39. this._envelopeFooter()
  40. }, function(err, data, xml) {
  41. if (callback) {
  42. callback.call(this, err, err ? null : linerase(data).getImagingSettingsResponse.imagingSettings, xml);
  43. }
  44. }.bind(this));
  45. };
  46. /**
  47. * @typedef {object} Cam~ImagingSetting
  48. * @property {string} token Video source token
  49. * @property {number} brightness
  50. * @property {number} colorSaturation
  51. * @property {number} contrast
  52. * @property {object} exposure
  53. * @property {string} exposure.mode Exposure mode -enum { 'AUTO', 'MANUAL' }
  54. * @property {string} exposure.priority The exposure priority mode (low noise/framerate) -enum { 'LowNoise', 'FrameRate' }
  55. * @property {number} exposure.minExposureTime
  56. * @property {number} exposure.maxExposureTime
  57. * @property {number} exposure.minGain
  58. * @property {number} exposure.maxGain
  59. * @property {number} exposure.minIris
  60. * @property {number} exposure.maxIris
  61. * @property {number} exposure.exposureTime
  62. * @property {number} exposure.gain
  63. * @property {number} exposure.iris
  64. * @property {object} focus
  65. * @property {string} focus.autoFocusMode Mode of auto focus -enum { 'AUTO', 'MANUAL' }
  66. * @property {number} focus.defaultSpeed
  67. * @property {number} focus.nearLimit
  68. * @property {number} focus.farLimit
  69. * @property {number} sharpness
  70. * @property {string} irCutFilter Mode of ir cut filter -enum { 'AUTO', 'ON', 'OFF' }
  71. */
  72. /**
  73. * Set the ImagingConfiguration for the requested VideoSource (default - the activeSource)
  74. * @param {Cam~ImagingSetting} options
  75. * @param callback
  76. */
  77. Cam.prototype.setImagingSettings = function(options, callback) {
  78. this._request({
  79. service: 'imaging'
  80. , body: this._envelopeHeader() +
  81. '<SetImagingSettings xmlns="http://www.onvif.org/ver20/imaging/wsdl" >' +
  82. '<VideoSourceToken xmlns="http://www.onvif.org/ver20/imaging/wsdl" >' +
  83. (options.token || this.activeSource.sourceToken) +
  84. '</VideoSourceToken>' +
  85. '<ImagingSettings xmlns="http://www.onvif.org/ver20/imaging/wsdl" >' +
  86. (
  87. options.brightness ?
  88. (
  89. '<Brightness xmlns="http://www.onvif.org/ver10/schema">' +
  90. options.brightness +
  91. '</Brightness>'
  92. ) : ''
  93. )
  94. +
  95. (
  96. options.colorSaturation ?
  97. (
  98. '<ColorSaturation xmlns="http://www.onvif.org/ver10/schema">' +
  99. options.colorSaturation +
  100. '</ColorSaturation>'
  101. ) : ''
  102. )
  103. +
  104. (
  105. options.contrast ?
  106. (
  107. '<Contrast xmlns="http://www.onvif.org/ver10/schema">' +
  108. options.contrast +
  109. '</Contrast>'
  110. ) : ''
  111. )
  112. +
  113. (
  114. options.exposure ?
  115. (
  116. '<Exposure xmlns="http://www.onvif.org/ver10/schema">' +
  117. (
  118. options.exposure.mode ?
  119. (
  120. '<Mode xmlns="http://www.onvif.org/ver10/schema">' + options.exposure.mode + '</Mode>'
  121. ) : ''
  122. )
  123. +
  124. (
  125. options.exposure.priority ?
  126. (
  127. '<Priority xmlns="http://www.onvif.org/ver10/schema">' + options.exposure.priority + '</Priority>'
  128. ) : ''
  129. )
  130. +
  131. (
  132. options.exposure.minExposureTime ?
  133. (
  134. '<MinExposureTime xmlns="http://www.onvif.org/ver10/schema">' + options.exposure.minExposureTime + '</MinExposureTime>'
  135. ) : ''
  136. )
  137. +
  138. (
  139. options.exposure.maxExposureTime ?
  140. (
  141. '<MaxExposureTime xmlns="http://www.onvif.org/ver10/schema">' + options.exposure.maxExposureTime + '</MaxExposureTime>'
  142. ) : ''
  143. )
  144. +
  145. (
  146. options.exposure.minGain ?
  147. (
  148. '<MinGain xmlns="http://www.onvif.org/ver10/schema">' + options.exposure.minGain + '</MinGain>'
  149. ) : ''
  150. )
  151. +
  152. (
  153. options.exposure.maxGain ?
  154. (
  155. '<MaxGain xmlns="http://www.onvif.org/ver10/schema">' + options.exposure.maxGain + '</MaxGain>'
  156. ) : ''
  157. )
  158. +
  159. (
  160. options.exposure.minIris ?
  161. (
  162. '<MinIris xmlns="http://www.onvif.org/ver10/schema">' + options.exposure.minIris + '</MinIris>'
  163. ) : ''
  164. )
  165. +
  166. (
  167. options.exposure.maxIris ?
  168. (
  169. '<MaxIris xmlns="http://www.onvif.org/ver10/schema">' + options.exposure.maxIris + '</MaxIris>'
  170. ) : ''
  171. )
  172. +
  173. (
  174. options.exposure.exposureTime ?
  175. (
  176. '<ExposureTime xmlns="http://www.onvif.org/ver10/schema">' + options.exposure.exposureTime + '</ExposureTime>'
  177. ) : ''
  178. )
  179. +
  180. (
  181. options.exposure.gain ?
  182. (
  183. '<Gain xmlns="http://www.onvif.org/ver10/schema">' + options.exposure.gain + '</Gain>'
  184. ) : ''
  185. )
  186. +
  187. (
  188. options.exposure.iris ?
  189. (
  190. '<Iris xmlns="http://www.onvif.org/ver10/schema">' + options.exposure.iris + '</Iris>'
  191. ) : ''
  192. ) +
  193. '</Exposure>'
  194. ) : ''
  195. )
  196. +
  197. (
  198. options.focus ?
  199. (
  200. '<Focus xmlns="http://www.onvif.org/ver10/schema">' +
  201. (
  202. options.focus.autoFocusMode ?
  203. (
  204. '<AutoFocusMode xmlns="http://www.onvif.org/ver10/schema">' + options.focus.autoFocusMode + '</AutoFocusMode>'
  205. ) : ''
  206. )
  207. +
  208. (
  209. options.focus.defaultSpeed ?
  210. (
  211. '<DefaultSpeed xmlns="http://www.onvif.org/ver10/schema">' + options.focus.defaultSpeed + '</DefaultSpeed>'
  212. ) : ''
  213. )
  214. +
  215. (
  216. options.focus.nearLimit ?
  217. (
  218. '<NearLimit xmlns="http://www.onvif.org/ver10/schema">' + options.focus.nearLimit + '</NearLimit>'
  219. ) : ''
  220. )
  221. +
  222. (
  223. options.focus.farLimit ?
  224. (
  225. '<FarLimit xmlns="http://www.onvif.org/ver10/schema">' + options.focus.farLimit + '</FarLimit>'
  226. ) : ''
  227. ) +
  228. '</Focus>'
  229. ) : ''
  230. )
  231. +
  232. (
  233. options.sharpness ?
  234. (
  235. '<Sharpness xmlns="http://www.onvif.org/ver10/schema">' +
  236. options.sharpness +
  237. '</Sharpness>'
  238. ) : ''
  239. )
  240. +
  241. (
  242. options.irCutFilter ?
  243. (
  244. '<IrCutFilter xmlns="http://www.onvif.org/ver10/schema">' +
  245. options.irCutFilter +
  246. '</IrCutFilter>'
  247. ) : ''
  248. )
  249. +
  250. '</ImagingSettings>' +
  251. '</SetImagingSettings>' +
  252. this._envelopeFooter()
  253. }, function(err, data, xml) {
  254. if (callback) {
  255. callback.call(this, err, err ? null : linerase(data).setImagingSettingsResponse, xml);
  256. }
  257. }.bind(this));
  258. };
  259. /**
  260. * @typedef {object} Cam~ImagingServiceCapabilities
  261. * @property {boolean} ImageStabilization Indicates whether or not Image Stabilization feature is supported
  262. * @property {boolean} [Presets] Indicates whether or not Imaging Presets feature is supported
  263. */
  264. /**
  265. * @callback Cam~GetImagingServiceCapabilitiesCallback
  266. * @property {?Error} error
  267. * @property {Cam~ImagingServiceCapabilities} capabilities
  268. */
  269. /**
  270. * Returns the capabilities of the imaging service
  271. * @property {Cam~GetImagingServiceCapabilitiesCallback}
  272. */
  273. Cam.prototype.getImagingServiceCapabilities = function(callback) {
  274. this._request({
  275. service: 'imaging'
  276. , body: this._envelopeHeader() +
  277. '<GetServiceCapabilities xmlns="http://www.onvif.org/ver20/imaging/wsdl" >' +
  278. '</GetServiceCapabilities>' +
  279. this._envelopeFooter()
  280. }, function(err, data, xml) {
  281. if (callback) {
  282. callback.call(this, err, err ? null : linerase(data[0].getServiceCapabilitiesResponse[0].capabilities[0].$), xml);
  283. }
  284. }.bind(this));
  285. };
  286. /**
  287. * @typedef {object} Cam~ImagingPreset
  288. * @property {string} token
  289. * @property {string} type Indicates Imaging Preset Type
  290. * @property {string} Name Human readable name of the Imaging Preset
  291. */
  292. /**
  293. * @callback Cam~GetCurrentImagingPresetCallback
  294. * @property {?Error} error
  295. * @property {Cam~ImagingPreset} preset
  296. */
  297. /**
  298. * Get the last Imaging Preset applied
  299. * @param {object} [options]
  300. * @param {string} [options.token] Reference token to the VideoSource where the current Imaging Preset should be requested
  301. * @param {Cam~GetCurrentImagingPresetCallback} callback
  302. */
  303. Cam.prototype.getCurrentImagingPreset = function(options, callback) {
  304. if (typeof callback === 'undefined') {
  305. callback = options;
  306. options = {};
  307. }
  308. this._request({
  309. service: 'imaging'
  310. , body: this._envelopeHeader() +
  311. '<GetCurrentPreset xmlns="http://www.onvif.org/ver20/imaging/wsdl" >' +
  312. '<VideoSourceToken>' + (options.token || this.activeSource.sourceToken) + '</VideoSourceToken>' +
  313. '</GetCurrentPreset>' +
  314. this._envelopeFooter()
  315. }, function(err, data, xml) {
  316. if (callback) {
  317. callback.call(this, err, err ? null : linerase(data).getCurrentPresetResponse.preset, xml);
  318. }
  319. }.bind(this));
  320. };
  321. /**
  322. * Set the ImagingConfiguration for the requested or current VideoSource
  323. * @param options
  324. * @param {string} [options.token] Reference token to the VideoSource to which the specified Imaging Preset should be applied.
  325. * @param {string} options.presetToken Reference token to the Imaging Preset to be applied to the specified Video Source
  326. * @param {Cam~RequestCallback} callback
  327. */
  328. Cam.prototype.setCurrentImagingPreset = function(options, callback) {
  329. this._request({
  330. service: 'imaging'
  331. , body: this._envelopeHeader() +
  332. '<SetCurrentPreset xmlns="http://www.onvif.org/ver20/imaging/wsdl" >' +
  333. '<VideoSourceToken>' + (options.token || this.activeSource.sourceToken) + '</VideoSourceToken>' +
  334. '<PresetToken>' + options.presetToken + '</PresetToken>' +
  335. '</SetCurrentPreset>' +
  336. this._envelopeFooter()
  337. }, function(err, data, xml) {
  338. if (callback) {
  339. callback.call(this, err, err ? null : linerase(data).setCurrentPresetResponse, xml);
  340. }
  341. }.bind(this));
  342. };
  343. /**
  344. * Get the video source options for a given video source
  345. * @param {Object} options.token videoSourceToken
  346. * @param {function} [callback]
  347. */
  348. Cam.prototype.getVideoSourceOptions = function(options, callback) {
  349. if (typeof callback === 'undefined') {
  350. callback = options;
  351. options = {};
  352. }
  353. this._request({
  354. service: 'imaging'
  355. , body: this._envelopeHeader() +
  356. '<GetOptions xmlns="http://www.onvif.org/ver20/imaging/wsdl">' +
  357. '<VideoSourceToken>' + (options.token || this.activeSource.sourceToken) + '</VideoSourceToken>' +
  358. '</GetOptions>' +
  359. this._envelopeFooter()
  360. }, function(err, data, xml) {
  361. if (callback) {
  362. let jsonData = linerase(data),
  363. respData = {};
  364. if (jsonData && jsonData.getOptionsResponse && jsonData.getOptionsResponse.imagingOptions) {
  365. respData = jsonData.getOptionsResponse.imagingOptions;
  366. }
  367. // Empty response on success
  368. callback.call(this, err, respData, xml);
  369. }
  370. }.bind(this));
  371. };
  372. /**
  373. * Get the move options to be used in the focus move command for a given video source
  374. * @param {Object} options
  375. * @param {string} [options.token=Cam#activeSource.sourceToken] videoSourceToken
  376. * @param {function} [callback]
  377. */
  378. Cam.prototype.imagingGetMoveOptions = function(options, callback) {
  379. if (typeof callback === 'undefined') {
  380. callback = options;
  381. options = {};
  382. }
  383. this._request({
  384. service: 'imaging'
  385. , body: this._envelopeHeader() +
  386. '<GetMoveOptions xmlns="http://www.onvif.org/ver20/imaging/wsdl">' +
  387. '<VideoSourceToken>' + (options.token || this.activeSource.sourceToken) + '</VideoSourceToken>' +
  388. '</GetMoveOptions>' +
  389. this._envelopeFooter()
  390. }, function(err, data, xml) {
  391. if (callback) {
  392. let jsonData = linerase(data),
  393. respData = {};
  394. if (jsonData && jsonData.getMoveOptionsResponse && jsonData.getMoveOptionsResponse.moveOptions) {
  395. respData = jsonData.getMoveOptionsResponse.moveOptions;
  396. }
  397. // Empty response on success
  398. callback.call(this, err, respData, xml);
  399. }
  400. }.bind(this));
  401. };
  402. /**
  403. * Get the current status of the move operation
  404. * @param {Object} options
  405. * @param {string} [options.token=Cam#activeSource.sourceToken] videoSourceToken
  406. * @param {function} [callback]
  407. */
  408. Cam.prototype.imagingGetStatus = function(options, callback) {
  409. if (typeof callback === 'undefined') {
  410. callback = options;
  411. options = {};
  412. }
  413. this._request({
  414. service: 'imaging'
  415. , body: this._envelopeHeader() +
  416. '<GetStatus xmlns="http://www.onvif.org/ver20/imaging/wsdl">' +
  417. '<VideoSourceToken>' + (options.token || this.activeSource.sourceToken) + '</VideoSourceToken>' +
  418. '</GetStatus>' +
  419. this._envelopeFooter()
  420. }, function(err, data, xml) {
  421. if (callback) {
  422. let jsonData = linerase(data),
  423. respData = {};
  424. if (jsonData && jsonData.getStatusResponse && jsonData.getStatusResponse.status) {
  425. respData = jsonData.getStatusResponse.status;
  426. }
  427. // Empty response on success
  428. callback.call(this, err, respData, xml);
  429. }
  430. }.bind(this));
  431. };
  432. /**
  433. * The command moves the focus lens in an absolute, a relative, or in a continuous manner from its current position.
  434. * @param {object} options The supported move options are signaled via the GetMoveOptions command
  435. * @param {string} [options.token=Cam#activeSource.sourceToken] videoSourceToken
  436. * @param {object} [options.absolute] Absolute movement
  437. * @param {number} [options.absolute.position] Min and Max values defined by the GetMoveOptions if support the absolute movement
  438. * @param {number} [options.absolute.speed] If the speed argument is omitted, the default speed set by the ImagingSetting will be used.
  439. * @param {object} [options.relative] Relative movement
  440. * @param {number} [options.relative.distance] Min and Max values defined by the GetMoveOptions if support the relative movement
  441. * @param {number} [options.relative.speed] If the speed argument is omitted, the default speed set by the ImagingSetting will be used.
  442. * @param {object} [options.continuous] Continuous move until the focus lens reaches its limits or gets a stop command
  443. * @param {number} [options.continuous.speed] Min and Max values defined by the GetMoveOptions if support the continuous movement
  444. * @param callback
  445. */
  446. Cam.prototype.imagingMove = function(options, callback) {
  447. this._request({
  448. service: 'imaging'
  449. , body: this._envelopeHeader() +
  450. '<Move xmlns="http://www.onvif.org/ver20/imaging/wsdl" >' +
  451. '<VideoSourceToken xmlns="http://www.onvif.org/ver20/imaging/wsdl" >' +
  452. (options.token || this.activeSource.sourceToken) +
  453. '</VideoSourceToken>' +
  454. '<Focus xmlns="http://www.onvif.org/ver20/imaging/wsdl">' +
  455. (
  456. options.absolute ?
  457. (
  458. '<Absolute xmlns="http://www.onvif.org/ver10/schema">' +
  459. (
  460. options.absolute.position ?
  461. (
  462. '<Position xmlns="http://www.onvif.org/ver10/schema">' + options.absolute.position + '</Position>'
  463. ) : ''
  464. )
  465. +
  466. (
  467. options.absolute.speed ?
  468. (
  469. '<Speed xmlns="http://www.onvif.org/ver10/schema">' + options.absolute.speed + '</Speed>'
  470. ) : ''
  471. )
  472. + '</Absolute>'
  473. ) : ''
  474. )
  475. +
  476. (
  477. options.relative ?
  478. (
  479. '<Relative xmlns="http://www.onvif.org/ver10/schema">' +
  480. (
  481. options.relative.distance ?
  482. (
  483. '<Distance xmlns="http://www.onvif.org/ver10/schema">' + options.relative.distance + '</Distance>'
  484. ) : ''
  485. )
  486. +
  487. (
  488. options.relative.speed ?
  489. (
  490. '<Speed xmlns="http://www.onvif.org/ver10/schema">' + options.relative.speed + '</Speed>'
  491. ) : ''
  492. )
  493. + '</Relative>'
  494. ) : ''
  495. )
  496. +
  497. (
  498. options.continuous ?
  499. (
  500. '<Continuous xmlns="http://www.onvif.org/ver10/schema">' +
  501. (
  502. options.continuous.speed ?
  503. (
  504. '<Speed xmlns="http://www.onvif.org/ver10/schema">' + options.continuous.speed + '</Speed>'
  505. ) : ''
  506. )
  507. + '</Continuous>'
  508. ) : ''
  509. )
  510. +
  511. '</Focus>' +
  512. '</Move>' +
  513. this._envelopeFooter()
  514. }, function(err, data, xml) {
  515. if (callback) {
  516. callback.call(this, err, err ? null : linerase(data).MoveResponse, xml);
  517. }
  518. }.bind(this));
  519. };
  520. /**
  521. * Stop the ongoing focus movements for a given video source
  522. * @param {Object} options
  523. * @param {string} [options.token=Cam#activeSource.sourceToken] videoSourceToken
  524. * @param callback
  525. */
  526. Cam.prototype.imagingStop = function(options, callback) {
  527. this._request({
  528. service: 'imaging'
  529. , body: this._envelopeHeader() +
  530. '<Stop xmlns="http://www.onvif.org/ver20/imaging/wsdl" >' +
  531. '<VideoSourceToken xmlns="http://www.onvif.org/ver20/imaging/wsdl" >' +
  532. (options.token || this.activeSource.sourceToken) +
  533. '</VideoSourceToken>' +
  534. '</Stop>' +
  535. this._envelopeFooter()
  536. }, function(err, data, xml) {
  537. if (callback) {
  538. callback.call(this, err, err ? null : linerase(data).StopResponse, xml);
  539. }
  540. }.bind(this));
  541. };
  542. };