camstreamerlib 3.5.2 → 4.0.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/CamOverlayAPI.d.ts +11 -28
  2. package/CamOverlayAPI.js +116 -138
  3. package/CamOverlayDrawingAPI.js +26 -18
  4. package/CamOverlayPainter/Frame.js +167 -182
  5. package/CamOverlayPainter/Painter.js +80 -101
  6. package/CamOverlayPainter/ResourceManager.js +31 -46
  7. package/CamScripterAPI.d.ts +19 -0
  8. package/CamScripterAPI.js +66 -0
  9. package/CamScripterAPICameraEventsGenerator.js +22 -16
  10. package/CamStreamerAPI.d.ts +5 -27
  11. package/CamStreamerAPI.js +45 -71
  12. package/CamSwitcherAPI.d.ts +38 -71
  13. package/CamSwitcherAPI.js +329 -91
  14. package/CamSwitcherEvents.d.ts +15 -33
  15. package/CamSwitcherEvents.js +53 -97
  16. package/CreatePackage.js +5 -7
  17. package/README.md +3 -1
  18. package/VapixAPI.d.ts +66 -0
  19. package/VapixAPI.js +454 -0
  20. package/VapixEvents.js +18 -16
  21. package/errors/errors.d.ts +34 -0
  22. package/errors/errors.js +66 -0
  23. package/events/AxisCameraStationEvents.js +29 -42
  24. package/events/GenetecAgent.d.ts +14 -15
  25. package/events/GenetecAgent.js +81 -100
  26. package/internal/Digest.js +5 -11
  27. package/internal/ProxyClient.d.ts +11 -0
  28. package/internal/ProxyClient.js +40 -0
  29. package/internal/common.d.ts +19 -4
  30. package/internal/common.js +11 -26
  31. package/internal/constants.d.ts +1 -0
  32. package/internal/constants.js +1 -0
  33. package/internal/transformers.d.ts +5 -0
  34. package/internal/transformers.js +25 -0
  35. package/internal/utils.d.ts +11 -0
  36. package/internal/utils.js +34 -0
  37. package/internal/versionCompare.d.ts +6 -0
  38. package/internal/versionCompare.js +44 -0
  39. package/node/DefaultClient.d.ts +15 -0
  40. package/node/DefaultClient.js +50 -0
  41. package/{internal → node}/HttpRequestSender.d.ts +2 -2
  42. package/node/HttpRequestSender.js +85 -0
  43. package/{HttpServer.d.ts → node/HttpServer.d.ts} +1 -1
  44. package/{HttpServer.js → node/HttpServer.js} +22 -24
  45. package/{internal → node}/WsClient.d.ts +1 -1
  46. package/{internal → node}/WsClient.js +32 -39
  47. package/node/WsEventClient.d.ts +13 -0
  48. package/node/WsEventClient.js +18 -0
  49. package/package.json +7 -3
  50. package/types/CamOverlayAPI.d.ts +188 -0
  51. package/types/CamOverlayAPI.js +44 -0
  52. package/types/CamScripterAPI.d.ts +67 -0
  53. package/types/CamScripterAPI.js +17 -0
  54. package/types/CamStreamerAPI.d.ts +139 -0
  55. package/types/CamStreamerAPI.js +25 -0
  56. package/types/CamSwitcherAPI.d.ts +814 -0
  57. package/types/CamSwitcherAPI.js +134 -0
  58. package/types/CamswitcherEvents.d.ts +491 -0
  59. package/types/CamswitcherEvents.js +59 -0
  60. package/types/VapixAPI.d.ts +1704 -0
  61. package/types/VapixAPI.js +129 -0
  62. package/types/common.d.ts +37 -0
  63. package/types/common.js +11 -0
  64. package/web/DefaultClient.d.ts +6 -0
  65. package/web/DefaultClient.js +16 -0
  66. package/web/WsClient.d.ts +13 -0
  67. package/web/WsClient.js +58 -0
  68. package/CameraVapix.d.ts +0 -98
  69. package/CameraVapix.js +0 -441
  70. package/DefaultAgent.d.ts +0 -15
  71. package/DefaultAgent.js +0 -68
  72. package/internal/HttpRequestSender.js +0 -117
package/CamSwitcherAPI.js CHANGED
@@ -1,112 +1,350 @@
1
- "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
- Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.CamSwitcherAPI = void 0;
13
- const DefaultAgent_1 = require("./DefaultAgent");
14
- const common_1 = require("./internal/common");
15
- const cgiNames = {
16
- camera: 'streams',
17
- audio: 'audios',
18
- playlist: 'playlists',
19
- clip: 'clips',
20
- tracker: 'trackers',
21
- };
22
- class CamSwitcherAPI {
23
- constructor(options = {}) {
24
- if ((0, common_1.isClient)(options)) {
25
- this.client = options;
26
- }
27
- else {
28
- this.client = new DefaultAgent_1.DefaultAgent(options);
29
- }
30
- }
31
- generateSilence(sampleRate, channels) {
32
- return this.get('/local/camswitcher/generate_silence.cgi', { sample_rate: sampleRate.toString(), channels });
1
+ import { z } from 'zod';
2
+ import { AddNewClipError } from './errors/errors';
3
+ import { isNullish, responseStringify } from './internal/common';
4
+ import { storageInfoListSchema, outputInfoSchema, audioPushInfoSchema, clipListSchema, playlistQueueSchema, streamSaveLoadSchema, clipSaveLoadSchema, playlistSaveLoadSchema, trackerSaveLoadSchema, } from './types/CamSwitcherAPI';
5
+ import { networkCameraListSchema } from './types/common';
6
+ import { VapixAPI } from './VapixAPI';
7
+ import { isFirmwareVersionAtLeast } from './internal/versionCompare';
8
+ import { isClip } from './internal/utils';
9
+ import { FIRMWARE_WITH_BITRATE_MODES_SUPPORT } from './internal/constants';
10
+ const baseUrl = '/local/camswitcher/api';
11
+ export class CamSwitcherAPI {
12
+ client;
13
+ vapixAgent;
14
+ constructor(client) {
15
+ this.client = client;
16
+ this.vapixAgent = new VapixAPI(client, () => '');
33
17
  }
34
- getIpListFromNetworkCheck() {
35
- return __awaiter(this, void 0, void 0, function* () {
36
- return (yield this.get('/local/camswitcher/network_camera_list.cgi')).data;
18
+ static getProxyUrl = () => `${baseUrl}/proxy.cgi`;
19
+ static getWsEventsUrl = () => `/local/camswitcher/events`;
20
+ static getClipPreview = (id, storage) => `${baseUrl}/clip_preview.cgi?clip_name=${id}&storage=${storage}`;
21
+ async generateSilence(sampleRate, channels) {
22
+ await this.client.get(`${baseUrl}/generate_silence.cgi`, {
23
+ sample_rate: sampleRate.toString(),
24
+ channels,
37
25
  });
38
26
  }
39
- getMaxFps(source) {
40
- return __awaiter(this, void 0, void 0, function* () {
41
- return (yield this.get('/local/camswitcher/get_max_framerate.cgi', { video_source: source.toString() })).data;
42
- });
27
+ async checkCameraTime() {
28
+ const data = await this.get(`${baseUrl}/camera_time.cgi`);
29
+ return z.boolean().parse(data);
43
30
  }
44
- getStorageInfo() {
45
- return __awaiter(this, void 0, void 0, function* () {
46
- return (yield this.get('/local/camswitcher/get_storage.cgi')).data;
47
- });
31
+ async getIpListFromNetworkCheck() {
32
+ const data = await this.get(`${baseUrl}/network_camera_list.cgi`);
33
+ return networkCameraListSchema.parse(data);
48
34
  }
49
- getOutputInfo() {
50
- return __awaiter(this, void 0, void 0, function* () {
51
- return (yield this.get('/local/camswitcher/output_info.cgi')).data;
35
+ async getMaxFps(source) {
36
+ const data = await this.get(`${baseUrl}/get_max_framerate.cgi`, {
37
+ video_source: source.toString(),
52
38
  });
39
+ return z.number().parse(data);
53
40
  }
54
- getPlaylistList() {
55
- return this.get('/local/camswitcher/playlists.cgi?action=get');
41
+ async getStorageInfo() {
42
+ const data = await this.get(`${baseUrl}/get_storage.cgi`);
43
+ return storageInfoListSchema.parse(data);
56
44
  }
57
- playlistSwitch(playlistName) {
58
- return __awaiter(this, void 0, void 0, function* () {
59
- yield this.get(`/local/camswitcher/playlist_switch.cgi?playlist_name=${playlistName}`);
60
- });
45
+ async wsAuthorization() {
46
+ const data = await this.get(`${baseUrl}/ws_authorization.cgi`);
47
+ return z.string().parse(data);
61
48
  }
62
- playlistQueuePush(playlistName) {
63
- return __awaiter(this, void 0, void 0, function* () {
64
- yield this.get(`/local/camswitcher/playlist_queue_push.cgi?playlist_name=${playlistName}`);
65
- });
49
+ async getOutputInfo() {
50
+ const data = await this.get(`${baseUrl}/output_info.cgi`);
51
+ return outputInfoSchema.parse(data);
66
52
  }
67
- playlistQueueClear() {
68
- return __awaiter(this, void 0, void 0, function* () {
69
- yield this.get('/local/camswitcher/playlist_queue_clear.cgi');
70
- });
53
+ async getAudioPushInfo() {
54
+ const data = await this.get(`${baseUrl}/audio_push_info.cgi`);
55
+ return audioPushInfoSchema.parse(data);
71
56
  }
72
- playlistQueueList() {
73
- return this.get('/local/camswitcher/playlist_queue_list.cgi');
57
+ async getStreamSaveList() {
58
+ const data = await this.get(`${baseUrl}/streams.cgi`, { action: 'get' });
59
+ return streamSaveLoadSchema.parse(data);
74
60
  }
75
- playlistQueuePlayNext() {
76
- return __awaiter(this, void 0, void 0, function* () {
77
- yield this.get('/local/camswitcher/playlist_queue_play_next.cgi');
78
- });
61
+ async getClipSaveList() {
62
+ const data = await this.get(`${baseUrl}/clips.cgi`, { action: 'get' });
63
+ return clipSaveLoadSchema.parse(data);
79
64
  }
80
- getClipList() {
81
- return this.get('/local/camswitcher/clips.cgi?action=get');
82
- }
83
- addNewClip(file, clipType, storage, id, fileName) {
84
- return __awaiter(this, void 0, void 0, function* () {
85
- const formData = new FormData();
86
- formData.append('clip_name', id);
87
- formData.append('clip_type', clipType);
88
- formData.append('file', file, fileName);
89
- const path = `/local/camswitcher/clip_upload.cgi?storage=${storage}`;
90
- const res = yield this.client.post(path, formData);
91
- const output = (yield res.json());
92
- if (output.status !== 200) {
93
- throw new Error('Error on camera: ' + output.message);
94
- }
95
- });
65
+ async getPlaylistSaveList() {
66
+ const data = await this.get(`${baseUrl}/playlists.cgi`, { action: 'get' });
67
+ return playlistSaveLoadSchema.parse(data);
68
+ }
69
+ async getTrackerSaveList() {
70
+ const data = await this.get(`${baseUrl}/trackers.cgi`, { action: 'get' });
71
+ return trackerSaveLoadSchema.parse(data);
72
+ }
73
+ async setStreamSaveList(data) {
74
+ return await this.set(`${baseUrl}/streams.cgi`, data, { action: 'set' });
75
+ }
76
+ async setClipSaveList(data) {
77
+ return await this.set(`${baseUrl}/clips.cgi`, data, { action: 'set' });
78
+ }
79
+ async setPlaylistSaveList(data) {
80
+ return await this.set(`${baseUrl}/playlists.cgi`, data, { action: 'set' });
81
+ }
82
+ async setTrackerSaveList(data) {
83
+ return await this.set(`${baseUrl}/trackers.cgi`, data, { action: 'set' });
84
+ }
85
+ async playlistSwitch(playlistName) {
86
+ await this.get(`${baseUrl}/playlist_switch.cgi?playlist_name=${playlistName}`);
87
+ }
88
+ async playlistQueuePush(playlistName) {
89
+ await this.get(`${baseUrl}/playlist_queue_push.cgi?playlist_name=${playlistName}`);
90
+ }
91
+ async playlistQueueClear() {
92
+ await this.get(`${baseUrl}/playlist_queue_clear.cgi`);
93
+ }
94
+ async playlistQueueList() {
95
+ const data = await this.get(`${baseUrl}/playlist_queue_list.cgi`);
96
+ return playlistQueueSchema.parse(data).playlistQueueList;
97
+ }
98
+ async playlistQueuePlayNext() {
99
+ await this.get(`${baseUrl}/playlist_queue_play_next.cgi`);
100
+ }
101
+ async addNewClip(file, clipType, storage, id, fileName) {
102
+ const formData = new FormData();
103
+ formData.append('clip_name', id);
104
+ formData.append('clip_type', clipType);
105
+ formData.append('file', file, fileName);
106
+ const path = `${baseUrl}/clip_upload.cgi?storage=${storage}`;
107
+ const res = await this.client.post(path, formData);
108
+ const output = (await res.json());
109
+ if (output.status !== 200) {
110
+ throw new AddNewClipError(output.message);
111
+ }
96
112
  }
97
113
  removeClip(id, storage) {
98
- return this.get(`/local/camswitcher/clip_remove.cgi`, { clip_name: id, storage });
114
+ return this.get(`${baseUrl}/clip_remove.cgi`, { clip_name: id, storage });
99
115
  }
100
- get(path, parameters = {}) {
101
- return __awaiter(this, void 0, void 0, function* () {
102
- const res = yield this.client.get(path, parameters);
103
- if (res.ok) {
104
- return yield res.json();
116
+ async getClipList() {
117
+ const data = await this.get(`${baseUrl}/clip_list.cgi`);
118
+ return clipListSchema.parse(data).clip_list;
119
+ }
120
+ setCamSwitchOptions(data, cameraFWVersion) {
121
+ const bitrateVapixParams = parseBitrateOptionsToBitrateVapixParams(cameraFWVersion, data.bitrateMode, data);
122
+ const saveData = {
123
+ video: {
124
+ resolution: data.resolution,
125
+ h264Profile: data.h264Profile,
126
+ fps: data.fps,
127
+ compression: data.compression,
128
+ govLength: data.govLength,
129
+ videoClipQuality: data.maximumBitRate,
130
+ bitrateVapixParams: bitrateVapixParams,
131
+ },
132
+ audio: {
133
+ sampleRate: data.audioSampleRate,
134
+ channelCount: data.audioChannelCount,
135
+ },
136
+ keyboard: data.keyboard,
137
+ };
138
+ return this.setParamFromCameraJSON(CSW_PARAM_NAMES.SETTINGS, saveData);
139
+ }
140
+ setGlobalAudioSettings(settings) {
141
+ let acceptedType = 'NONE';
142
+ if (settings.type === 'source' && settings.source) {
143
+ if (isClip(settings.source)) {
144
+ acceptedType = 'CLIP';
105
145
  }
106
146
  else {
107
- throw new Error(yield (0, common_1.responseStringify)(res));
147
+ acceptedType = 'STREAM';
108
148
  }
109
- });
149
+ }
150
+ const data = {
151
+ type: acceptedType,
152
+ stream_name: settings.source,
153
+ clip_name: settings.source,
154
+ storage: settings.storage,
155
+ };
156
+ return this.setParamFromCameraJSON(CSW_PARAM_NAMES.MASTER_AUDIO, data);
157
+ }
158
+ setSecondaryAudioSettings(settings) {
159
+ const data = {
160
+ type: settings.type,
161
+ stream_name: settings.streamName ?? '',
162
+ clip_name: settings.clipName ?? '',
163
+ storage: settings.storage,
164
+ secondary_audio_level: settings.secondaryAudioLevel,
165
+ master_audio_level: settings.masterAudioLevel,
166
+ };
167
+ return this.setParamFromCameraJSON(CSW_PARAM_NAMES.SECONDARY_AUDIO, data);
168
+ }
169
+ setDefaultPlaylist(id) {
170
+ const value = JSON.stringify({ default_playlist_id: id });
171
+ return this.vapixAgent.setParameter({
172
+ [CSW_PARAM_NAMES.DEFAULT_PLAYLIST]: value,
173
+ }, null);
174
+ }
175
+ setPermanentRtspUrlToken(token) {
176
+ return this.vapixAgent.setParameter({ [CSW_PARAM_NAMES.RTSP_TOKEN]: token }, null);
177
+ }
178
+ async getCamSwitchOptions() {
179
+ const saveData = await this.getParamFromCameraAndJSONParse(CSW_PARAM_NAMES.SETTINGS);
180
+ if (isNullish(saveData.video)) {
181
+ return saveData;
182
+ }
183
+ if (!isNullish(saveData.video?.bitrateVapixParams)) {
184
+ const bitrateOptions = parseVapixParamsToBitrateOptions(saveData.video.bitrateVapixParams);
185
+ saveData.video.bitrateMode = bitrateOptions.bitrateMode;
186
+ saveData.video.maximumBitRate = bitrateOptions.maximumBitRate;
187
+ saveData.video.retentionTime = bitrateOptions.retentionTime;
188
+ saveData.video.bitRateLimit = bitrateOptions.bitRateLimit;
189
+ }
190
+ if (!isNullish(saveData.video?.bitrateLimit)) {
191
+ saveData.video.maximumBitRate = saveData.video.bitrateLimit;
192
+ saveData.video.bitrateMode = 'MBR';
193
+ }
194
+ if (!isNullish(saveData.video?.videoClipQuality)) {
195
+ saveData.video.maximumBitRate = saveData.video.videoClipQuality;
196
+ }
197
+ return {
198
+ ...saveData.video,
199
+ audioSampleRate: saveData.audio.sampleRate,
200
+ audioChannelCount: saveData.audio.channelCount,
201
+ keyboard: saveData.keyboard,
202
+ };
203
+ }
204
+ async getGlobalAudioSettings() {
205
+ const settings = {
206
+ type: 'fromSource',
207
+ source: 'fromSource',
208
+ };
209
+ const res = await this.getParamFromCameraAndJSONParse(CSW_PARAM_NAMES.MASTER_AUDIO);
210
+ if (res.type === 'STREAM') {
211
+ settings.type = 'source';
212
+ settings.source = res.stream_name;
213
+ }
214
+ else if (res.type === 'CLIP') {
215
+ settings.type = 'source';
216
+ settings.source = res.clip_name;
217
+ settings.storage = res.storage;
218
+ }
219
+ return settings;
220
+ }
221
+ async getSecondaryAudioSettings() {
222
+ const res = await this.getParamFromCameraAndJSONParse(CSW_PARAM_NAMES.SECONDARY_AUDIO);
223
+ const settings = {
224
+ type: res.type ?? 'NONE',
225
+ streamName: res.stream_name,
226
+ clipName: res.clip_name,
227
+ storage: res.storage,
228
+ secondaryAudioLevel: res.secondary_audio_level ?? 1,
229
+ masterAudioLevel: res.master_audio_level ?? 1,
230
+ };
231
+ return settings;
232
+ }
233
+ async getPermanentRtspUrlToken() {
234
+ const paramName = CSW_PARAM_NAMES.RTSP_TOKEN;
235
+ const res = await this.vapixAgent.getParameter([paramName], null);
236
+ return res[paramName] ?? '';
237
+ }
238
+ async get(path, parameters = {}) {
239
+ const res = await this.client.get(path, parameters);
240
+ if (res.ok) {
241
+ const d = (await res.json());
242
+ return d.data;
243
+ }
244
+ else {
245
+ throw new Error(await responseStringify(res));
246
+ }
247
+ }
248
+ async set(path, data, parameters = {}) {
249
+ const res = await this.client.post(path, JSON.stringify(data), parameters);
250
+ if (res.ok) {
251
+ const parsed = await res.json();
252
+ return parsed.message === 'OK';
253
+ }
254
+ else {
255
+ throw new Error(await responseStringify(res));
256
+ }
257
+ }
258
+ setParamFromCameraJSON(paramName, data) {
259
+ const params = {};
260
+ params[paramName] = JSON.stringify(data);
261
+ return this.vapixAgent.setParameter(params, null);
262
+ }
263
+ async getParamFromCameraAndJSONParse(paramName) {
264
+ const data = await this.vapixAgent.getParameter([paramName], null);
265
+ if (data[paramName] !== undefined) {
266
+ try {
267
+ if (data[paramName] === '') {
268
+ return {};
269
+ }
270
+ else {
271
+ return JSON.parse(data[paramName] + '');
272
+ }
273
+ }
274
+ catch {
275
+ throw new Error('Error: in JSON parsing of ' + paramName + '. Cannot parse: ' + data[paramName]);
276
+ }
277
+ }
278
+ throw new Error("Error: no parametr '" + paramName + "' was found");
110
279
  }
111
280
  }
112
- exports.CamSwitcherAPI = CamSwitcherAPI;
281
+ const CSW_PARAM_NAMES = {
282
+ SETTINGS: 'Camswitcher.Settings',
283
+ MASTER_AUDIO: 'Camswitcher.MasterAudio',
284
+ SECONDARY_AUDIO: 'Camswitcher.SecondaryAudio',
285
+ RTSP_TOKEN: 'Camswitcher.RTSPAccessToken',
286
+ DEFAULT_PLAYLIST: 'Camswitcher.DefaultPlaylist',
287
+ };
288
+ const parseBitrateOptionsToBitrateVapixParams = (firmWareVersion, bitrateMode, cameraOptions) => {
289
+ if (!isFirmwareVersionAtLeast(firmWareVersion, FIRMWARE_WITH_BITRATE_MODES_SUPPORT)) {
290
+ return `videomaxbitrate=${cameraOptions.maximumBitRate}`;
291
+ }
292
+ if (bitrateMode === null) {
293
+ return '';
294
+ }
295
+ if (bitrateMode === 'VBR') {
296
+ return 'videobitratemode=vbr';
297
+ }
298
+ if (bitrateMode === 'MBR') {
299
+ return `videobitratemode=mbr&videomaxbitrate=${cameraOptions.maximumBitRate}`;
300
+ }
301
+ if (bitrateMode === 'ABR') {
302
+ return `videobitratemode=abr&videoabrtargetbitrate=${cameraOptions.maximumBitRate}&videoabrretentiontime=${cameraOptions.retentionTime}&videoabrmaxbitrate=${cameraOptions.bitRateLimit}`;
303
+ }
304
+ throw new Error('Unknown bitrateMode param in getVapixParams method.');
305
+ };
306
+ const parseVapixParamsToBitrateOptions = (bitrateVapixParams) => {
307
+ const params = {};
308
+ const searchParams = new URLSearchParams(bitrateVapixParams);
309
+ searchParams.forEach((value, key) => {
310
+ params[key] = value;
311
+ });
312
+ const bitrateMode = params['videobitratemode'] !== undefined ? params['videobitratemode'].toUpperCase() : undefined;
313
+ const hasLowerFw = bitrateMode === undefined && params['videomaxbitrate'] !== undefined;
314
+ if (hasLowerFw) {
315
+ const maximumBitRate = parseInt(params['videomaxbitrate'], 10);
316
+ return {
317
+ bitrateMode: 'MBR',
318
+ maximumBitRate: maximumBitRate,
319
+ retentionTime: 1,
320
+ bitRateLimit: Math.floor(maximumBitRate * 1.1),
321
+ };
322
+ }
323
+ if (bitrateMode === 'ABR') {
324
+ const maximumBitRate = parseInt(params['videoabrtargetbitrate'], 10);
325
+ const retentionTime = parseInt(params['videoabrretentiontime'], 10);
326
+ const bitrateLimit = parseInt(params['videoabrmaxbitrate'], 10);
327
+ return {
328
+ bitrateMode: bitrateMode,
329
+ maximumBitRate: maximumBitRate,
330
+ retentionTime: retentionTime,
331
+ bitRateLimit: bitrateLimit,
332
+ };
333
+ }
334
+ else if (bitrateMode === 'MBR') {
335
+ const maximumBitRate = parseInt(params['videomaxbitrate'], 10);
336
+ const oldMaximumBitrateParamValue = parseInt(params['videombrmaxbitrate'], 10);
337
+ return {
338
+ bitrateMode: bitrateMode,
339
+ maximumBitRate: maximumBitRate ?? oldMaximumBitrateParamValue,
340
+ retentionTime: 1,
341
+ bitRateLimit: Math.floor(maximumBitRate ?? oldMaximumBitrateParamValue * 1.1),
342
+ };
343
+ }
344
+ return {
345
+ bitrateMode: bitrateMode,
346
+ retentionTime: 1,
347
+ maximumBitRate: 0,
348
+ bitRateLimit: 0,
349
+ };
350
+ };
@@ -1,36 +1,18 @@
1
- /// <reference types="node" />
2
- import * as EventEmitter from 'events';
3
- import { HttpOptions } from './internal/common';
4
- export type CamSwitcherEventsOptions = HttpOptions;
5
- export type TEvent = {
6
- type: string;
7
- date: Record<string, string | number | boolean> & {
8
- type: string;
9
- };
10
- };
11
- export interface CamSwitcherEvents {
12
- on(event: 'open', listener: () => void): this;
13
- on(event: 'close', listener: () => void): this;
14
- on(event: 'event', listener: (data: TEvent) => void): this;
15
- on(event: 'error', listener: (err: Error) => void): this;
16
- emit(event: 'open'): boolean;
17
- emit(event: 'close'): boolean;
18
- emit(event: 'event', data: TEvent): boolean;
19
- emit(event: 'error', err: Error): boolean;
20
- }
21
- export declare class CamSwitcherEvents extends EventEmitter {
22
- private tls;
23
- private tlsInsecure;
24
- private ip;
25
- private port;
26
- private user;
27
- private pass;
28
- private client;
1
+ import { IWebsocket } from './internal/common';
2
+ import { TCamSwitcherEventOfType, TCamSwitcherEventType } from './types/CamswitcherEvents';
3
+ type TListenerFunction<T extends TCamSwitcherEventType> = (data: TCamSwitcherEventOfType<T>, isInit: boolean) => void;
4
+ export declare class CamSwitcherEvents<Event extends {
5
+ data: string;
6
+ }> {
7
+ isDestroyed: boolean;
29
8
  private ws;
30
- constructor(options?: CamSwitcherEventsOptions);
31
- connect(): void;
32
- disconnect(): void;
9
+ private listeners;
10
+ setWebsocket(ws: IWebsocket<Event>): void;
33
11
  resendInitData(): void;
34
- private createWsClient;
35
- private get;
12
+ addListener<T extends TCamSwitcherEventType>(type: T, listener: TListenerFunction<T>, id: string): void;
13
+ removeListener<T extends TCamSwitcherEventType>(type: T, id: string): void;
14
+ private onMessage;
15
+ private processMessage;
16
+ destroy(): void;
36
17
  }
18
+ export {};
@@ -1,107 +1,63 @@
1
- "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
- Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.CamSwitcherEvents = void 0;
13
- const EventEmitter = require("events");
14
- const WsClient_1 = require("./internal/WsClient");
15
- const DefaultAgent_1 = require("./DefaultAgent");
16
- class CamSwitcherEvents extends EventEmitter {
17
- constructor(options = {}) {
18
- var _a, _b, _c, _d, _e, _f;
19
- super();
20
- this.tls = (_a = options.tls) !== null && _a !== void 0 ? _a : false;
21
- this.tlsInsecure = (_b = options.tlsInsecure) !== null && _b !== void 0 ? _b : false;
22
- this.ip = (_c = options.ip) !== null && _c !== void 0 ? _c : '127.0.0.1';
23
- this.port = (_d = options.port) !== null && _d !== void 0 ? _d : (this.tls ? 443 : 80);
24
- this.user = (_e = options.user) !== null && _e !== void 0 ? _e : 'root';
25
- this.pass = (_f = options.pass) !== null && _f !== void 0 ? _f : '';
26
- this.client = new DefaultAgent_1.DefaultAgent(options);
27
- this.createWsClient();
28
- EventEmitter.call(this);
29
- }
30
- connect() {
31
- this.ws.open();
32
- }
33
- disconnect() {
34
- this.ws.close();
1
+ import { cswEventsSchema, } from './types/CamswitcherEvents';
2
+ export class CamSwitcherEvents {
3
+ isDestroyed = false;
4
+ ws = null;
5
+ listeners = {};
6
+ setWebsocket(ws) {
7
+ if (this.ws) {
8
+ this.ws.destroy();
9
+ }
10
+ this.ws = ws;
11
+ this.ws.onmessage = (e) => this.onMessage(e);
35
12
  }
36
13
  resendInitData() {
37
14
  const request = {
38
15
  command: 'sendInitData',
39
16
  };
40
- this.ws.send(JSON.stringify(request));
17
+ this.ws?.send(JSON.stringify(request));
41
18
  }
42
- createWsClient() {
43
- const options = {
44
- ip: this.ip,
45
- port: this.port,
46
- user: this.user,
47
- pass: this.pass,
48
- tls: this.tls,
49
- tlsInsecure: this.tlsInsecure,
50
- address: '/local/camswitcher/events',
51
- protocol: 'events',
52
- };
53
- this.ws = new WsClient_1.WsClient(options);
54
- this.ws.on('open', () => __awaiter(this, void 0, void 0, function* () {
55
- try {
56
- const token = yield this.get('/local/camswitcher/ws_authorization.cgi');
57
- this.ws.send(JSON.stringify({ authorization: token }));
58
- }
59
- catch (err) {
60
- this.emit('error', err);
61
- }
62
- }));
63
- this.ws.on('message', (data) => {
64
- try {
65
- const parsedData = JSON.parse(data.toString());
66
- if (parsedData.type === 'authorization') {
67
- if (parsedData.state === 'OK') {
68
- this.emit('open');
69
- }
70
- else {
71
- this.emit('error', new Error(data.toString()));
72
- }
73
- }
74
- else {
75
- this.emit('event', parsedData);
76
- }
77
- }
78
- catch (err) {
79
- this.emit('error', err);
80
- }
81
- });
82
- this.ws.on('error', (err) => {
83
- this.emit('error', err);
84
- });
85
- this.ws.on('close', () => {
86
- this.emit('close');
87
- });
19
+ addListener(type, listener, id) {
20
+ const typeList = this.listeners[type];
21
+ if (typeList === undefined) {
22
+ this.listeners[type] = { [id]: listener };
23
+ return;
24
+ }
25
+ typeList[id] = listener;
88
26
  }
89
- get(path) {
90
- return __awaiter(this, void 0, void 0, function* () {
91
- const res = yield this.client.get(path);
92
- if (res.ok) {
93
- const responseText = JSON.parse(yield res.text());
94
- if (responseText.status === 200) {
95
- return responseText.data;
96
- }
97
- else {
98
- throw new Error(`Request (${path}) error, response: ${JSON.stringify(responseText)}`);
99
- }
100
- }
101
- else {
102
- throw new Error(JSON.stringify(res));
27
+ removeListener(type, id) {
28
+ const typeList = this.listeners[type];
29
+ if (typeList) {
30
+ delete typeList[id];
31
+ }
32
+ }
33
+ onMessage(evt) {
34
+ if (this.isDestroyed) {
35
+ return;
36
+ }
37
+ try {
38
+ const eventData = JSON.parse(evt.data);
39
+ const data = cswEventsSchema.parse(eventData);
40
+ if (data.type === 'init') {
41
+ this.processMessage(data.data, true);
42
+ return;
103
43
  }
104
- });
44
+ this.processMessage(data, false);
45
+ }
46
+ catch (error) {
47
+ console.error('Error parsing event data:', evt.data, error);
48
+ }
49
+ }
50
+ processMessage(event, isInit) {
51
+ const listeners = this.listeners[event.type];
52
+ const list = Object.values(listeners ?? {});
53
+ list.forEach((listener) => listener(event, isInit));
54
+ }
55
+ destroy() {
56
+ this.isDestroyed = true;
57
+ if (this.ws) {
58
+ this.ws.destroy();
59
+ this.ws = null;
60
+ }
61
+ this.listeners = {};
105
62
  }
106
63
  }
107
- exports.CamSwitcherEvents = CamSwitcherEvents;