@camstack/addon-go2rtc 0.1.13 → 0.1.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.
@@ -1,428 +0,0 @@
1
- // src/go2rtc.addon.ts
2
- import { spawn } from "child_process";
3
- import { mkdirSync, writeFileSync } from "fs";
4
- import { join, dirname } from "path";
5
-
6
- // src/go2rtc-engine.ts
7
- var Go2rtcEngine = class {
8
- constructor(config) {
9
- this.config = config;
10
- this.baseUrl = `http://127.0.0.1:${config.apiPort}`;
11
- }
12
- baseUrl;
13
- streams = /* @__PURE__ */ new Map();
14
- async initialize(_config) {
15
- try {
16
- const res = await fetch(`${this.baseUrl}/api/streams`);
17
- if (!res.ok) {
18
- throw new Error(`go2rtc API returned ${res.status}`);
19
- }
20
- } catch (err) {
21
- throw new Error(
22
- `Failed to reach go2rtc at ${this.baseUrl}: ${err instanceof Error ? err.message : String(err)}`
23
- );
24
- }
25
- }
26
- async shutdown() {
27
- this.streams.clear();
28
- }
29
- async registerStream(streamId, source) {
30
- const url = `${this.baseUrl}/api/streams?src=${encodeURIComponent(streamId)}&url=${encodeURIComponent(source.url)}`;
31
- const res = await fetch(url, { method: "PUT" });
32
- if (!res.ok) {
33
- throw new Error(`go2rtc registerStream failed: ${res.status}`);
34
- }
35
- this.streams.set(streamId, source);
36
- }
37
- async unregisterStream(streamId) {
38
- const url = `${this.baseUrl}/api/streams?src=${encodeURIComponent(streamId)}`;
39
- const res = await fetch(url, { method: "DELETE" });
40
- if (!res.ok) {
41
- throw new Error(`go2rtc unregisterStream failed: ${res.status}`);
42
- }
43
- this.streams.delete(streamId);
44
- }
45
- getStreamUrl(streamId, format) {
46
- const encoded = encodeURIComponent(streamId);
47
- switch (format) {
48
- case "webrtc":
49
- return `${this.baseUrl}/api/webrtc?src=${encoded}`;
50
- case "hls":
51
- return `${this.baseUrl}/api/stream.m3u8?src=${encoded}`;
52
- case "mjpeg":
53
- return `${this.baseUrl}/api/frame.jpeg?src=${encoded}`;
54
- case "rtsp":
55
- return `rtsp://127.0.0.1:${this.config.rtspPort}/${streamId}`;
56
- default:
57
- return null;
58
- }
59
- }
60
- async proxyWhepOffer(streamId, sdpOffer) {
61
- const url = `${this.baseUrl}/api/webrtc?src=${encodeURIComponent(streamId)}`;
62
- const res = await fetch(url, {
63
- method: "POST",
64
- headers: { "Content-Type": "application/sdp" },
65
- body: sdpOffer
66
- });
67
- if (!res.ok) {
68
- throw new Error(`go2rtc WHEP failed: ${res.status}`);
69
- }
70
- return res.text();
71
- }
72
- listStreams() {
73
- return [...this.streams.entries()].map(([id, source]) => ({
74
- streamId: id,
75
- source,
76
- formats: ["webrtc", "hls", "mjpeg", "rtsp"]
77
- }));
78
- }
79
- getStreamStatus(streamId) {
80
- if (!this.streams.has(streamId)) return null;
81
- return { active: true, viewers: 0 };
82
- }
83
- };
84
-
85
- // src/go2rtc-config-generator.ts
86
- function generateGo2rtcConfig(config) {
87
- const yaml = `
88
- api:
89
- listen: ":${config.apiPort}"
90
-
91
- rtsp:
92
- listen: ":${config.rtspPort}"
93
-
94
- webrtc:
95
- listen: ":${config.webrtcPort}"
96
- ice_servers: []
97
-
98
- streams: {}
99
- `;
100
- return yaml.trim();
101
- }
102
-
103
- // src/go2rtc-downloader.ts
104
- var GO2RTC_VERSION = "1.9.14";
105
- var BASE_URL = `https://github.com/AlexxIT/go2rtc/releases/download/v${GO2RTC_VERSION}`;
106
- function getGo2rtcDownloadUrl() {
107
- const os = process.platform;
108
- const rawArch = process.arch;
109
- let arch;
110
- switch (rawArch) {
111
- case "x64":
112
- arch = "amd64";
113
- break;
114
- case "arm64":
115
- arch = "arm64";
116
- break;
117
- case "arm":
118
- arch = "arm";
119
- break;
120
- case "ia32":
121
- arch = "i386";
122
- break;
123
- default:
124
- throw new Error(`Unsupported architecture: ${rawArch}`);
125
- }
126
- switch (os) {
127
- case "darwin":
128
- return { url: `${BASE_URL}/go2rtc_mac_${arch}.zip`, isArchive: true, archiveFormat: "zip" };
129
- case "linux":
130
- return { url: `${BASE_URL}/go2rtc_linux_${arch}`, isArchive: false };
131
- case "win32":
132
- return { url: `${BASE_URL}/go2rtc_win_${arch}.zip`, isArchive: true, archiveFormat: "zip" };
133
- default:
134
- throw new Error(`Unsupported platform: ${os}`);
135
- }
136
- }
137
- async function ensureGo2rtcBinary(deps) {
138
- const { url, isArchive, archiveFormat } = getGo2rtcDownloadUrl();
139
- return deps.ensureBinary({
140
- name: "go2rtc",
141
- downloadUrl: url,
142
- isArchive,
143
- archiveFormat
144
- });
145
- }
146
-
147
- // src/go2rtc.addon.ts
148
- var Go2rtcAddon = class {
149
- manifest = {
150
- id: "go2rtc",
151
- name: "go2rtc Streaming Engine",
152
- version: "1.0.0",
153
- capabilities: ["streaming-engine"]
154
- };
155
- /** IRestreamer identity */
156
- id = "go2rtc";
157
- name = "go2rtc Restreamer";
158
- engine = null;
159
- process = null;
160
- registeredDevices = /* @__PURE__ */ new Map();
161
- currentConfig = {
162
- apiPort: 1984,
163
- rtspPort: 8554,
164
- webrtcPort: 8555,
165
- binaryPath: "go2rtc"
166
- };
167
- async initialize(context) {
168
- const dataPath = context.locationPaths.data;
169
- const resolvedBinaryPath = await ensureGo2rtcBinary(context.deps);
170
- const processConfig = {
171
- apiPort: context.addonConfig.apiPort ?? this.currentConfig.apiPort,
172
- rtspPort: context.addonConfig.rtspPort ?? this.currentConfig.rtspPort,
173
- webrtcPort: context.addonConfig.webrtcPort ?? this.currentConfig.webrtcPort,
174
- binaryPath: resolvedBinaryPath
175
- };
176
- this.currentConfig = processConfig;
177
- const configYaml = generateGo2rtcConfig(processConfig);
178
- const configPath = join(dataPath, "go2rtc.yaml");
179
- mkdirSync(dirname(configPath), { recursive: true });
180
- writeFileSync(configPath, configYaml);
181
- this.process = spawn(processConfig.binaryPath, ["-config", configPath], {
182
- stdio: ["pipe", "pipe", "pipe"]
183
- });
184
- this.process.on("exit", (code, signal) => {
185
- context.logger.warn(`go2rtc process exited (code: ${code}, signal: ${signal})`);
186
- });
187
- this.process.stderr?.on("data", (data) => {
188
- const msg = data.toString().trim();
189
- if (msg) context.logger.debug(`go2rtc stderr: ${msg}`);
190
- });
191
- this.process.stdout?.on("data", (data) => {
192
- const msg = data.toString().trim();
193
- if (msg) context.logger.debug(`go2rtc stdout: ${msg}`);
194
- });
195
- const apiUrl = `http://127.0.0.1:${processConfig.apiPort}/api/streams`;
196
- await this.waitForReady(apiUrl, 1e4);
197
- const engineConfig = {
198
- apiPort: processConfig.apiPort,
199
- rtspPort: processConfig.rtspPort,
200
- webrtcPort: processConfig.webrtcPort,
201
- binaryPath: processConfig.binaryPath
202
- };
203
- this.engine = new Go2rtcEngine(engineConfig);
204
- await this.engine.initialize();
205
- context.logger.info(`go2rtc started (PID: ${this.process.pid}, API: ${processConfig.apiPort})`);
206
- }
207
- async shutdown() {
208
- await this.engine?.shutdown();
209
- this.engine = null;
210
- this.registeredDevices.clear();
211
- if (this.process) {
212
- this.process.kill("SIGTERM");
213
- this.process = null;
214
- }
215
- }
216
- getEngine() {
217
- if (!this.engine) throw new Error("go2rtc not initialized");
218
- return this.engine;
219
- }
220
- getCapabilityProvider(name) {
221
- if (name === "streaming-engine" && this.engine) {
222
- return this.engine;
223
- }
224
- if (name === "restreamer") {
225
- return this;
226
- }
227
- if (name === "webrtc") {
228
- return this;
229
- }
230
- return null;
231
- }
232
- // --- IRestreamer implementation ---
233
- async registerDevice(deviceId, streams) {
234
- if (!this.engine) {
235
- throw new Error("go2rtc not initialized \u2014 cannot register device");
236
- }
237
- const streamIds = [];
238
- for (const stream of streams) {
239
- streamIds.push(stream.streamId);
240
- if (stream.sourceUrl) {
241
- await this.engine.registerStream(stream.streamId, {
242
- url: `ffmpeg:${stream.sourceUrl}#video=${stream.codec}`,
243
- protocol: "rtsp",
244
- deviceId,
245
- providerId: "broker"
246
- });
247
- }
248
- }
249
- this.registeredDevices.set(deviceId, {
250
- deviceId,
251
- streams,
252
- streamIds
253
- });
254
- }
255
- pushPacket(_streamId, _packet) {
256
- }
257
- async unregisterDevice(deviceId) {
258
- const registration = this.registeredDevices.get(deviceId);
259
- if (!registration) {
260
- return;
261
- }
262
- if (this.engine) {
263
- for (const streamId of registration.streamIds) {
264
- try {
265
- await this.engine.unregisterStream(streamId);
266
- } catch {
267
- }
268
- }
269
- }
270
- this.registeredDevices.delete(deviceId);
271
- }
272
- getExposedResources(deviceId) {
273
- const registration = this.registeredDevices.get(deviceId);
274
- if (!registration || !this.engine) {
275
- return [];
276
- }
277
- const resources = [];
278
- for (const streamId of registration.streamIds) {
279
- const webrtcUrl = this.engine.getStreamUrl(streamId, "webrtc");
280
- if (webrtcUrl) {
281
- resources.push({ type: "url", format: "webrtc", value: webrtcUrl });
282
- }
283
- const hlsUrl = this.engine.getStreamUrl(streamId, "hls");
284
- if (hlsUrl) {
285
- resources.push({ type: "url", format: "hls", value: hlsUrl });
286
- }
287
- const mjpegUrl = this.engine.getStreamUrl(streamId, "mjpeg");
288
- if (mjpegUrl) {
289
- resources.push({ type: "url", format: "mjpeg", value: mjpegUrl });
290
- }
291
- const rtspUrl = this.engine.getStreamUrl(streamId, "rtsp");
292
- if (rtspUrl) {
293
- resources.push({ type: "url", format: "rtsp", value: rtspUrl });
294
- }
295
- }
296
- return resources;
297
- }
298
- async proxyWhepOffer(streamId, sdpOffer) {
299
- if (!this.engine) {
300
- throw new Error("go2rtc not initialized \u2014 cannot proxy WHEP");
301
- }
302
- return this.engine.proxyWhepOffer(streamId, sdpOffer);
303
- }
304
- // --- End IRestreamer ---
305
- // --- IWebRtcProvider implementation ---
306
- async handleOffer(streamId, sdpOffer) {
307
- if (!this.engine) {
308
- throw new Error("go2rtc not initialized \u2014 cannot handle WebRTC offer");
309
- }
310
- return this.engine.proxyWhepOffer(streamId, sdpOffer);
311
- }
312
- supportsStream(streamId) {
313
- const deviceId = streamId.split("/")[0];
314
- return deviceId !== void 0 && this.registeredDevices.has(deviceId);
315
- }
316
- async registerStream(streamId, _codec) {
317
- const deviceId = streamId.split("/")[0];
318
- if (deviceId && !this.registeredDevices.has(deviceId)) {
319
- this.registeredDevices.set(deviceId, {
320
- deviceId,
321
- streams: [{ streamId, label: streamId, codec: _codec, type: "video" }],
322
- streamIds: [streamId]
323
- });
324
- }
325
- }
326
- async unregisterStream(streamId) {
327
- if (!this.engine) {
328
- return;
329
- }
330
- try {
331
- await this.engine.unregisterStream(streamId);
332
- } catch {
333
- }
334
- }
335
- // --- End IWebRtcProvider ---
336
- /** Exposed for testing */
337
- async waitForReady(url, timeoutMs) {
338
- const start = Date.now();
339
- while (Date.now() - start < timeoutMs) {
340
- try {
341
- const res = await fetch(url);
342
- if (res.ok) return;
343
- } catch {
344
- }
345
- await new Promise((r) => setTimeout(r, 500));
346
- }
347
- throw new Error(`go2rtc did not become ready within ${timeoutMs}ms`);
348
- }
349
- getConfigSchema() {
350
- return {
351
- sections: [
352
- {
353
- id: "go2rtc-info",
354
- title: "go2rtc",
355
- fields: [
356
- {
357
- type: "info",
358
- key: "binary-info",
359
- label: "Binary",
360
- content: "go2rtc is automatically downloaded on first boot. The binary is stored in the data directory.",
361
- variant: "info"
362
- }
363
- ]
364
- },
365
- {
366
- id: "go2rtc-ports",
367
- title: "Network Ports",
368
- description: "Port configuration for the go2rtc restreamer. Changes require a restart.",
369
- columns: 3,
370
- fields: [
371
- {
372
- type: "info",
373
- key: "restart-note",
374
- label: "Restart required",
375
- content: "Port changes require restarting go2rtc.",
376
- variant: "warning"
377
- },
378
- {
379
- type: "number",
380
- key: "apiPort",
381
- label: "API Port",
382
- description: "go2rtc HTTP API",
383
- min: 1024,
384
- max: 65535,
385
- step: 1
386
- },
387
- {
388
- type: "number",
389
- key: "rtspPort",
390
- label: "RTSP Port",
391
- description: "RTSP restream output",
392
- min: 1024,
393
- max: 65535,
394
- step: 1
395
- },
396
- {
397
- type: "number",
398
- key: "webrtcPort",
399
- label: "WebRTC Port",
400
- description: "WebRTC UDP/TCP",
401
- min: 1024,
402
- max: 65535,
403
- step: 1
404
- }
405
- ]
406
- }
407
- ]
408
- };
409
- }
410
- getConfig() {
411
- return { ...this.currentConfig };
412
- }
413
- async onConfigChange(config) {
414
- this.currentConfig = {
415
- binaryPath: config.binaryPath ?? this.currentConfig.binaryPath,
416
- apiPort: config.apiPort ?? this.currentConfig.apiPort,
417
- rtspPort: config.rtspPort ?? this.currentConfig.rtspPort,
418
- webrtcPort: config.webrtcPort ?? this.currentConfig.webrtcPort
419
- };
420
- }
421
- };
422
-
423
- export {
424
- Go2rtcEngine,
425
- generateGo2rtcConfig,
426
- Go2rtcAddon
427
- };
428
- //# sourceMappingURL=chunk-R6UZ6HX4.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/go2rtc.addon.ts","../src/go2rtc-engine.ts","../src/go2rtc-config-generator.ts","../src/go2rtc-downloader.ts"],"sourcesContent":["import { spawn, type ChildProcess } from 'node:child_process'\nimport { mkdirSync, writeFileSync } from 'node:fs'\nimport { join, dirname } from 'node:path'\nimport type {\n ICamstackAddon,\n AddonManifest,\n AddonContext,\n IConfigurable,\n ConfigUISchema,\n CapabilityProviderMap,\n IRestreamer,\n RegisteredStream,\n RestreamerExposedResource as ExposedResource,\n EncodedPacket,\n} from '@camstack/types'\nimport type { IWebRtcProvider } from './webrtc-provider'\nimport { Go2rtcEngine } from './go2rtc-engine'\nimport type { Go2rtcConfig } from './go2rtc-engine'\nimport { generateGo2rtcConfig } from './go2rtc-config-generator'\nimport { ensureGo2rtcBinary } from './go2rtc-downloader'\n\nexport interface Go2rtcProcessConfig {\n readonly apiPort: number\n readonly rtspPort: number\n readonly webrtcPort: number\n readonly binaryPath: string\n}\n\ninterface DeviceRegistration {\n readonly deviceId: string\n readonly streams: readonly RegisteredStream[]\n /** The original source URL registered with go2rtc (for cleanup) */\n readonly streamIds: readonly string[]\n}\n\nexport class Go2rtcAddon implements ICamstackAddon, IConfigurable, IRestreamer, IWebRtcProvider {\n readonly manifest: AddonManifest = {\n id: 'go2rtc',\n name: 'go2rtc Streaming Engine',\n version: '1.0.0',\n capabilities: ['streaming-engine'],\n }\n\n /** IRestreamer identity */\n readonly id = 'go2rtc'\n readonly name = 'go2rtc Restreamer'\n\n private engine: Go2rtcEngine | null = null\n private process: ChildProcess | null = null\n private readonly registeredDevices = new Map<string, DeviceRegistration>()\n private currentConfig: Go2rtcProcessConfig = {\n apiPort: 1984,\n rtspPort: 8554,\n webrtcPort: 8555,\n binaryPath: 'go2rtc',\n }\n\n async initialize(context: AddonContext): Promise<void> {\n // Path comes from StorageLocationManager via context.locationPaths\n const dataPath = context.locationPaths.data\n\n // Auto-download go2rtc binary if not found\n const resolvedBinaryPath = await ensureGo2rtcBinary(context.deps!)\n\n const processConfig: Go2rtcProcessConfig = {\n apiPort: (context.addonConfig.apiPort as number) ?? this.currentConfig.apiPort,\n rtspPort: (context.addonConfig.rtspPort as number) ?? this.currentConfig.rtspPort,\n webrtcPort: (context.addonConfig.webrtcPort as number) ?? this.currentConfig.webrtcPort,\n binaryPath: resolvedBinaryPath,\n }\n this.currentConfig = processConfig\n\n // Generate config file\n const configYaml = generateGo2rtcConfig(processConfig)\n const configPath = join(dataPath, 'go2rtc.yaml')\n mkdirSync(dirname(configPath), { recursive: true })\n writeFileSync(configPath, configYaml)\n\n // Start go2rtc as a child process\n this.process = spawn(processConfig.binaryPath, ['-config', configPath], {\n stdio: ['pipe', 'pipe', 'pipe'],\n })\n\n this.process.on('exit', (code, signal) => {\n context.logger.warn(`go2rtc process exited (code: ${code}, signal: ${signal})`)\n })\n\n this.process.stderr?.on('data', (data: Buffer) => {\n const msg = data.toString().trim()\n if (msg) context.logger.debug(`go2rtc stderr: ${msg}`)\n })\n\n this.process.stdout?.on('data', (data: Buffer) => {\n const msg = data.toString().trim()\n if (msg) context.logger.debug(`go2rtc stdout: ${msg}`)\n })\n\n // Wait for API to be ready\n const apiUrl = `http://127.0.0.1:${processConfig.apiPort}/api/streams`\n await this.waitForReady(apiUrl, 10_000)\n\n // Create engine\n const engineConfig: Go2rtcConfig = {\n apiPort: processConfig.apiPort,\n rtspPort: processConfig.rtspPort,\n webrtcPort: processConfig.webrtcPort,\n binaryPath: processConfig.binaryPath,\n }\n this.engine = new Go2rtcEngine(engineConfig)\n await this.engine.initialize()\n\n context.logger.info(`go2rtc started (PID: ${this.process.pid}, API: ${processConfig.apiPort})`)\n }\n\n async shutdown(): Promise<void> {\n await this.engine?.shutdown()\n this.engine = null\n this.registeredDevices.clear()\n\n if (this.process) {\n this.process.kill('SIGTERM')\n this.process = null\n }\n }\n\n getEngine(): Go2rtcEngine {\n if (!this.engine) throw new Error('go2rtc not initialized')\n return this.engine\n }\n\n getCapabilityProvider<K extends keyof CapabilityProviderMap>(\n name: K,\n ): CapabilityProviderMap[K] | null {\n if (name === 'streaming-engine' && this.engine) {\n return this.engine as unknown as CapabilityProviderMap[K]\n }\n if (name === 'restreamer') {\n return this as unknown as CapabilityProviderMap[K]\n }\n if (name === 'webrtc') {\n return this as unknown as CapabilityProviderMap[K]\n }\n return null\n }\n\n // --- IRestreamer implementation ---\n\n async registerDevice(deviceId: string, streams: readonly RegisteredStream[]): Promise<void> {\n if (!this.engine) {\n throw new Error('go2rtc not initialized — cannot register device')\n }\n\n const streamIds: string[] = []\n\n for (const stream of streams) {\n streamIds.push(stream.streamId)\n\n // Register the stream with go2rtc using the broker's local TCP URL.\n // The broker is the sole reader from the camera; go2rtc consumes the\n // broker's TCP pipe instead of connecting to the camera directly.\n if (stream.sourceUrl) {\n await this.engine.registerStream(stream.streamId, {\n url: `ffmpeg:${stream.sourceUrl}#video=${stream.codec}`,\n protocol: 'rtsp',\n deviceId,\n providerId: 'broker',\n })\n }\n }\n\n this.registeredDevices.set(deviceId, {\n deviceId,\n streams,\n streamIds,\n })\n }\n\n pushPacket(_streamId: string, _packet: EncodedPacket): void {\n // Packet push from the broker is a no-op — go2rtc reads directly from\n // the broker's local TCP pipe server instead.\n }\n\n async unregisterDevice(deviceId: string): Promise<void> {\n const registration = this.registeredDevices.get(deviceId)\n if (!registration) {\n return\n }\n\n if (this.engine) {\n for (const streamId of registration.streamIds) {\n try {\n await this.engine.unregisterStream(streamId)\n } catch {\n // Best-effort cleanup\n }\n }\n }\n\n this.registeredDevices.delete(deviceId)\n }\n\n getExposedResources(deviceId: string): readonly ExposedResource[] {\n const registration = this.registeredDevices.get(deviceId)\n if (!registration || !this.engine) {\n return []\n }\n\n const resources: ExposedResource[] = []\n\n for (const streamId of registration.streamIds) {\n const webrtcUrl = this.engine.getStreamUrl(streamId, 'webrtc')\n if (webrtcUrl) {\n resources.push({ type: 'url', format: 'webrtc', value: webrtcUrl })\n }\n\n const hlsUrl = this.engine.getStreamUrl(streamId, 'hls')\n if (hlsUrl) {\n resources.push({ type: 'url', format: 'hls', value: hlsUrl })\n }\n\n const mjpegUrl = this.engine.getStreamUrl(streamId, 'mjpeg')\n if (mjpegUrl) {\n resources.push({ type: 'url', format: 'mjpeg', value: mjpegUrl })\n }\n\n const rtspUrl = this.engine.getStreamUrl(streamId, 'rtsp')\n if (rtspUrl) {\n resources.push({ type: 'url', format: 'rtsp', value: rtspUrl })\n }\n }\n\n return resources\n }\n\n async proxyWhepOffer(streamId: string, sdpOffer: string): Promise<string> {\n if (!this.engine) {\n throw new Error('go2rtc not initialized — cannot proxy WHEP')\n }\n return this.engine.proxyWhepOffer(streamId, sdpOffer)\n }\n\n // --- End IRestreamer ---\n\n // --- IWebRtcProvider implementation ---\n\n async handleOffer(streamId: string, sdpOffer: string): Promise<string> {\n if (!this.engine) {\n throw new Error('go2rtc not initialized — cannot handle WebRTC offer')\n }\n return this.engine.proxyWhepOffer(streamId, sdpOffer)\n }\n\n supportsStream(streamId: string): boolean {\n const deviceId = streamId.split('/')[0]\n return deviceId !== undefined && this.registeredDevices.has(deviceId)\n }\n\n async registerStream(streamId: string, _codec: string): Promise<void> {\n // Stream registration is handled via registerDevice (IRestreamer).\n // This is a no-op since go2rtc manages streams through its own API.\n const deviceId = streamId.split('/')[0]\n if (deviceId && !this.registeredDevices.has(deviceId)) {\n this.registeredDevices.set(deviceId, {\n deviceId,\n streams: [{ streamId, label: streamId, codec: _codec, type: 'video' }],\n streamIds: [streamId],\n })\n }\n }\n\n async unregisterStream(streamId: string): Promise<void> {\n if (!this.engine) {\n return\n }\n try {\n await this.engine.unregisterStream(streamId)\n } catch {\n // Best-effort cleanup\n }\n }\n\n // --- End IWebRtcProvider ---\n\n /** Exposed for testing */\n async waitForReady(url: string, timeoutMs: number): Promise<void> {\n const start = Date.now()\n while (Date.now() - start < timeoutMs) {\n try {\n const res = await fetch(url)\n if (res.ok) return\n } catch {\n // Not ready yet\n }\n await new Promise((r) => setTimeout(r, 500))\n }\n throw new Error(`go2rtc did not become ready within ${timeoutMs}ms`)\n }\n\n getConfigSchema(): ConfigUISchema {\n return {\n sections: [\n {\n id: 'go2rtc-info',\n title: 'go2rtc',\n fields: [\n {\n type: 'info',\n key: 'binary-info',\n label: 'Binary',\n content: 'go2rtc is automatically downloaded on first boot. The binary is stored in the data directory.',\n variant: 'info',\n },\n ],\n },\n {\n id: 'go2rtc-ports',\n title: 'Network Ports',\n description: 'Port configuration for the go2rtc restreamer. Changes require a restart.',\n columns: 3,\n fields: [\n {\n type: 'info',\n key: 'restart-note',\n label: 'Restart required',\n content: 'Port changes require restarting go2rtc.',\n variant: 'warning',\n },\n {\n type: 'number',\n key: 'apiPort',\n label: 'API Port',\n description: 'go2rtc HTTP API',\n min: 1024,\n max: 65535,\n step: 1,\n },\n {\n type: 'number',\n key: 'rtspPort',\n label: 'RTSP Port',\n description: 'RTSP restream output',\n min: 1024,\n max: 65535,\n step: 1,\n },\n {\n type: 'number',\n key: 'webrtcPort',\n label: 'WebRTC Port',\n description: 'WebRTC UDP/TCP',\n min: 1024,\n max: 65535,\n step: 1,\n },\n ],\n },\n ],\n }\n }\n\n getConfig(): Record<string, unknown> {\n return { ...this.currentConfig }\n }\n\n async onConfigChange(config: Record<string, unknown>): Promise<void> {\n this.currentConfig = {\n binaryPath: (config.binaryPath as string) ?? this.currentConfig.binaryPath,\n apiPort: (config.apiPort as number) ?? this.currentConfig.apiPort,\n rtspPort: (config.rtspPort as number) ?? this.currentConfig.rtspPort,\n webrtcPort: (config.webrtcPort as number) ?? this.currentConfig.webrtcPort,\n }\n }\n}\n","import type {\n IStreamingEngine,\n StreamFormat,\n StreamInfo,\n StreamingSource,\n StreamStatus,\n} from '@camstack/types'\n\nexport interface Go2rtcConfig {\n readonly apiPort: number\n readonly rtspPort: number\n readonly webrtcPort: number\n readonly binaryPath?: string\n}\n\nexport class Go2rtcEngine implements IStreamingEngine {\n private readonly baseUrl: string\n private readonly streams = new Map<string, StreamingSource>()\n\n constructor(private readonly config: Go2rtcConfig) {\n this.baseUrl = `http://127.0.0.1:${config.apiPort}`\n }\n\n async initialize(_config?: Record<string, unknown>): Promise<void> {\n try {\n const res = await fetch(`${this.baseUrl}/api/streams`)\n if (!res.ok) {\n throw new Error(`go2rtc API returned ${res.status}`)\n }\n } catch (err) {\n throw new Error(\n `Failed to reach go2rtc at ${this.baseUrl}: ${err instanceof Error ? err.message : String(err)}`,\n )\n }\n }\n\n async shutdown(): Promise<void> {\n this.streams.clear()\n }\n\n async registerStream(streamId: string, source: StreamingSource): Promise<void> {\n const url = `${this.baseUrl}/api/streams?src=${encodeURIComponent(streamId)}&url=${encodeURIComponent(source.url)}`\n const res = await fetch(url, { method: 'PUT' })\n if (!res.ok) {\n throw new Error(`go2rtc registerStream failed: ${res.status}`)\n }\n this.streams.set(streamId, source)\n }\n\n async unregisterStream(streamId: string): Promise<void> {\n const url = `${this.baseUrl}/api/streams?src=${encodeURIComponent(streamId)}`\n const res = await fetch(url, { method: 'DELETE' })\n if (!res.ok) {\n throw new Error(`go2rtc unregisterStream failed: ${res.status}`)\n }\n this.streams.delete(streamId)\n }\n\n getStreamUrl(streamId: string, format: StreamFormat): string | null {\n const encoded = encodeURIComponent(streamId)\n switch (format) {\n case 'webrtc':\n return `${this.baseUrl}/api/webrtc?src=${encoded}`\n case 'hls':\n return `${this.baseUrl}/api/stream.m3u8?src=${encoded}`\n case 'mjpeg':\n return `${this.baseUrl}/api/frame.jpeg?src=${encoded}`\n case 'rtsp':\n return `rtsp://127.0.0.1:${this.config.rtspPort}/${streamId}`\n default:\n return null\n }\n }\n\n async proxyWhepOffer(streamId: string, sdpOffer: string): Promise<string> {\n const url = `${this.baseUrl}/api/webrtc?src=${encodeURIComponent(streamId)}`\n const res = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/sdp' },\n body: sdpOffer,\n })\n if (!res.ok) {\n throw new Error(`go2rtc WHEP failed: ${res.status}`)\n }\n return res.text()\n }\n\n listStreams(): StreamInfo[] {\n return [...this.streams.entries()].map(([id, source]) => ({\n streamId: id,\n source,\n formats: ['webrtc', 'hls', 'mjpeg', 'rtsp'] as StreamFormat[],\n }))\n }\n\n getStreamStatus(streamId: string): StreamStatus | null {\n if (!this.streams.has(streamId)) return null\n return { active: true, viewers: 0 }\n }\n}\n","export interface Go2rtcGeneratedConfig {\n api: { listen: string }\n rtsp: { listen: string }\n webrtc: { listen: string }\n streams: Record<string, string[]>\n}\n\nexport function generateGo2rtcConfig(config: {\n apiPort: number\n rtspPort: number\n webrtcPort: number\n}): string {\n const yaml = `\napi:\n listen: \":${config.apiPort}\"\n\nrtsp:\n listen: \":${config.rtspPort}\"\n\nwebrtc:\n listen: \":${config.webrtcPort}\"\n ice_servers: []\n\nstreams: {}\n`\n return yaml.trim()\n}\n","/**\n * Auto-download go2rtc binary for the current platform.\n * Uses IAddonDepsManager (ctx.deps) for binary management.\n */\nimport type { IAddonDepsManager } from '@camstack/types'\n\nconst GO2RTC_VERSION = '1.9.14'\nconst BASE_URL = `https://github.com/AlexxIT/go2rtc/releases/download/v${GO2RTC_VERSION}`\n\nfunction getGo2rtcDownloadUrl(): { url: string; isArchive: boolean; archiveFormat?: 'zip' } {\n const os = process.platform\n const rawArch = process.arch\n\n let arch: string\n switch (rawArch) {\n case 'x64': arch = 'amd64'; break\n case 'arm64': arch = 'arm64'; break\n case 'arm': arch = 'arm'; break\n case 'ia32': arch = 'i386'; break\n default: throw new Error(`Unsupported architecture: ${rawArch}`)\n }\n\n switch (os) {\n case 'darwin':\n return { url: `${BASE_URL}/go2rtc_mac_${arch}.zip`, isArchive: true, archiveFormat: 'zip' }\n case 'linux':\n return { url: `${BASE_URL}/go2rtc_linux_${arch}`, isArchive: false }\n case 'win32':\n return { url: `${BASE_URL}/go2rtc_win_${arch}.zip`, isArchive: true, archiveFormat: 'zip' }\n default:\n throw new Error(`Unsupported platform: ${os}`)\n }\n}\n\n/**\n * Ensure go2rtc binary is available.\n * Returns the absolute path to the binary.\n */\nexport async function ensureGo2rtcBinary(deps: IAddonDepsManager): Promise<string> {\n const { url, isArchive, archiveFormat } = getGo2rtcDownloadUrl()\n\n return deps.ensureBinary({\n name: 'go2rtc',\n downloadUrl: url,\n isArchive,\n archiveFormat,\n })\n}\n"],"mappings":"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","names":[]}
@@ -1,79 +0,0 @@
1
- import { EncodedPacket, IStreamingEngine, StreamingSource, StreamFormat, StreamInfo, StreamStatus, ICamstackAddon, IConfigurable, IRestreamer, AddonManifest, AddonContext, CapabilityProviderMap, RegisteredStream, RestreamerExposedResource, ConfigUISchema } from '@camstack/types';
2
-
3
- /**
4
- * IWebRtcProvider interface — copied from server/backend/src/interfaces/webrtc-provider.ts
5
- * to avoid cross-package dependency.
6
- */
7
-
8
- interface IWebRtcProvider {
9
- readonly id: string;
10
- readonly name: string;
11
- /** Negotiate SDP for a specific stream */
12
- handleOffer(streamId: string, sdpOffer: string): Promise<string>;
13
- /** Check if this provider can serve the stream */
14
- supportsStream(streamId: string): boolean;
15
- /** Register a stream so the provider knows about it */
16
- registerStream(streamId: string, codec: string): Promise<void>;
17
- /** Push encoded packets (provider needs video data to serve WebRTC) */
18
- pushPacket(streamId: string, packet: EncodedPacket): void;
19
- /** Unregister a stream */
20
- unregisterStream(streamId: string): Promise<void>;
21
- }
22
-
23
- interface Go2rtcConfig {
24
- readonly apiPort: number;
25
- readonly rtspPort: number;
26
- readonly webrtcPort: number;
27
- readonly binaryPath?: string;
28
- }
29
- declare class Go2rtcEngine implements IStreamingEngine {
30
- private readonly config;
31
- private readonly baseUrl;
32
- private readonly streams;
33
- constructor(config: Go2rtcConfig);
34
- initialize(_config?: Record<string, unknown>): Promise<void>;
35
- shutdown(): Promise<void>;
36
- registerStream(streamId: string, source: StreamingSource): Promise<void>;
37
- unregisterStream(streamId: string): Promise<void>;
38
- getStreamUrl(streamId: string, format: StreamFormat): string | null;
39
- proxyWhepOffer(streamId: string, sdpOffer: string): Promise<string>;
40
- listStreams(): StreamInfo[];
41
- getStreamStatus(streamId: string): StreamStatus | null;
42
- }
43
-
44
- interface Go2rtcProcessConfig {
45
- readonly apiPort: number;
46
- readonly rtspPort: number;
47
- readonly webrtcPort: number;
48
- readonly binaryPath: string;
49
- }
50
- declare class Go2rtcAddon implements ICamstackAddon, IConfigurable, IRestreamer, IWebRtcProvider {
51
- readonly manifest: AddonManifest;
52
- /** IRestreamer identity */
53
- readonly id = "go2rtc";
54
- readonly name = "go2rtc Restreamer";
55
- private engine;
56
- private process;
57
- private readonly registeredDevices;
58
- private currentConfig;
59
- initialize(context: AddonContext): Promise<void>;
60
- shutdown(): Promise<void>;
61
- getEngine(): Go2rtcEngine;
62
- getCapabilityProvider<K extends keyof CapabilityProviderMap>(name: K): CapabilityProviderMap[K] | null;
63
- registerDevice(deviceId: string, streams: readonly RegisteredStream[]): Promise<void>;
64
- pushPacket(_streamId: string, _packet: EncodedPacket): void;
65
- unregisterDevice(deviceId: string): Promise<void>;
66
- getExposedResources(deviceId: string): readonly RestreamerExposedResource[];
67
- proxyWhepOffer(streamId: string, sdpOffer: string): Promise<string>;
68
- handleOffer(streamId: string, sdpOffer: string): Promise<string>;
69
- supportsStream(streamId: string): boolean;
70
- registerStream(streamId: string, _codec: string): Promise<void>;
71
- unregisterStream(streamId: string): Promise<void>;
72
- /** Exposed for testing */
73
- waitForReady(url: string, timeoutMs: number): Promise<void>;
74
- getConfigSchema(): ConfigUISchema;
75
- getConfig(): Record<string, unknown>;
76
- onConfigChange(config: Record<string, unknown>): Promise<void>;
77
- }
78
-
79
- export { Go2rtcAddon as G, type Go2rtcConfig as a, Go2rtcEngine as b, type Go2rtcProcessConfig as c };
@@ -1,79 +0,0 @@
1
- import { EncodedPacket, IStreamingEngine, StreamingSource, StreamFormat, StreamInfo, StreamStatus, ICamstackAddon, IConfigurable, IRestreamer, AddonManifest, AddonContext, CapabilityProviderMap, RegisteredStream, RestreamerExposedResource, ConfigUISchema } from '@camstack/types';
2
-
3
- /**
4
- * IWebRtcProvider interface — copied from server/backend/src/interfaces/webrtc-provider.ts
5
- * to avoid cross-package dependency.
6
- */
7
-
8
- interface IWebRtcProvider {
9
- readonly id: string;
10
- readonly name: string;
11
- /** Negotiate SDP for a specific stream */
12
- handleOffer(streamId: string, sdpOffer: string): Promise<string>;
13
- /** Check if this provider can serve the stream */
14
- supportsStream(streamId: string): boolean;
15
- /** Register a stream so the provider knows about it */
16
- registerStream(streamId: string, codec: string): Promise<void>;
17
- /** Push encoded packets (provider needs video data to serve WebRTC) */
18
- pushPacket(streamId: string, packet: EncodedPacket): void;
19
- /** Unregister a stream */
20
- unregisterStream(streamId: string): Promise<void>;
21
- }
22
-
23
- interface Go2rtcConfig {
24
- readonly apiPort: number;
25
- readonly rtspPort: number;
26
- readonly webrtcPort: number;
27
- readonly binaryPath?: string;
28
- }
29
- declare class Go2rtcEngine implements IStreamingEngine {
30
- private readonly config;
31
- private readonly baseUrl;
32
- private readonly streams;
33
- constructor(config: Go2rtcConfig);
34
- initialize(_config?: Record<string, unknown>): Promise<void>;
35
- shutdown(): Promise<void>;
36
- registerStream(streamId: string, source: StreamingSource): Promise<void>;
37
- unregisterStream(streamId: string): Promise<void>;
38
- getStreamUrl(streamId: string, format: StreamFormat): string | null;
39
- proxyWhepOffer(streamId: string, sdpOffer: string): Promise<string>;
40
- listStreams(): StreamInfo[];
41
- getStreamStatus(streamId: string): StreamStatus | null;
42
- }
43
-
44
- interface Go2rtcProcessConfig {
45
- readonly apiPort: number;
46
- readonly rtspPort: number;
47
- readonly webrtcPort: number;
48
- readonly binaryPath: string;
49
- }
50
- declare class Go2rtcAddon implements ICamstackAddon, IConfigurable, IRestreamer, IWebRtcProvider {
51
- readonly manifest: AddonManifest;
52
- /** IRestreamer identity */
53
- readonly id = "go2rtc";
54
- readonly name = "go2rtc Restreamer";
55
- private engine;
56
- private process;
57
- private readonly registeredDevices;
58
- private currentConfig;
59
- initialize(context: AddonContext): Promise<void>;
60
- shutdown(): Promise<void>;
61
- getEngine(): Go2rtcEngine;
62
- getCapabilityProvider<K extends keyof CapabilityProviderMap>(name: K): CapabilityProviderMap[K] | null;
63
- registerDevice(deviceId: string, streams: readonly RegisteredStream[]): Promise<void>;
64
- pushPacket(_streamId: string, _packet: EncodedPacket): void;
65
- unregisterDevice(deviceId: string): Promise<void>;
66
- getExposedResources(deviceId: string): readonly RestreamerExposedResource[];
67
- proxyWhepOffer(streamId: string, sdpOffer: string): Promise<string>;
68
- handleOffer(streamId: string, sdpOffer: string): Promise<string>;
69
- supportsStream(streamId: string): boolean;
70
- registerStream(streamId: string, _codec: string): Promise<void>;
71
- unregisterStream(streamId: string): Promise<void>;
72
- /** Exposed for testing */
73
- waitForReady(url: string, timeoutMs: number): Promise<void>;
74
- getConfigSchema(): ConfigUISchema;
75
- getConfig(): Record<string, unknown>;
76
- onConfigChange(config: Record<string, unknown>): Promise<void>;
77
- }
78
-
79
- export { Go2rtcAddon as G, type Go2rtcConfig as a, Go2rtcEngine as b, type Go2rtcProcessConfig as c };
@@ -1,2 +0,0 @@
1
- import '@camstack/types';
2
- export { G as Go2rtcAddon, c as Go2rtcProcessConfig } from './go2rtc.addon-CONM8rgq.mjs';
@@ -1,2 +0,0 @@
1
- import '@camstack/types';
2
- export { G as Go2rtcAddon, c as Go2rtcProcessConfig } from './go2rtc.addon-CONM8rgq.js';
package/dist/index.d.mts DELETED
@@ -1,22 +0,0 @@
1
- export { G as Go2rtcAddon, a as Go2rtcConfig, b as Go2rtcEngine, c as Go2rtcProcessConfig } from './go2rtc.addon-CONM8rgq.mjs';
2
- import '@camstack/types';
3
-
4
- interface Go2rtcGeneratedConfig {
5
- api: {
6
- listen: string;
7
- };
8
- rtsp: {
9
- listen: string;
10
- };
11
- webrtc: {
12
- listen: string;
13
- };
14
- streams: Record<string, string[]>;
15
- }
16
- declare function generateGo2rtcConfig(config: {
17
- apiPort: number;
18
- rtspPort: number;
19
- webrtcPort: number;
20
- }): string;
21
-
22
- export { type Go2rtcGeneratedConfig, generateGo2rtcConfig };