@camstack/addon-go2rtc 0.1.13 → 0.1.14

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.
@@ -2,13 +2,16 @@
2
2
  import { spawn } from "child_process";
3
3
  import { mkdirSync, writeFileSync } from "fs";
4
4
  import { join, dirname } from "path";
5
+ import { BaseAddon, streamingEngineCapability, restreamerCapability, webrtcCapability } from "@camstack/types";
5
6
 
6
7
  // src/go2rtc-engine.ts
8
+ import { errMsg } from "@camstack/types";
7
9
  var Go2rtcEngine = class {
8
10
  constructor(config) {
9
11
  this.config = config;
10
12
  this.baseUrl = `http://127.0.0.1:${config.apiPort}`;
11
13
  }
14
+ config;
12
15
  baseUrl;
13
16
  streams = /* @__PURE__ */ new Map();
14
17
  async initialize(_config) {
@@ -19,7 +22,8 @@ var Go2rtcEngine = class {
19
22
  }
20
23
  } catch (err) {
21
24
  throw new Error(
22
- `Failed to reach go2rtc at ${this.baseUrl}: ${err instanceof Error ? err.message : String(err)}`
25
+ `Failed to reach go2rtc at ${this.baseUrl}: ${errMsg(err)}`,
26
+ { cause: err }
23
27
  );
24
28
  }
25
29
  }
@@ -145,52 +149,42 @@ async function ensureGo2rtcBinary(deps) {
145
149
  }
146
150
 
147
151
  // 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
- };
152
+ var Go2rtcAddon = class extends BaseAddon {
155
153
  /** IRestreamer identity */
156
154
  id = "go2rtc";
157
155
  name = "go2rtc Restreamer";
158
156
  engine = null;
159
- process = null;
157
+ childProc = null;
160
158
  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);
159
+ constructor() {
160
+ super({ apiPort: 1984, rtspPort: 8554, webrtcPort: 8555, binaryPath: "go2rtc" });
161
+ }
162
+ async onInitialize() {
163
+ const dataPath = await this.ctx.api.storage.resolve.query({ location: "data", relativePath: "" }).catch(() => "camstack-data");
164
+ const resolvedBinaryPath = await ensureGo2rtcBinary(this.ctx.deps);
170
165
  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,
166
+ apiPort: this.config.apiPort,
167
+ rtspPort: this.config.rtspPort,
168
+ webrtcPort: this.config.webrtcPort,
174
169
  binaryPath: resolvedBinaryPath
175
170
  };
176
- this.currentConfig = processConfig;
177
171
  const configYaml = generateGo2rtcConfig(processConfig);
178
172
  const configPath = join(dataPath, "go2rtc.yaml");
179
173
  mkdirSync(dirname(configPath), { recursive: true });
180
174
  writeFileSync(configPath, configYaml);
181
- this.process = spawn(processConfig.binaryPath, ["-config", configPath], {
175
+ this.childProc = spawn(processConfig.binaryPath, ["-config", configPath], {
182
176
  stdio: ["pipe", "pipe", "pipe"]
183
177
  });
184
- this.process.on("exit", (code, signal) => {
185
- context.logger.warn(`go2rtc process exited (code: ${code}, signal: ${signal})`);
178
+ this.childProc.on("exit", (code, signal) => {
179
+ this.ctx.logger.warn("go2rtc process exited", { meta: { code, signal } });
186
180
  });
187
- this.process.stderr?.on("data", (data) => {
181
+ this.childProc.stderr?.on("data", (data) => {
188
182
  const msg = data.toString().trim();
189
- if (msg) context.logger.debug(`go2rtc stderr: ${msg}`);
183
+ if (msg) this.ctx.logger.debug("go2rtc stderr", { meta: { line: msg } });
190
184
  });
191
- this.process.stdout?.on("data", (data) => {
185
+ this.childProc.stdout?.on("data", (data) => {
192
186
  const msg = data.toString().trim();
193
- if (msg) context.logger.debug(`go2rtc stdout: ${msg}`);
187
+ if (msg) this.ctx.logger.debug("go2rtc stdout", { meta: { line: msg } });
194
188
  });
195
189
  const apiUrl = `http://127.0.0.1:${processConfig.apiPort}/api/streams`;
196
190
  await this.waitForReady(apiUrl, 1e4);
@@ -202,33 +196,28 @@ var Go2rtcAddon = class {
202
196
  };
203
197
  this.engine = new Go2rtcEngine(engineConfig);
204
198
  await this.engine.initialize();
205
- context.logger.info(`go2rtc started (PID: ${this.process.pid}, API: ${processConfig.apiPort})`);
199
+ this.ctx.logger.info("go2rtc started", {
200
+ meta: { pid: this.childProc.pid, apiPort: processConfig.apiPort }
201
+ });
202
+ return [
203
+ { capability: streamingEngineCapability, provider: this.engine },
204
+ { capability: restreamerCapability, provider: this },
205
+ { capability: webrtcCapability, provider: this }
206
+ ];
206
207
  }
207
- async shutdown() {
208
+ async onShutdown() {
208
209
  await this.engine?.shutdown();
209
210
  this.engine = null;
210
211
  this.registeredDevices.clear();
211
- if (this.process) {
212
- this.process.kill("SIGTERM");
213
- this.process = null;
212
+ if (this.childProc) {
213
+ this.childProc.kill("SIGTERM");
214
+ this.childProc = null;
214
215
  }
215
216
  }
216
217
  getEngine() {
217
218
  if (!this.engine) throw new Error("go2rtc not initialized");
218
219
  return this.engine;
219
220
  }
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
221
  // --- IRestreamer implementation ---
233
222
  async registerDevice(deviceId, streams) {
234
223
  if (!this.engine) {
@@ -241,7 +230,7 @@ var Go2rtcAddon = class {
241
230
  await this.engine.registerStream(stream.streamId, {
242
231
  url: `ffmpeg:${stream.sourceUrl}#video=${stream.codec}`,
243
232
  protocol: "rtsp",
244
- deviceId,
233
+ deviceId: `${deviceId}`,
245
234
  providerId: "broker"
246
235
  });
247
236
  }
@@ -310,12 +299,17 @@ var Go2rtcAddon = class {
310
299
  return this.engine.proxyWhepOffer(streamId, sdpOffer);
311
300
  }
312
301
  supportsStream(streamId) {
313
- const deviceId = streamId.split("/")[0];
314
- return deviceId !== void 0 && this.registeredDevices.has(deviceId);
302
+ const prefix = streamId.split("/")[0];
303
+ if (!prefix) return false;
304
+ const deviceId = Number(prefix);
305
+ return Number.isFinite(deviceId) && this.registeredDevices.has(deviceId);
315
306
  }
316
307
  async registerStream(streamId, _codec) {
317
- const deviceId = streamId.split("/")[0];
318
- if (deviceId && !this.registeredDevices.has(deviceId)) {
308
+ const prefix = streamId.split("/")[0];
309
+ if (!prefix) return;
310
+ const deviceId = Number(prefix);
311
+ if (!Number.isFinite(deviceId)) return;
312
+ if (!this.registeredDevices.has(deviceId)) {
319
313
  this.registeredDevices.set(deviceId, {
320
314
  deviceId,
321
315
  streams: [{ streamId, label: streamId, codec: _codec, type: "video" }],
@@ -332,6 +326,14 @@ var Go2rtcAddon = class {
332
326
  } catch {
333
327
  }
334
328
  }
329
+ /**
330
+ * go2rtc does not implement adaptive bitrate — it proxies the source
331
+ * stream at its native resolution/bitrate. Use addon-webrtc-adaptive
332
+ * for clients that need dynamic quality adjustment.
333
+ */
334
+ hasAdaptiveBitrate(_streamId) {
335
+ return false;
336
+ }
335
337
  // --- End IWebRtcProvider ---
336
338
  /** Exposed for testing */
337
339
  async waitForReady(url, timeoutMs) {
@@ -346,8 +348,8 @@ var Go2rtcAddon = class {
346
348
  }
347
349
  throw new Error(`go2rtc did not become ready within ${timeoutMs}ms`);
348
350
  }
349
- getConfigSchema() {
350
- return {
351
+ globalSettingsSchema() {
352
+ return this.schema({
351
353
  sections: [
352
354
  {
353
355
  id: "go2rtc-info",
@@ -357,7 +359,7 @@ var Go2rtcAddon = class {
357
359
  type: "info",
358
360
  key: "binary-info",
359
361
  label: "Binary",
360
- content: "go2rtc is automatically downloaded on first boot. The binary is stored in the data directory.",
362
+ content: "go2rtc is automatically downloaded on first boot.",
361
363
  variant: "info"
362
364
  }
363
365
  ]
@@ -365,7 +367,7 @@ var Go2rtcAddon = class {
365
367
  {
366
368
  id: "go2rtc-ports",
367
369
  title: "Network Ports",
368
- description: "Port configuration for the go2rtc restreamer. Changes require a restart.",
370
+ description: "Port configuration. Changes require a restart.",
369
371
  columns: 3,
370
372
  fields: [
371
373
  {
@@ -375,48 +377,40 @@ var Go2rtcAddon = class {
375
377
  content: "Port changes require restarting go2rtc.",
376
378
  variant: "warning"
377
379
  },
378
- {
380
+ this.field({
379
381
  type: "number",
380
382
  key: "apiPort",
381
383
  label: "API Port",
382
384
  description: "go2rtc HTTP API",
383
385
  min: 1024,
384
386
  max: 65535,
385
- step: 1
386
- },
387
- {
387
+ step: 1,
388
+ default: 1984
389
+ }),
390
+ this.field({
388
391
  type: "number",
389
392
  key: "rtspPort",
390
393
  label: "RTSP Port",
391
394
  description: "RTSP restream output",
392
395
  min: 1024,
393
396
  max: 65535,
394
- step: 1
395
- },
396
- {
397
+ step: 1,
398
+ default: 8554
399
+ }),
400
+ this.field({
397
401
  type: "number",
398
402
  key: "webrtcPort",
399
403
  label: "WebRTC Port",
400
404
  description: "WebRTC UDP/TCP",
401
405
  min: 1024,
402
406
  max: 65535,
403
- step: 1
404
- }
407
+ step: 1,
408
+ default: 8555
409
+ })
405
410
  ]
406
411
  }
407
412
  ]
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
- };
413
+ });
420
414
  }
421
415
  };
422
416
 
@@ -425,4 +419,4 @@ export {
425
419
  generateGo2rtcConfig,
426
420
  Go2rtcAddon
427
421
  };
428
- //# sourceMappingURL=chunk-R6UZ6HX4.mjs.map
422
+ //# sourceMappingURL=chunk-QV2FOMZN.mjs.map
@@ -0,0 +1 @@
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 ProviderRegistration,\n IRestreamer,\n RegisteredStream,\n RestreamerExposedResource as ExposedResource,\n EncodedPacket,\n} from '@camstack/types'\nimport { BaseAddon, streamingEngineCapability, restreamerCapability, webrtcCapability } from '@camstack/types'\nimport type { IWebRtcProvider } from '@camstack/types'\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: number\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 extends BaseAddon<Go2rtcProcessConfig> implements IRestreamer, IWebRtcProvider {\n /** IRestreamer identity */\n readonly id = 'go2rtc'\n readonly name = 'go2rtc Restreamer'\n\n private engine: Go2rtcEngine | null = null\n private childProc: ChildProcess | null = null\n private readonly registeredDevices = new Map<number, DeviceRegistration>()\n\n constructor() {\n super({ apiPort: 1984, rtspPort: 8554, webrtcPort: 8555, binaryPath: 'go2rtc' })\n }\n\n protected async onInitialize(): Promise<ProviderRegistration[]> {\n const dataPath = await this.ctx.api.storage.resolve.query({ location: 'data', relativePath: '' })\n .catch(() => 'camstack-data')\n\n const resolvedBinaryPath = await ensureGo2rtcBinary(this.ctx.deps)\n\n const processConfig: Go2rtcProcessConfig = {\n apiPort: this.config.apiPort,\n rtspPort: this.config.rtspPort,\n webrtcPort: this.config.webrtcPort,\n binaryPath: resolvedBinaryPath,\n }\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.childProc = spawn(processConfig.binaryPath, ['-config', configPath], {\n stdio: ['pipe', 'pipe', 'pipe'],\n })\n\n this.childProc.on('exit', (code, signal) => {\n this.ctx.logger.warn('go2rtc process exited', { meta: { code, signal } })\n })\n\n this.childProc.stderr?.on('data', (data: Buffer) => {\n const msg = data.toString().trim()\n if (msg) this.ctx.logger.debug('go2rtc stderr', { meta: { line: msg } })\n })\n\n this.childProc.stdout?.on('data', (data: Buffer) => {\n const msg = data.toString().trim()\n if (msg) this.ctx.logger.debug('go2rtc stdout', { meta: { line: 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 this.ctx.logger.info('go2rtc started', {\n meta: { pid: this.childProc.pid, apiPort: processConfig.apiPort },\n })\n\n return [\n { capability: streamingEngineCapability, provider: this.engine },\n { capability: restreamerCapability, provider: this },\n { capability: webrtcCapability, provider: this },\n ]\n }\n\n protected async onShutdown(): Promise<void> {\n await this.engine?.shutdown()\n this.engine = null\n this.registeredDevices.clear()\n\n if (this.childProc) {\n this.childProc.kill('SIGTERM')\n this.childProc = null\n }\n }\n\n getEngine(): Go2rtcEngine {\n if (!this.engine) throw new Error('go2rtc not initialized')\n return this.engine\n }\n\n // --- IRestreamer implementation ---\n\n async registerDevice(deviceId: number, 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: `${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: number): 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: number): 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 prefix = streamId.split('/')[0]\n if (!prefix) return false\n const deviceId = Number(prefix)\n return Number.isFinite(deviceId) && 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 prefix = streamId.split('/')[0]\n if (!prefix) return\n const deviceId = Number(prefix)\n if (!Number.isFinite(deviceId)) return\n if (!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 /**\n * go2rtc does not implement adaptive bitrate — it proxies the source\n * stream at its native resolution/bitrate. Use addon-webrtc-adaptive\n * for clients that need dynamic quality adjustment.\n */\n hasAdaptiveBitrate(_streamId: string): boolean {\n return false\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 protected globalSettingsSchema() {\n return this.schema({\n sections: [\n {\n id: 'go2rtc-info',\n title: 'go2rtc',\n fields: [\n {\n type: 'info' as const,\n key: 'binary-info',\n label: 'Binary',\n content: 'go2rtc is automatically downloaded on first boot.',\n variant: 'info' as const,\n },\n ],\n },\n {\n id: 'go2rtc-ports',\n title: 'Network Ports',\n description: 'Port configuration. Changes require a restart.',\n columns: 3,\n fields: [\n {\n type: 'info' as const,\n key: 'restart-note',\n label: 'Restart required',\n content: 'Port changes require restarting go2rtc.',\n variant: 'warning' as const,\n },\n this.field({\n type: 'number', key: 'apiPort', label: 'API Port',\n description: 'go2rtc HTTP API', min: 1024, max: 65535, step: 1, default: 1984,\n }),\n this.field({\n type: 'number', key: 'rtspPort', label: 'RTSP Port',\n description: 'RTSP restream output', min: 1024, max: 65535, step: 1, default: 8554,\n }),\n this.field({\n type: 'number', key: 'webrtcPort', label: 'WebRTC Port',\n description: 'WebRTC UDP/TCP', min: 1024, max: 65535, step: 1, default: 8555,\n }),\n ],\n },\n ],\n })\n }\n\n}\n","import { errMsg } from '@camstack/types'\nimport 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}: ${errMsg(err)}`,\n { cause: 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,24 +1,5 @@
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
- }
1
+ import * as _camstack_types from '@camstack/types';
2
+ import { IStreamingEngine, StreamingSource, StreamFormat, StreamInfo, StreamStatus, BaseAddon, IRestreamer, IWebRtcProvider, ProviderRegistration, RegisteredStream, EncodedPacket, RestreamerExposedResource } from '@camstack/types';
22
3
 
23
4
  interface Go2rtcConfig {
24
5
  readonly apiPort: number;
@@ -47,33 +28,35 @@ interface Go2rtcProcessConfig {
47
28
  readonly webrtcPort: number;
48
29
  readonly binaryPath: string;
49
30
  }
50
- declare class Go2rtcAddon implements ICamstackAddon, IConfigurable, IRestreamer, IWebRtcProvider {
51
- readonly manifest: AddonManifest;
31
+ declare class Go2rtcAddon extends BaseAddon<Go2rtcProcessConfig> implements IRestreamer, IWebRtcProvider {
52
32
  /** IRestreamer identity */
53
33
  readonly id = "go2rtc";
54
34
  readonly name = "go2rtc Restreamer";
55
35
  private engine;
56
- private process;
36
+ private childProc;
57
37
  private readonly registeredDevices;
58
- private currentConfig;
59
- initialize(context: AddonContext): Promise<void>;
60
- shutdown(): Promise<void>;
38
+ constructor();
39
+ protected onInitialize(): Promise<ProviderRegistration[]>;
40
+ protected onShutdown(): Promise<void>;
61
41
  getEngine(): Go2rtcEngine;
62
- getCapabilityProvider<K extends keyof CapabilityProviderMap>(name: K): CapabilityProviderMap[K] | null;
63
- registerDevice(deviceId: string, streams: readonly RegisteredStream[]): Promise<void>;
42
+ registerDevice(deviceId: number, streams: readonly RegisteredStream[]): Promise<void>;
64
43
  pushPacket(_streamId: string, _packet: EncodedPacket): void;
65
- unregisterDevice(deviceId: string): Promise<void>;
66
- getExposedResources(deviceId: string): readonly RestreamerExposedResource[];
44
+ unregisterDevice(deviceId: number): Promise<void>;
45
+ getExposedResources(deviceId: number): readonly RestreamerExposedResource[];
67
46
  proxyWhepOffer(streamId: string, sdpOffer: string): Promise<string>;
68
47
  handleOffer(streamId: string, sdpOffer: string): Promise<string>;
69
48
  supportsStream(streamId: string): boolean;
70
49
  registerStream(streamId: string, _codec: string): Promise<void>;
71
50
  unregisterStream(streamId: string): Promise<void>;
51
+ /**
52
+ * go2rtc does not implement adaptive bitrate — it proxies the source
53
+ * stream at its native resolution/bitrate. Use addon-webrtc-adaptive
54
+ * for clients that need dynamic quality adjustment.
55
+ */
56
+ hasAdaptiveBitrate(_streamId: string): boolean;
72
57
  /** Exposed for testing */
73
58
  waitForReady(url: string, timeoutMs: number): Promise<void>;
74
- getConfigSchema(): ConfigUISchema;
75
- getConfig(): Record<string, unknown>;
76
- onConfigChange(config: Record<string, unknown>): Promise<void>;
59
+ protected globalSettingsSchema(): _camstack_types.ConfigUISchema;
77
60
  }
78
61
 
79
62
  export { Go2rtcAddon as G, type Go2rtcConfig as a, Go2rtcEngine as b, type Go2rtcProcessConfig as c };
@@ -1,24 +1,5 @@
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
- }
1
+ import * as _camstack_types from '@camstack/types';
2
+ import { IStreamingEngine, StreamingSource, StreamFormat, StreamInfo, StreamStatus, BaseAddon, IRestreamer, IWebRtcProvider, ProviderRegistration, RegisteredStream, EncodedPacket, RestreamerExposedResource } from '@camstack/types';
22
3
 
23
4
  interface Go2rtcConfig {
24
5
  readonly apiPort: number;
@@ -47,33 +28,35 @@ interface Go2rtcProcessConfig {
47
28
  readonly webrtcPort: number;
48
29
  readonly binaryPath: string;
49
30
  }
50
- declare class Go2rtcAddon implements ICamstackAddon, IConfigurable, IRestreamer, IWebRtcProvider {
51
- readonly manifest: AddonManifest;
31
+ declare class Go2rtcAddon extends BaseAddon<Go2rtcProcessConfig> implements IRestreamer, IWebRtcProvider {
52
32
  /** IRestreamer identity */
53
33
  readonly id = "go2rtc";
54
34
  readonly name = "go2rtc Restreamer";
55
35
  private engine;
56
- private process;
36
+ private childProc;
57
37
  private readonly registeredDevices;
58
- private currentConfig;
59
- initialize(context: AddonContext): Promise<void>;
60
- shutdown(): Promise<void>;
38
+ constructor();
39
+ protected onInitialize(): Promise<ProviderRegistration[]>;
40
+ protected onShutdown(): Promise<void>;
61
41
  getEngine(): Go2rtcEngine;
62
- getCapabilityProvider<K extends keyof CapabilityProviderMap>(name: K): CapabilityProviderMap[K] | null;
63
- registerDevice(deviceId: string, streams: readonly RegisteredStream[]): Promise<void>;
42
+ registerDevice(deviceId: number, streams: readonly RegisteredStream[]): Promise<void>;
64
43
  pushPacket(_streamId: string, _packet: EncodedPacket): void;
65
- unregisterDevice(deviceId: string): Promise<void>;
66
- getExposedResources(deviceId: string): readonly RestreamerExposedResource[];
44
+ unregisterDevice(deviceId: number): Promise<void>;
45
+ getExposedResources(deviceId: number): readonly RestreamerExposedResource[];
67
46
  proxyWhepOffer(streamId: string, sdpOffer: string): Promise<string>;
68
47
  handleOffer(streamId: string, sdpOffer: string): Promise<string>;
69
48
  supportsStream(streamId: string): boolean;
70
49
  registerStream(streamId: string, _codec: string): Promise<void>;
71
50
  unregisterStream(streamId: string): Promise<void>;
51
+ /**
52
+ * go2rtc does not implement adaptive bitrate — it proxies the source
53
+ * stream at its native resolution/bitrate. Use addon-webrtc-adaptive
54
+ * for clients that need dynamic quality adjustment.
55
+ */
56
+ hasAdaptiveBitrate(_streamId: string): boolean;
72
57
  /** Exposed for testing */
73
58
  waitForReady(url: string, timeoutMs: number): Promise<void>;
74
- getConfigSchema(): ConfigUISchema;
75
- getConfig(): Record<string, unknown>;
76
- onConfigChange(config: Record<string, unknown>): Promise<void>;
59
+ protected globalSettingsSchema(): _camstack_types.ConfigUISchema;
77
60
  }
78
61
 
79
62
  export { Go2rtcAddon as G, type Go2rtcConfig as a, Go2rtcEngine as b, type Go2rtcProcessConfig as c };
@@ -1,2 +1,2 @@
1
1
  import '@camstack/types';
2
- export { G as Go2rtcAddon, c as Go2rtcProcessConfig } from './go2rtc.addon-CONM8rgq.mjs';
2
+ export { G as Go2rtcAddon, c as Go2rtcProcessConfig } from './go2rtc.addon-D9qkXBV6.mjs';
@@ -1,2 +1,2 @@
1
1
  import '@camstack/types';
2
- export { G as Go2rtcAddon, c as Go2rtcProcessConfig } from './go2rtc.addon-CONM8rgq.js';
2
+ export { G as Go2rtcAddon, c as Go2rtcProcessConfig } from './go2rtc.addon-D9qkXBV6.js';