@camera.ui/common 0.0.13 → 0.0.15

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 (48) hide show
  1. package/dist/cameraUtils/ffmpeg-process.d.ts +23 -0
  2. package/dist/cameraUtils/ffmpeg-process.js +73 -0
  3. package/dist/cameraUtils/ffmpeg-process.js.map +1 -0
  4. package/dist/{utils → cameraUtils}/ffmpeg.d.ts +2 -0
  5. package/dist/{utils → cameraUtils}/ffmpeg.js +16 -0
  6. package/dist/cameraUtils/ffmpeg.js.map +1 -0
  7. package/dist/cameraUtils/index.d.ts +6 -0
  8. package/dist/cameraUtils/index.js +7 -0
  9. package/dist/cameraUtils/index.js.map +1 -0
  10. package/dist/cameraUtils/mp4.d.ts +10 -0
  11. package/dist/cameraUtils/mp4.js +53 -0
  12. package/dist/cameraUtils/mp4.js.map +1 -0
  13. package/dist/cameraUtils/ports.d.ts +7 -0
  14. package/dist/cameraUtils/ports.js +43 -0
  15. package/dist/cameraUtils/ports.js.map +1 -0
  16. package/dist/cameraUtils/rtp-splitter.d.ts +35 -0
  17. package/dist/cameraUtils/rtp-splitter.js +86 -0
  18. package/dist/cameraUtils/rtp-splitter.js.map +1 -0
  19. package/dist/cameraUtils/rtp.d.ts +3 -0
  20. package/dist/cameraUtils/rtp.js +16 -0
  21. package/dist/cameraUtils/rtp.js.map +1 -0
  22. package/dist/index.d.ts +6 -5
  23. package/dist/index.js +6 -5
  24. package/dist/index.js.map +1 -1
  25. package/dist/logger/index.d.ts +2 -2
  26. package/dist/utils/index.d.ts +0 -1
  27. package/dist/utils/index.js +0 -1
  28. package/dist/utils/index.js.map +1 -1
  29. package/dist/utils/subscribed.d.ts +9 -0
  30. package/dist/utils/subscribed.js +16 -0
  31. package/dist/utils/subscribed.js.map +1 -1
  32. package/dist/utils/utils.d.ts +5 -0
  33. package/dist/utils/utils.js +38 -0
  34. package/dist/utils/utils.js.map +1 -1
  35. package/package.json +11 -30
  36. package/dist/messaging/index.d.ts +0 -48
  37. package/dist/messaging/index.js +0 -141
  38. package/dist/messaging/index.js.map +0 -1
  39. package/dist/nats/index.d.ts +0 -30
  40. package/dist/nats/index.js +0 -85
  41. package/dist/nats/index.js.map +0 -1
  42. package/dist/packer/index.d.ts +0 -2
  43. package/dist/packer/index.js +0 -17
  44. package/dist/packer/index.js.map +0 -1
  45. package/dist/python/index.d.ts +0 -48
  46. package/dist/python/index.js +0 -478
  47. package/dist/python/index.js.map +0 -1
  48. package/dist/utils/ffmpeg.js.map +0 -1
@@ -0,0 +1,23 @@
1
+ export interface FfmpegProcessOptions {
2
+ ffmpegPath: string;
3
+ ffmpegArgs: (string | number)[];
4
+ logger?: {
5
+ error: (...args: any[]) => void;
6
+ info: (...args: any[]) => void;
7
+ };
8
+ logLabel?: string;
9
+ exitCallback?: (code: number | null, signal: string | null) => unknown;
10
+ stdoutCallback?: (data: any) => unknown;
11
+ startedCallback?: () => unknown;
12
+ }
13
+ export declare class FfmpegProcess {
14
+ readonly options: FfmpegProcessOptions;
15
+ private ff;
16
+ private processSubscription;
17
+ private started;
18
+ private stopped;
19
+ private exited;
20
+ constructor(options: FfmpegProcessOptions);
21
+ stop(): void;
22
+ writeStdin(input: string): void;
23
+ }
@@ -0,0 +1,73 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { Subject } from 'rxjs';
3
+ const noop = () => null;
4
+ const onGlobalProcessStopped = new Subject();
5
+ // register a single event listener, rather than listener per ffmpeg process
6
+ // this helps avoid a warning for hitting too many listeners
7
+ process.on('exit', () => onGlobalProcessStopped.next(null));
8
+ export class FfmpegProcess {
9
+ options;
10
+ ff;
11
+ processSubscription = onGlobalProcessStopped.subscribe(() => this.stop());
12
+ started = false;
13
+ stopped = false;
14
+ exited = false;
15
+ constructor(options) {
16
+ this.options = options;
17
+ const ffmpegArgs = options.ffmpegArgs.map((x) => x.toString());
18
+ this.ff = spawn(options.ffmpegPath, ffmpegArgs);
19
+ const { logger, logLabel } = options;
20
+ const logError = logger?.error || noop;
21
+ const logInfo = logger?.info || noop;
22
+ const logPrefix = logLabel ? `${logLabel}: ` : '';
23
+ if (options.stdoutCallback) {
24
+ const { stdoutCallback } = options;
25
+ this.ff.stdout.on('data', (data) => {
26
+ stdoutCallback(data);
27
+ });
28
+ }
29
+ this.ff.stderr.on('data', (data) => {
30
+ if (!this.started) {
31
+ this.started = true;
32
+ options.startedCallback?.();
33
+ }
34
+ logInfo(logPrefix + data);
35
+ });
36
+ this.ff.stdin.on('error', (error) => {
37
+ if (!error.message.includes('EPIPE')) {
38
+ logError(logPrefix + error.message);
39
+ }
40
+ });
41
+ this.ff.on('exit', (code, signal) => {
42
+ this.exited = true;
43
+ this.options.exitCallback?.(code, signal);
44
+ if (!code || code === 255) {
45
+ logInfo(logPrefix + 'stopped gracefully');
46
+ }
47
+ else {
48
+ logError(logPrefix + `exited with code ${code} and signal ${signal}`);
49
+ }
50
+ this.stop();
51
+ });
52
+ }
53
+ stop() {
54
+ if (this.stopped) {
55
+ return;
56
+ }
57
+ this.stopped = true;
58
+ this.processSubscription.unsubscribe();
59
+ this.ff.stderr.pause();
60
+ this.ff.stdout.pause();
61
+ if (!this.exited) {
62
+ this.ff.kill();
63
+ }
64
+ }
65
+ writeStdin(input) {
66
+ if (this.stopped) {
67
+ return;
68
+ }
69
+ this.ff.stdin.write(input);
70
+ this.ff.stdin.end();
71
+ }
72
+ }
73
+ //# sourceMappingURL=ffmpeg-process.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ffmpeg-process.js","sourceRoot":"","sources":["../../src/cameraUtils/ffmpeg-process.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAI/B,MAAM,IAAI,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC;AACxB,MAAM,sBAAsB,GAAG,IAAI,OAAO,EAAE,CAAC;AAE7C,4EAA4E;AAC5E,4DAA4D;AAC5D,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,sBAAsB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;AAe5D,MAAM,OAAO,aAAa;IAOI;IANpB,EAAE,CAAiC;IACnC,mBAAmB,GAAG,sBAAsB,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;IAC1E,OAAO,GAAG,KAAK,CAAC;IAChB,OAAO,GAAG,KAAK,CAAC;IAChB,MAAM,GAAG,KAAK,CAAC;IAEvB,YAA4B,OAA6B;QAA7B,YAAO,GAAP,OAAO,CAAsB;QACvD,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;QAC/D,IAAI,CAAC,EAAE,GAAG,KAAK,CAAC,OAAO,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;QAEhD,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC;QACrC,MAAM,QAAQ,GAAG,MAAM,EAAE,KAAK,IAAI,IAAI,CAAC;QACvC,MAAM,OAAO,GAAG,MAAM,EAAE,IAAI,IAAI,IAAI,CAAC;QACrC,MAAM,SAAS,GAAG,QAAQ,CAAC,CAAC,CAAC,GAAG,QAAQ,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;QAElD,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;YAC3B,MAAM,EAAE,cAAc,EAAE,GAAG,OAAO,CAAC;YACnC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAS,EAAE,EAAE;gBACtC,cAAc,CAAC,IAAI,CAAC,CAAC;YACvB,CAAC,CAAC,CAAC;QACL,CAAC;QAED,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAS,EAAE,EAAE;YACtC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;gBAClB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;gBACpB,OAAO,CAAC,eAAe,EAAE,EAAE,CAAC;YAC9B,CAAC;YAED,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC;QAC5B,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;YAClC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;gBACrC,QAAQ,CAAC,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC;YACtC,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE;YAClC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;YACnB,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YAE1C,IAAI,CAAC,IAAI,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;gBAC1B,OAAO,CAAC,SAAS,GAAG,oBAAoB,CAAC,CAAC;YAC5C,CAAC;iBAAM,CAAC;gBACN,QAAQ,CAAC,SAAS,GAAG,oBAAoB,IAAI,eAAe,MAAM,EAAE,CAAC,CAAC;YACxE,CAAC;YACD,IAAI,CAAC,IAAI,EAAE,CAAC;QACd,CAAC,CAAC,CAAC;IACL,CAAC;IAEM,IAAI;QACT,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,OAAO;QACT,CAAC;QACD,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,IAAI,CAAC,mBAAmB,CAAC,WAAW,EAAE,CAAC;QAEvC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QACvB,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QAEvB,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YACjB,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC;QACjB,CAAC;IACH,CAAC;IAEM,UAAU,CAAC,KAAa;QAC7B,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,OAAO;QACT,CAAC;QAED,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC3B,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC;IACtB,CAAC;CACF"}
@@ -6,4 +6,6 @@ export interface HardwareSource {
6
6
  export interface HardwareResponse {
7
7
  sources: HardwareSource[];
8
8
  }
9
+ export declare function doesFfmpegSupportCodec(codec: string, ffmpegPath: string): Promise<boolean>;
10
+ export declare function isFfmpegInstalled(ffmpegPath: string): Promise<boolean>;
9
11
  export declare function getHwaccelInfo(go2rtcEndpoint: string): Promise<FfmpegArgs>;
@@ -1,3 +1,19 @@
1
+ import { exec } from 'node:child_process';
2
+ import { promisify } from 'node:util';
3
+ const execAwait = promisify(exec);
4
+ export async function doesFfmpegSupportCodec(codec, ffmpegPath) {
5
+ const output = await execAwait(`${ffmpegPath} -codecs`);
6
+ return output.stdout.includes(codec);
7
+ }
8
+ export async function isFfmpegInstalled(ffmpegPath) {
9
+ try {
10
+ await execAwait(`${ffmpegPath} -codecs`);
11
+ return true;
12
+ }
13
+ catch {
14
+ return false;
15
+ }
16
+ }
1
17
  export async function getHwaccelInfo(go2rtcEndpoint) {
2
18
  let hwaccel = 'auto';
3
19
  let hwaccelArgs = [];
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ffmpeg.js","sourceRoot":"","sources":["../../src/cameraUtils/ffmpeg.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export * from './ffmpeg-process.js';
2
+ export * from './ffmpeg.js';
3
+ export * from './mp4.js';
4
+ export * from './ports.js';
5
+ export * from './rtp-splitter.js';
6
+ export * from './rtp.js';
@@ -0,0 +1,7 @@
1
+ export * from './ffmpeg-process.js';
2
+ export * from './ffmpeg.js';
3
+ export * from './mp4.js';
4
+ export * from './ports.js';
5
+ export * from './rtp-splitter.js';
6
+ export * from './rtp.js';
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cameraUtils/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,cAAc,mBAAmB,CAAC;AAClC,cAAc,UAAU,CAAC"}
@@ -0,0 +1,10 @@
1
+ export declare const NAL_TYPE_STAP_A = 24;
2
+ export declare const NAL_TYPE_FU_A = 28;
3
+ export declare const NAL_TYPE_NON_IDR = 1;
4
+ export declare const NAL_TYPE_IDR = 5;
5
+ export declare const NAL_TYPE_SEI = 6;
6
+ export declare const NAL_TYPE_SPS = 7;
7
+ export declare const NAL_TYPE_PPS = 8;
8
+ export declare const NAL_TYPE_DELIMITER = 9;
9
+ export declare const allowedNaluTypes: number[];
10
+ export declare function checkMp4StartsWithKeyFrame(mp4: Buffer, ffmpegPath: string): Promise<boolean>;
@@ -0,0 +1,53 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { timeoutPromise } from './../utils/utils.js';
3
+ // https://yumichan.net/video-processing/video-compression/introduction-to-h264-nal-unit/
4
+ export const NAL_TYPE_STAP_A = 24;
5
+ export const NAL_TYPE_FU_A = 28;
6
+ export const NAL_TYPE_NON_IDR = 1;
7
+ export const NAL_TYPE_IDR = 5;
8
+ export const NAL_TYPE_SEI = 6;
9
+ export const NAL_TYPE_SPS = 7;
10
+ export const NAL_TYPE_PPS = 8;
11
+ export const NAL_TYPE_DELIMITER = 9;
12
+ export const allowedNaluTypes = [NAL_TYPE_STAP_A, NAL_TYPE_SPS, NAL_TYPE_PPS, NAL_TYPE_SEI, NAL_TYPE_DELIMITER];
13
+ export async function checkMp4StartsWithKeyFrame(mp4, ffmpegPath) {
14
+ const cp = spawn(ffmpegPath, ['-hide_banner', '-f', 'mp4', '-i', 'pipe:3', '-vcodec', 'copy', '-f', 'h264', 'pipe:4'], {
15
+ stdio: ['pipe', 'pipe', 'pipe', 'pipe', 'pipe'],
16
+ });
17
+ const input = cp.stdio[3];
18
+ const output = cp.stdio[4];
19
+ const buffers = [];
20
+ input.write(mp4);
21
+ input.end();
22
+ output.on('data', (data) => buffers.push(data));
23
+ try {
24
+ await timeoutPromise(1000, new Promise((resolve) => cp.on('exit', resolve)));
25
+ const h264 = Buffer.concat(buffers);
26
+ let offset = 0;
27
+ while (offset < h264.length - 6) {
28
+ if (h264.readInt32BE(offset) !== 1) {
29
+ offset++;
30
+ continue;
31
+ }
32
+ offset += 4;
33
+ let naluType = h264.readUInt8(offset) & 0x1f;
34
+ if (naluType === NAL_TYPE_FU_A) {
35
+ offset++;
36
+ naluType = h264.readUInt8(offset) & 0x1f;
37
+ }
38
+ if (naluType === NAL_TYPE_IDR) {
39
+ return true;
40
+ }
41
+ if (allowedNaluTypes.includes(naluType)) {
42
+ offset++;
43
+ continue;
44
+ }
45
+ return false;
46
+ }
47
+ return false;
48
+ }
49
+ catch {
50
+ return false;
51
+ }
52
+ }
53
+ //# sourceMappingURL=mp4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mp4.js","sourceRoot":"","sources":["../../src/cameraUtils/mp4.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { Socket } from 'node:dgram';
2
+ export declare function reservePorts({ count, type, attemptNumber, }?: {
3
+ count?: number;
4
+ type?: 'udp' | 'tcp';
5
+ attemptNumber?: number;
6
+ }): Promise<number[]>;
7
+ export declare function bindToPort(socket: Socket, address?: string): Promise<number>;
@@ -0,0 +1,43 @@
1
+ import { pickPort } from 'pick-port';
2
+ // Need to reserve ports in sequence because ffmpeg uses the next port up by default. If it's taken, ffmpeg will error
3
+ export async function reservePorts({ count = 1, type = 'udp', attemptNumber = 0, } = {}) {
4
+ if (attemptNumber > 100) {
5
+ throw new Error('Failed to reserve ports after 100 tries');
6
+ }
7
+ const pickPortOptions = {
8
+ type,
9
+ reserveTimeout: 15, // 15 seconds is max setup time for HomeKit streams, so the port should be in use by then
10
+ }, port = await pickPort(pickPortOptions), ports = [port], tryAgain = () => {
11
+ return reservePorts({
12
+ count,
13
+ type,
14
+ attemptNumber: attemptNumber + 1,
15
+ });
16
+ };
17
+ for (let i = 1; i < count; i++) {
18
+ try {
19
+ const targetConsecutivePort = port + i, openPort = await pickPort({
20
+ ...pickPortOptions,
21
+ minPort: targetConsecutivePort,
22
+ maxPort: targetConsecutivePort,
23
+ });
24
+ ports.push(openPort);
25
+ }
26
+ catch {
27
+ // can't reserve next port, bail and get another set
28
+ return tryAgain();
29
+ }
30
+ }
31
+ return ports;
32
+ }
33
+ export function bindToPort(socket, address = '127.0.0.1') {
34
+ return new Promise((resolve, reject) => {
35
+ socket.on('error', reject);
36
+ // 0 means select a random open port
37
+ socket.bind(0, address, () => {
38
+ const { port } = socket.address();
39
+ resolve(port);
40
+ });
41
+ });
42
+ }
43
+ //# sourceMappingURL=ports.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ports.js","sourceRoot":"","sources":["../../src/cameraUtils/ports.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAKrC,uHAAuH;AACvH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,EACjC,KAAK,GAAG,CAAC,EACT,IAAI,GAAG,KAAK,EACZ,aAAa,GAAG,CAAC,MAKf,EAAE;IACJ,IAAI,aAAa,GAAG,GAAG,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;IAC7D,CAAC;IAED,MAAM,eAAe,GAAG;QACpB,IAAI;QACJ,cAAc,EAAE,EAAE,EAAE,yFAAyF;KAC9G,EACD,IAAI,GAAG,MAAM,QAAQ,CAAC,eAAe,CAAC,EACtC,KAAK,GAAG,CAAC,IAAI,CAAC,EACd,QAAQ,GAAG,GAAG,EAAE;QACd,OAAO,YAAY,CAAC;YAClB,KAAK;YACL,IAAI;YACJ,aAAa,EAAE,aAAa,GAAG,CAAC;SACjC,CAAC,CAAC;IACL,CAAC,CAAC;IAEJ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;QAC/B,IAAI,CAAC;YACH,MAAM,qBAAqB,GAAG,IAAI,GAAG,CAAC,EACpC,QAAQ,GAAG,MAAM,QAAQ,CAAC;gBACxB,GAAG,eAAe;gBAClB,OAAO,EAAE,qBAAqB;gBAC9B,OAAO,EAAE,qBAAqB;aAC/B,CAAC,CAAC;YAEL,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACvB,CAAC;QAAC,MAAM,CAAC;YACP,oDAAoD;YACpD,OAAO,QAAQ,EAAE,CAAC;QACpB,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,MAAc,EAAE,OAAO,GAAG,WAAW;IAC9D,OAAO,IAAI,OAAO,CAAS,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC7C,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAE3B,oCAAoC;QACpC,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE;YAC3B,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,CAAC,OAAO,EAAiB,CAAC;YACjD,OAAO,CAAC,IAAI,CAAC,CAAC;QAChB,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,35 @@
1
+ import type { RemoteInfo, Socket } from 'node:dgram';
2
+ import type { Observable } from 'rxjs';
3
+ export interface SocketTarget {
4
+ port: number;
5
+ address?: string;
6
+ }
7
+ export interface RtpMessageDescription {
8
+ isRtpMessage: boolean;
9
+ payloadType: number;
10
+ info: RemoteInfo;
11
+ message: Buffer;
12
+ }
13
+ export type RtpMessageHandler = (description: RtpMessageDescription) => SocketTarget | null;
14
+ export declare class RtpSplitter {
15
+ socket?: Socket;
16
+ address?: string;
17
+ port?: number;
18
+ type?: 'udp4' | 'udp6';
19
+ onMessage?: Observable<{
20
+ message: Buffer;
21
+ info: RemoteInfo;
22
+ isRtpMessage: boolean;
23
+ payloadType: number;
24
+ }>;
25
+ private closed;
26
+ private cleanedUp;
27
+ private onClose;
28
+ constructor();
29
+ prepare(type: 'udp4' | 'udp6', address?: string, messageHandler?: RtpMessageHandler): Promise<void>;
30
+ addMessageHandler(handler: RtpMessageHandler): void;
31
+ addOneTimeMessageHandler(handler: RtpMessageHandler): void;
32
+ send(message: Buffer, sendTo: SocketTarget): void;
33
+ private cleanUp;
34
+ close(): void;
35
+ }
@@ -0,0 +1,86 @@
1
+ import { createSocket } from 'node:dgram';
2
+ import { fromEvent, merge, ReplaySubject } from 'rxjs';
3
+ import { map, share, takeUntil } from 'rxjs/operators';
4
+ import { bindToPort } from './ports.js';
5
+ import { getPayloadType, isRtpMessagePayloadType } from './rtp.js';
6
+ export class RtpSplitter {
7
+ socket;
8
+ address;
9
+ port;
10
+ type;
11
+ onMessage;
12
+ closed = false;
13
+ cleanedUp = false;
14
+ onClose = new ReplaySubject();
15
+ constructor() { }
16
+ async prepare(type, address = '127.0.0.1', messageHandler) {
17
+ this.type = type;
18
+ const socket = createSocket(type);
19
+ const port = await bindToPort(socket, address);
20
+ socket.setSendBufferSize(1024 * 1024);
21
+ this.socket = socket;
22
+ this.address = address;
23
+ this.port = port;
24
+ this.onMessage = fromEvent(this.socket, 'message').pipe(map(([message, info]) => {
25
+ const payloadType = getPayloadType(message);
26
+ return {
27
+ message,
28
+ info,
29
+ isRtpMessage: isRtpMessagePayloadType(payloadType),
30
+ payloadType,
31
+ };
32
+ }), takeUntil(this.onClose), share());
33
+ if (messageHandler) {
34
+ this.addMessageHandler(messageHandler);
35
+ }
36
+ merge(fromEvent(this.socket, 'close'), fromEvent(this.socket, 'error'))
37
+ .pipe(takeUntil(this.onClose))
38
+ .subscribe(() => {
39
+ this.cleanUp();
40
+ });
41
+ }
42
+ addMessageHandler(handler) {
43
+ this.onMessage?.subscribe((description) => {
44
+ const forwardingTarget = handler(description);
45
+ if (forwardingTarget) {
46
+ this.send(description.message, forwardingTarget);
47
+ }
48
+ });
49
+ }
50
+ addOneTimeMessageHandler(handler) {
51
+ const subscription = this.onMessage?.subscribe((description) => {
52
+ const forwardingTarget = handler(description);
53
+ if (forwardingTarget) {
54
+ this.send(description.message, forwardingTarget);
55
+ }
56
+ // Unsubscribe nach der ersten Ausführung
57
+ subscription?.unsubscribe();
58
+ });
59
+ }
60
+ send(message, sendTo) {
61
+ if (this.closed) {
62
+ // If we send a message on a closed socket, it will throw an ERR_SOCKET_DGRAM_NOT_RUNNING error
63
+ return;
64
+ }
65
+ this.socket?.send(message, sendTo.port, sendTo.address || '127.0.0.1');
66
+ }
67
+ cleanUp() {
68
+ this.closed = true;
69
+ if (this.cleanedUp) {
70
+ return;
71
+ }
72
+ this.address = undefined;
73
+ this.port = undefined;
74
+ this.type = undefined;
75
+ this.cleanedUp = true;
76
+ this.onClose.next(null);
77
+ }
78
+ close() {
79
+ if (this.closed) {
80
+ return;
81
+ }
82
+ this.socket?.close();
83
+ this.cleanUp();
84
+ }
85
+ }
86
+ //# sourceMappingURL=rtp-splitter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rtp-splitter.js","sourceRoot":"","sources":["../../src/cameraUtils/rtp-splitter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export declare function getPayloadType(message: Buffer): number;
2
+ export declare function isRtpMessagePayloadType(payloadType: number): boolean;
3
+ export declare function getSsrc(message: Buffer): number | null;
@@ -0,0 +1,16 @@
1
+ export function getPayloadType(message) {
2
+ return message.readUInt8(1) & 0x7f;
3
+ }
4
+ export function isRtpMessagePayloadType(payloadType) {
5
+ return payloadType > 90 || payloadType === 0;
6
+ }
7
+ export function getSsrc(message) {
8
+ try {
9
+ const payloadType = getPayloadType(message), isRtp = isRtpMessagePayloadType(payloadType);
10
+ return message.readUInt32BE(isRtp ? 8 : 4);
11
+ }
12
+ catch {
13
+ return null;
14
+ }
15
+ }
16
+ //# sourceMappingURL=rtp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rtp.js","sourceRoot":"","sources":["../../src/cameraUtils/rtp.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,cAAc,CAAC,OAAe;IAC5C,OAAO,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;AACrC,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,WAAmB;IACzD,OAAO,WAAW,GAAG,EAAE,IAAI,WAAW,KAAK,CAAC,CAAC;AAC/C,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,OAAe;IACrC,IAAI,CAAC;QACH,MAAM,WAAW,GAAG,cAAc,CAAC,OAAO,CAAC,EACzC,KAAK,GAAG,uBAAuB,CAAC,WAAW,CAAC,CAAC;QAC/C,OAAO,OAAO,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1,12 +1,13 @@
1
+ export * from './cameraUtils/ffmpeg-process.js';
2
+ export * from './cameraUtils/ffmpeg.js';
3
+ export * from './cameraUtils/mp4.js';
4
+ export * from './cameraUtils/ports.js';
5
+ export * from './cameraUtils/rtp-splitter.js';
6
+ export * from './cameraUtils/rtp.js';
1
7
  export * from './logger/index.js';
2
- export * from './messaging/index.js';
3
- export * from './nats/index.js';
4
8
  export * from './net/index.js';
5
9
  export * from './network/index.js';
6
10
  export * from './npm/index.js';
7
- export * from './packer/index.js';
8
- export * from './python/index.js';
9
11
  export * from './utils/env.js';
10
- export * from './utils/ffmpeg.js';
11
12
  export * from './utils/subscribed.js';
12
13
  export * from './utils/utils.js';
package/dist/index.js CHANGED
@@ -1,13 +1,14 @@
1
+ export * from './cameraUtils/ffmpeg-process.js';
2
+ export * from './cameraUtils/ffmpeg.js';
3
+ export * from './cameraUtils/mp4.js';
4
+ export * from './cameraUtils/ports.js';
5
+ export * from './cameraUtils/rtp-splitter.js';
6
+ export * from './cameraUtils/rtp.js';
1
7
  export * from './logger/index.js';
2
- export * from './messaging/index.js';
3
- export * from './nats/index.js';
4
8
  export * from './net/index.js';
5
9
  export * from './network/index.js';
6
10
  export * from './npm/index.js';
7
- export * from './packer/index.js';
8
- export * from './python/index.js';
9
11
  export * from './utils/env.js';
10
- export * from './utils/ffmpeg.js';
11
12
  export * from './utils/subscribed.js';
12
13
  export * from './utils/utils.js';
13
14
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,sBAAsB,CAAC;AACrC,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iCAAiC,CAAC;AAChD,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC"}
@@ -1,4 +1,4 @@
1
- import type { PluginLogger } from '@camera.ui/types';
1
+ import type { LoggerService } from '@camera.ui/types';
2
2
  export interface LoggerOptions {
3
3
  prefix?: string;
4
4
  suffix?: string;
@@ -6,7 +6,7 @@ export interface LoggerOptions {
6
6
  debugEnabled?: boolean;
7
7
  traceEnabled?: boolean;
8
8
  }
9
- export declare class Logger implements PluginLogger {
9
+ export declare class Logger implements LoggerService {
10
10
  private prefix;
11
11
  private suffix?;
12
12
  disableTimestamps: boolean;
@@ -1,4 +1,3 @@
1
1
  export * from './env.js';
2
- export * from './ffmpeg.js';
3
2
  export * from './subscribed.js';
4
3
  export * from './utils.js';
@@ -1,5 +1,4 @@
1
1
  export * from './env.js';
2
- export * from './ffmpeg.js';
3
2
  export * from './subscribed.js';
4
3
  export * from './utils.js';
5
4
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,YAAY,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,iBAAiB,CAAC;AAChC,cAAc,YAAY,CAAC"}
@@ -1,3 +1,4 @@
1
+ import type { Subscribed as SubscribedInterface } from '@camera.ui/types';
1
2
  import type { Subscription } from 'rxjs';
2
3
  export declare class Subscribed {
3
4
  private readonly subscriptions;
@@ -7,3 +8,11 @@ export declare class Subscribed {
7
8
  protected unsubscribe(): void;
8
9
  protected unsubscribeAdditional(): void;
9
10
  }
11
+ export declare class SubscribedPublic implements SubscribedInterface {
12
+ private readonly subscriptions;
13
+ private readonly additionalSubscriptions;
14
+ addSubscriptions(...subscriptions: Subscription[]): void;
15
+ addAdditionalSubscriptions(...subscriptions: Subscription[]): void;
16
+ unsubscribe(): void;
17
+ unsubscribeAdditional(): void;
18
+ }
@@ -14,4 +14,20 @@ export class Subscribed {
14
14
  this.additionalSubscriptions.forEach((subscription) => subscription.unsubscribe());
15
15
  }
16
16
  }
17
+ export class SubscribedPublic {
18
+ subscriptions = [];
19
+ additionalSubscriptions = [];
20
+ addSubscriptions(...subscriptions) {
21
+ this.subscriptions.push(...subscriptions);
22
+ }
23
+ addAdditionalSubscriptions(...subscriptions) {
24
+ this.additionalSubscriptions.push(...subscriptions);
25
+ }
26
+ unsubscribe() {
27
+ this.subscriptions.forEach((subscription) => subscription.unsubscribe());
28
+ }
29
+ unsubscribeAdditional() {
30
+ this.additionalSubscriptions.forEach((subscription) => subscription.unsubscribe());
31
+ }
32
+ }
17
33
  //# sourceMappingURL=subscribed.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"subscribed.js","sourceRoot":"","sources":["../../src/utils/subscribed.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,UAAU;IACJ,aAAa,GAAmB,EAAE,CAAC;IACnC,uBAAuB,GAAmB,EAAE,CAAC;IAEpD,gBAAgB,CAAC,GAAG,aAA6B;QACzD,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,GAAG,aAAa,CAAC,CAAC;IAC5C,CAAC;IAES,0BAA0B,CAAC,GAAG,aAA6B;QACnE,IAAI,CAAC,uBAAuB,CAAC,IAAI,CAAC,GAAG,aAAa,CAAC,CAAC;IACtD,CAAC;IAES,WAAW;QACnB,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,CAAC,CAAC;IAC3E,CAAC;IAES,qBAAqB;QAC7B,IAAI,CAAC,uBAAuB,CAAC,OAAO,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,CAAC,CAAC;IACrF,CAAC;CACF"}
1
+ {"version":3,"file":"subscribed.js","sourceRoot":"","sources":["../../src/utils/subscribed.ts"],"names":[],"mappings":"AAGA,MAAM,OAAO,UAAU;IACJ,aAAa,GAAmB,EAAE,CAAC;IACnC,uBAAuB,GAAmB,EAAE,CAAC;IAEpD,gBAAgB,CAAC,GAAG,aAA6B;QACzD,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,GAAG,aAAa,CAAC,CAAC;IAC5C,CAAC;IAES,0BAA0B,CAAC,GAAG,aAA6B;QACnE,IAAI,CAAC,uBAAuB,CAAC,IAAI,CAAC,GAAG,aAAa,CAAC,CAAC;IACtD,CAAC;IAES,WAAW;QACnB,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,CAAC,CAAC;IAC3E,CAAC;IAES,qBAAqB;QAC7B,IAAI,CAAC,uBAAuB,CAAC,OAAO,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,CAAC,CAAC;IACrF,CAAC;CACF;AAED,MAAM,OAAO,gBAAgB;IACV,aAAa,GAAmB,EAAE,CAAC;IACnC,uBAAuB,GAAmB,EAAE,CAAC;IAEvD,gBAAgB,CAAC,GAAG,aAA6B;QACtD,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,GAAG,aAAa,CAAC,CAAC;IAC5C,CAAC;IAEM,0BAA0B,CAAC,GAAG,aAA6B;QAChE,IAAI,CAAC,uBAAuB,CAAC,IAAI,CAAC,GAAG,aAAa,CAAC,CAAC;IACtD,CAAC;IAEM,WAAW;QAChB,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,CAAC,CAAC;IAC3E,CAAC;IAEM,qBAAqB;QAC1B,IAAI,CAAC,uBAAuB,CAAC,OAAO,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,CAAC,CAAC;IACrF,CAAC;CACF"}
@@ -1,4 +1,6 @@
1
+ import type { AudioCodec } from '@camera.ui/types';
1
2
  export type Customizer<TObject, TSource> = (objValue: any, srcValue: any, key: string, object: TObject, source: TSource, stack: any[]) => any;
3
+ export declare function timeoutPromise<T>(timeout: number, promise: Promise<T>): Promise<T>;
2
4
  export declare function toQuery(data: any): string;
3
5
  export declare function toData(query: string): Record<string, any>;
4
6
  export declare function isJson(str: any): boolean;
@@ -8,3 +10,6 @@ export declare function mergeWith<TObject, TSource>(object: TObject, source: TSo
8
10
  export declare function orderBy(array: any[], keys: string[], orders: ('asc' | 'desc')[]): any[];
9
11
  export declare function structuredClone<T>(obj: T): T;
10
12
  export declare function createSourceName(cameraName: string, sourceName: string): string;
13
+ export declare function isWebRtcCompatibleAudioCodec(audioCodec: AudioCodec): boolean;
14
+ export declare function isWebRtcCompatibleVideoCodec(videoCodec: string): boolean;
15
+ export declare function getCleanSdp(sdp: string, includeVideo: boolean, direction?: 'sendonly' | 'recvonly'): string;
@@ -1,3 +1,17 @@
1
+ export function timeoutPromise(timeout, promise) {
2
+ return new Promise((resolve, reject) => {
3
+ const t = setTimeout(() => reject(new Error('Operation timed out')), timeout);
4
+ promise
5
+ .then((v) => {
6
+ clearTimeout(t);
7
+ resolve(v);
8
+ })
9
+ .catch((e) => {
10
+ clearTimeout(t);
11
+ reject(e);
12
+ });
13
+ });
14
+ }
1
15
  export function toQuery(data) {
2
16
  let query = '';
3
17
  if (typeof data === 'object' && !Array.isArray(data)) {
@@ -164,4 +178,28 @@ export function structuredClone(obj) {
164
178
  export function createSourceName(cameraName, sourceName) {
165
179
  return `${cameraName.replace(/ /g, '_').toLowerCase()}_${sourceName.replace(/ /g, '_').toLowerCase()}`;
166
180
  }
181
+ export function isWebRtcCompatibleAudioCodec(audioCodec) {
182
+ return audioCodec === 'opus' || audioCodec === 'G722' || audioCodec === 'PCMU' || audioCodec === 'PCMA';
183
+ }
184
+ export function isWebRtcCompatibleVideoCodec(videoCodec) {
185
+ return videoCodec === 'H264' || videoCodec === 'VP8' || videoCodec === 'VP9';
186
+ }
187
+ export function getCleanSdp(sdp, includeVideo, direction) {
188
+ return sdp
189
+ .split('\nm=')
190
+ .slice(1)
191
+ .map((section) => 'm=' + section)
192
+ .filter((section) => {
193
+ const isVideoSection = section.startsWith('m=video');
194
+ if (!includeVideo && isVideoSection) {
195
+ return false;
196
+ }
197
+ if (direction) {
198
+ const directionRegex = new RegExp(`a=${direction}`, 'i');
199
+ return directionRegex.test(section);
200
+ }
201
+ return true;
202
+ })
203
+ .join('\n');
204
+ }
167
205
  //# sourceMappingURL=utils.js.map