UNPKG

camstreamerlib

Version:

Helper library for CamStreamer ACAP applications.

352 lines (351 loc) 14.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.CamSwitcherAPI = void 0; const zod_1 = require("zod"); const errors_1 = require("./errors/errors"); const utils_1 = require("./internal/utils"); const CamSwitcherAPI_1 = require("./types/CamSwitcherAPI"); const common_1 = require("./types/common"); const VapixAPI_1 = require("./VapixAPI"); const versionCompare_1 = require("./internal/versionCompare"); const constants_1 = require("./internal/constants"); const baseUrl = '/local/camswitcher/api'; class CamSwitcherAPI { client; CustomFormData; vapixAgent; constructor(client, CustomFormData = FormData) { this.client = client; this.CustomFormData = CustomFormData; this.vapixAgent = new VapixAPI_1.VapixAPI(client, () => ''); } static getProxyUrlPath = () => `${baseUrl}/proxy.cgi`; static getWsEventsUrlPath = () => `/local/camswitcher/events`; static getClipPreviewUrlPath = (id, storage) => `${baseUrl}/clip_preview.cgi?clip_name=${id}&storage=${storage}`; async generateSilence(sampleRate, channels) { await this.client.get(`${baseUrl}/generate_silence.cgi`, { sample_rate: sampleRate.toString(), channels, }); } async checkCameraTime() { const data = await this.get(`${baseUrl}/camera_time.cgi`); return zod_1.z.boolean().parse(data); } async getIpListFromNetworkCheck() { const data = await this.get(`${baseUrl}/network_camera_list.cgi`); return common_1.networkCameraListSchema.parse(data); } async getMaxFps(source) { const data = await this.get(`${baseUrl}/get_max_framerate.cgi`, { video_source: source.toString(), }); return zod_1.z.number().parse(data); } async getStorageInfo() { const data = await this.get(`${baseUrl}/get_storage.cgi`); return CamSwitcherAPI_1.storageInfoListSchema.parse(data); } async wsAuthorization() { const data = await this.get(`${baseUrl}/ws_authorization.cgi`); return zod_1.z.string().parse(data); } async getOutputInfo() { const data = await this.get(`${baseUrl}/output_info.cgi`); return CamSwitcherAPI_1.outputInfoSchema.parse(data); } async getAudioPushInfo() { const data = await this.get(`${baseUrl}/audio_push_info.cgi`); return CamSwitcherAPI_1.audioPushInfoSchema.parse(data); } async getStreamSaveList() { const data = await this.get(`${baseUrl}/streams.cgi`, { action: 'get' }); return CamSwitcherAPI_1.streamSaveLoadSchema.parse(data); } async getClipSaveList() { const data = await this.get(`${baseUrl}/clips.cgi`, { action: 'get' }); return CamSwitcherAPI_1.clipSaveLoadSchema.parse(data); } async getPlaylistSaveList() { const data = await this.get(`${baseUrl}/playlists.cgi`, { action: 'get' }); return CamSwitcherAPI_1.playlistSaveLoadSchema.parse(data); } async getTrackerSaveList() { const data = await this.get(`${baseUrl}/trackers.cgi`, { action: 'get' }); return CamSwitcherAPI_1.trackerSaveLoadSchema.parse(data); } async setStreamSaveList(data) { return await this.set(`${baseUrl}/streams.cgi`, data, { action: 'set' }); } async setClipSaveList(data) { return await this.set(`${baseUrl}/clips.cgi`, data, { action: 'set' }); } async setPlaylistSaveList(data) { return await this.set(`${baseUrl}/playlists.cgi`, data, { action: 'set' }); } async setTrackerSaveList(data) { return await this.set(`${baseUrl}/trackers.cgi`, data, { action: 'set' }); } async playlistSwitch(playlistName) { await this.get(`${baseUrl}/playlist_switch.cgi?playlist_name=${playlistName}`); } async playlistQueuePush(playlistName) { await this.get(`${baseUrl}/playlist_queue_push.cgi?playlist_name=${playlistName}`); } async playlistQueueClear() { await this.get(`${baseUrl}/playlist_queue_clear.cgi`); } async playlistQueueList() { const data = await this.get(`${baseUrl}/playlist_queue_list.cgi`); return CamSwitcherAPI_1.playlistQueueSchema.parse(data).playlistQueueList; } async playlistQueuePlayNext() { await this.get(`${baseUrl}/playlist_queue_play_next.cgi`); } async addNewClip(file, clipType, storage, id, fileName) { const formData = new this.CustomFormData(); formData.append('clip_name', id); formData.append('clip_type', clipType); formData.append('file', file, fileName); const path = `${baseUrl}/clip_upload.cgi?storage=${storage}`; const res = await this.client.post(path, formData); const output = (await res.json()); if (output.status !== 200) { throw new errors_1.AddNewClipError(output.message); } } removeClip(id, storage) { return this.get(`${baseUrl}/clip_remove.cgi`, { clip_name: id, storage }); } async getClipList() { const data = await this.get(`${baseUrl}/clip_list.cgi`); return CamSwitcherAPI_1.clipListSchema.parse(data).clip_list; } setCamSwitchOptions(data, cameraFWVersion) { const bitrateVapixParams = parseBitrateOptionsToBitrateVapixParams(cameraFWVersion, data.bitrateMode, data); const saveData = { video: { resolution: data.resolution, h264Profile: data.h264Profile, fps: data.fps, compression: data.compression, govLength: data.govLength, videoClipQuality: data.maximumBitRate, bitrateVapixParams: bitrateVapixParams, }, audio: { sampleRate: data.audioSampleRate, channelCount: data.audioChannelCount, }, keyboard: data.keyboard, }; return this.setParamFromCameraJSON(CSW_PARAM_NAMES.SETTINGS, saveData); } setGlobalAudioSettings(settings) { let acceptedType = 'NONE'; if (settings.type === 'source' && settings.source) { if ((0, utils_1.isClip)(settings.source)) { acceptedType = 'CLIP'; } else { acceptedType = 'STREAM'; } } const data = { type: acceptedType, stream_name: settings.source, clip_name: settings.source, storage: settings.storage, }; return this.setParamFromCameraJSON(CSW_PARAM_NAMES.MASTER_AUDIO, data); } setSecondaryAudioSettings(settings) { const data = { type: settings.type, stream_name: settings.streamName ?? '', clip_name: settings.clipName ?? '', storage: settings.storage, secondary_audio_level: settings.secondaryAudioLevel, master_audio_level: settings.masterAudioLevel, }; return this.setParamFromCameraJSON(CSW_PARAM_NAMES.SECONDARY_AUDIO, data); } setDefaultPlaylist(id) { const value = JSON.stringify({ default_playlist_id: id }); return this.vapixAgent.setParameter({ [CSW_PARAM_NAMES.DEFAULT_PLAYLIST]: value, }, null); } setPermanentRtspUrlToken(token) { return this.vapixAgent.setParameter({ [CSW_PARAM_NAMES.RTSP_TOKEN]: token }, null); } async getCamSwitchOptions() { const saveData = await this.getParamFromCameraAndJSONParse(CSW_PARAM_NAMES.SETTINGS); if ((0, utils_1.isNullish)(saveData.video)) { return saveData; } if (!(0, utils_1.isNullish)(saveData.video?.bitrateVapixParams)) { const bitrateOptions = parseVapixParamsToBitrateOptions(saveData.video.bitrateVapixParams); saveData.video.bitrateMode = bitrateOptions.bitrateMode; saveData.video.maximumBitRate = bitrateOptions.maximumBitRate; saveData.video.retentionTime = bitrateOptions.retentionTime; saveData.video.bitRateLimit = bitrateOptions.bitRateLimit; } if (!(0, utils_1.isNullish)(saveData.video?.bitrateLimit)) { saveData.video.maximumBitRate = saveData.video.bitrateLimit; saveData.video.bitrateMode = 'MBR'; } if (!(0, utils_1.isNullish)(saveData.video?.videoClipQuality)) { saveData.video.maximumBitRate = saveData.video.videoClipQuality; } return { ...saveData.video, audioSampleRate: saveData.audio.sampleRate, audioChannelCount: saveData.audio.channelCount, keyboard: saveData.keyboard, }; } async getGlobalAudioSettings() { const settings = { type: 'fromSource', source: 'fromSource', }; const res = await this.getParamFromCameraAndJSONParse(CSW_PARAM_NAMES.MASTER_AUDIO); if (res.type === 'STREAM') { settings.type = 'source'; settings.source = res.stream_name; } else if (res.type === 'CLIP') { settings.type = 'source'; settings.source = res.clip_name; settings.storage = res.storage; } return settings; } async getSecondaryAudioSettings() { const res = await this.getParamFromCameraAndJSONParse(CSW_PARAM_NAMES.SECONDARY_AUDIO); const settings = { type: res.type ?? 'NONE', streamName: res.stream_name, clipName: res.clip_name, storage: res.storage, secondaryAudioLevel: res.secondary_audio_level ?? 1, masterAudioLevel: res.master_audio_level ?? 1, }; return settings; } async getPermanentRtspUrlToken() { const paramName = CSW_PARAM_NAMES.RTSP_TOKEN; const res = await this.vapixAgent.getParameter([paramName], null); return res[paramName] ?? ''; } async get(path, parameters = {}) { const res = await this.client.get(path, parameters); if (res.ok) { const d = (await res.json()); return d.data; } else { throw new Error(await (0, utils_1.responseStringify)(res)); } } async set(path, data, parameters = {}) { const res = await this.client.post(path, JSON.stringify(data), parameters); if (res.ok) { const parsed = await res.json(); return parsed.message === 'OK'; } else { throw new Error(await (0, utils_1.responseStringify)(res)); } } setParamFromCameraJSON(paramName, data) { const params = {}; params[paramName] = JSON.stringify(data); return this.vapixAgent.setParameter(params, null); } async getParamFromCameraAndJSONParse(paramName) { const data = await this.vapixAgent.getParameter([paramName], null); if (data[paramName] !== undefined) { try { if (data[paramName] === '') { return {}; } else { return JSON.parse(data[paramName] + ''); } } catch { throw new Error('Error: in JSON parsing of ' + paramName + '. Cannot parse: ' + data[paramName]); } } throw new Error("Error: no parametr '" + paramName + "' was found"); } } exports.CamSwitcherAPI = CamSwitcherAPI; const CSW_PARAM_NAMES = { SETTINGS: 'Camswitcher.Settings', MASTER_AUDIO: 'Camswitcher.MasterAudio', SECONDARY_AUDIO: 'Camswitcher.SecondaryAudio', RTSP_TOKEN: 'Camswitcher.RTSPAccessToken', DEFAULT_PLAYLIST: 'Camswitcher.DefaultPlaylist', }; const parseBitrateOptionsToBitrateVapixParams = (firmWareVersion, bitrateMode, cameraOptions) => { if (!(0, versionCompare_1.isFirmwareVersionAtLeast)(firmWareVersion, constants_1.FIRMWARE_WITH_BITRATE_MODES_SUPPORT)) { return `videomaxbitrate=${cameraOptions.maximumBitRate}`; } if (bitrateMode === null) { return ''; } const data = { VBR: 'videobitratemode=vbr', MBR: `videobitratemode=mbr&videomaxbitrate=${cameraOptions.maximumBitRate}`, ABR: `videobitratemode=abr&videoabrtargetbitrate=${cameraOptions.maximumBitRate}&videoabrretentiontime=${cameraOptions.retentionTime}&videoabrmaxbitrate=${cameraOptions.bitRateLimit}`, }; return data[bitrateMode]; }; const parseVapixParamsToBitrateOptions = (bitrateVapixParams) => { const params = {}; const searchParams = new URLSearchParams(bitrateVapixParams); searchParams.forEach((value, key) => { params[key] = value; }); const bitrateMode = params['videobitratemode'] !== undefined ? params['videobitratemode'].toUpperCase() : undefined; const hasLowerFw = bitrateMode === undefined && params['videomaxbitrate'] !== undefined; if (hasLowerFw) { const maximumBitRate = parseInt(params['videomaxbitrate'] ?? '0', 10); return { bitrateMode: 'MBR', maximumBitRate: maximumBitRate, retentionTime: 1, bitRateLimit: Math.floor(maximumBitRate * 1.1), }; } if (bitrateMode === 'ABR') { const maximumBitRate = parseInt(params['videoabrtargetbitrate'] ?? '0', 10); const retentionTime = parseInt(params['videoabrretentiontime'] ?? '0', 10); const bitRateLimit = parseInt(params['videoabrmaxbitrate'] ?? '0', 10); return { bitrateMode, maximumBitRate, retentionTime, bitRateLimit, }; } else if (bitrateMode === 'MBR') { const maximumBitRate = params['videomaxbitrate'] !== undefined ? parseInt(params['videomaxbitrate'], 10) : null; const oldMaximumBitrateParamValue = parseInt(params['videombrmaxbitrate'] ?? '0', 10); return { bitrateMode: bitrateMode, maximumBitRate: maximumBitRate ?? oldMaximumBitrateParamValue, retentionTime: 1, bitRateLimit: Math.floor(maximumBitRate ?? oldMaximumBitrateParamValue * 1.1), }; } return { bitrateMode: bitrateMode, retentionTime: 1, maximumBitRate: 0, bitRateLimit: 0, }; };