camstreamerlib
Version:
Helper library for CamStreamer ACAP applications.
173 lines (172 loc) • 8.48 kB
JavaScript
import { z } from 'zod';
import { audioFileListSchema, diagnosticsSchema, srtStreamStatisticsSchema, storageListSchema, streamSchema, streamStatsSchema, } from './types/CamStreamerAPI/CamStreamerAPI';
import { UtcTimeFetchError, WsAuthorizationError, MigrationError } from './errors/errors';
import { oldStringStreamSchema, oldStringStreamSchemaWithId, } from './types/CamStreamerAPI/oldStreamSchema';
import { BasicAPI } from './internal/BasicAPI';
import { streamPlatforms } from './types/CamStreamerAPI';
const BASE_PATH = '/local/camstreamer';
export class CamStreamerAPI extends BasicAPI {
static getProxyPath = () => `${BASE_PATH}/proxy.cgi`;
static getWsEventsPath = () => `${BASE_PATH}/events`;
async checkAPIAvailable(options) {
await this._getJson(`${BASE_PATH}/api_check.cgi`, undefined, options);
}
async wsAuthorization(options) {
const res = await this._getJson(`${BASE_PATH}/ws_authorization.cgi`, undefined, options);
if (res.status !== 200) {
throw new WsAuthorizationError(res.message);
}
return z.string().parse(res.data);
}
async getUtcTime(options) {
const res = await this._getJson(`${BASE_PATH}/get_utc_time.cgi`, undefined, options);
if (res.status !== 200) {
throw new UtcTimeFetchError(res.message);
}
return z.number().parse(res.data);
}
async getMaxFps(source = 0, options) {
return await this._getJson(`${BASE_PATH}/get_max_framerate.cgi`, { video_source: source.toString() }, options);
}
async isCSPassValid(pass, options) {
const res = await this._getJson(`${BASE_PATH}/check_pass.cgi`, { pass }, options);
return res.data === '1';
}
async getCamStreamerAppLog(options) {
return await this._getText(`${BASE_PATH}/view_log.cgi`, undefined, options);
}
async getStreamList(options) {
const res = await this._getJson(`${BASE_PATH}/stream_list.cgi`, { action: 'get' }, options);
const oldStreamListRecord = z.record(z.string(), oldStringStreamSchema).safeParse(res.data);
if (oldStreamListRecord.success) {
const data = Object.entries(oldStreamListRecord.data).map(([streamId, streamData]) => ({
streamId,
...parseCameraStreamResponse(streamData),
}));
throw new MigrationError([], data, [], []);
}
const newStreamData = [];
const unknownStreamData = [];
const oldStreamData = [];
const invalidStreamData = [];
for (const streamData of res.data.streamList) {
if (streamData.platform !== undefined && !Object.values(streamPlatforms).includes(streamData.platform)) {
unknownStreamData.push(streamData);
continue;
}
const newStreamParse = streamSchema.safeParse(streamData);
if (newStreamParse.success) {
newStreamData.push(newStreamParse.data);
continue;
}
const oldStreamParse = oldStringStreamSchemaWithId.safeParse(streamData);
if (oldStreamParse.success) {
oldStreamData.push({
streamId: oldStreamParse.data.streamId,
...parseCameraStreamResponse(oldStreamParse.data),
});
continue;
}
invalidStreamData.push(streamData);
}
if (oldStreamData.length > 0 || invalidStreamData.length > 0) {
throw new MigrationError(newStreamData, oldStreamData, invalidStreamData, unknownStreamData);
}
return [...newStreamData, ...unknownStreamData];
}
async setStreamList(streamList, options) {
await this._postJsonEncoded(`${BASE_PATH}/stream_list.cgi`, { streamList }, {
action: 'set',
}, options);
}
async getStream(streamId, options) {
const res = await this._getJson(`${BASE_PATH}/stream_list.cgi`, { action: 'get', stream_id: streamId }, options);
const newStream = streamSchema.safeParse(res.data);
if (newStream.success) {
return newStream.data;
}
const oldStream = oldStringStreamSchema.passthrough().parse(res.data);
throw new MigrationError([], [{ streamId, ...parseCameraStreamResponse(oldStream) }], [], []);
}
async setStream(streamId, streamData, options) {
await this._postJsonEncoded(`${BASE_PATH}/stream_list.cgi`, streamData, {
action: 'set',
stream_id: streamId,
}, options);
}
async getStreamNetworkStatistics(streamId, options) {
const res = await this._getJson(`${BASE_PATH}/get_streamstat.cgi`, { stream_id: streamId }, options);
return streamStatsSchema.parse(res.data);
}
async getSrtStreamStatistics(streamId, options) {
const res = await this._getJson(`${BASE_PATH}/srt_statistics.cgi`, { stream_id: streamId }, options);
return srtStreamStatisticsSchema.parse(res.data);
}
async setStreamEnabled(streamId, enabled, options) {
await this._postUrlEncoded(`${BASE_PATH}/set_stream_enabled.cgi`, { stream_id: streamId, enabled: enabled ? 1 : 0 }, options);
}
async setStreamActive(streamId, active, options) {
await this._postUrlEncoded(`${BASE_PATH}/set_stream_active.cgi`, { stream_id: streamId, active: active ? 1 : 0 }, options);
}
async listFiles(options) {
const res = await this._getJson(`${BASE_PATH}/upload_audio.cgi`, { action: 'list' }, options);
return audioFileListSchema.parse(res.data);
}
async uploadFile(formData, storage, options) {
await this._post(`${BASE_PATH}/upload_audio.cgi`, formData, {
action: 'upload',
storage: storage,
}, options);
}
async removeFile(fileParams, options) {
await this._postUrlEncoded(`${BASE_PATH}/upload_audio.cgi`, { action: 'remove', ...fileParams }, options);
}
async getFileStorage(options) {
const res = await this._getJson(`${BASE_PATH}/upload_audio.cgi`, { action: 'get_storage' }, options);
return storageListSchema.parse(res.data);
}
async getFileFromCamera(path, options) {
return await this._getBlob(`${BASE_PATH}/audio.cgi`, { path }, options);
}
downloadReport(options) {
return this._getText(`${BASE_PATH}/report.cgi`, undefined, options);
}
async getDiagnostics(params, options) {
const convertedParams = {
camerainfo: params.camerainfo ? '1' : '0',
checkserver: params.checkserver ? '1' : '0',
checkservertime: params.checkservertime ? '1' : '0',
speedtest: params.speedtest ? '1' : '0',
pingtest: params.pingtest ? '1' : '0',
videoHostPort: params.videoHostPort,
audioHostPort: params.audioHostPort,
};
const res = await this._getJson(`${BASE_PATH}/diagnostics.cgi`, convertedParams, options);
return diagnosticsSchema.parse(res);
}
}
export const parseCameraStreamResponse = (cameraStreamData) => {
return {
enabled: parseInt(cameraStreamData.enabled),
active: parseInt(cameraStreamData.active),
audioSource: cameraStreamData.audioSource,
avSyncMsec: parseInt(cameraStreamData.avSyncMsec),
internalVapixParameters: cameraStreamData.internalVapixParameters,
userVapixParameters: cameraStreamData.userVapixParameters,
outputParameters: cameraStreamData.outputParameters,
outputType: cameraStreamData.outputType,
mediaServerUrl: cameraStreamData.mediaServerUrl,
inputType: cameraStreamData.inputType,
inputUrl: cameraStreamData.inputUrl,
forceStereo: parseInt(cameraStreamData.forceStereo),
streamDelay: isNaN(parseInt(cameraStreamData.streamDelay)) ? null : parseInt(cameraStreamData.streamDelay),
statusLed: parseInt(cameraStreamData.statusLed),
statusPort: cameraStreamData.statusPort,
callApi: parseInt(cameraStreamData.callApi),
trigger: cameraStreamData.trigger,
schedule: cameraStreamData.schedule,
prepareAhead: parseInt(cameraStreamData.prepareAhead),
startTime: isNaN(parseInt(cameraStreamData.startTime)) ? null : parseInt(cameraStreamData.startTime),
stopTime: isNaN(parseInt(cameraStreamData.stopTime)) ? null : parseInt(cameraStreamData.stopTime),
};
};