@ceralive/cerastream 2026.9.2 → 2026.9.4

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.
package/README.md CHANGED
@@ -10,12 +10,17 @@ engine's JSON-RPC 2.0 / NDJSON control plane over a Unix domain socket.
10
10
  - Two-tier error codes (RPC + runtime)
11
11
  - Typed capture-probe causes retained on runtime events and rejected-start exceptions
12
12
  - Typed platform capture-converter reporting (`librga`, `v4l2-rga2`, or `none`)
13
+ - Typed RK3588 composition config (secondary input, six PiP/PbP layouts, alpha),
14
+ gated by the READY-trialled `composition` capability token
13
15
  - A unified engine config schema (= `start` params)
14
16
  - A `CerastreamClient` interface + `connect()` factory (UDS transport)
15
17
  - Additive `client.getCapabilities()` discovery for platform, source, encoder, and
16
18
  local preview availability
19
+ - Per-codec encoder capability entries with format, resolution/framerate, and
20
+ explicit 4K60 qualification-gate truth
17
21
  - Additive `client.changeConfig()` — reconfigure the live session (resolution,
18
- framerate, codec, pipeline, source) as one transaction with typed rollback
22
+ framerate, codec, pipeline, source) as one transaction with typed rollback;
23
+ composition-only changes use live layout/alpha writes and secondary rebind
19
24
 
20
25
  The Zod schemas, types, and constants are the frozen wire contract; `connect()`
21
26
  drives that contract over an NDJSON/UDS transport with no native dependencies.
package/dist/client.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { type HelloResult } from './envelope.js';
2
2
  import { type EventParams } from './events.js';
3
- import { type ChangeConfigParams, type ChangeConfigResult, type GetCapabilitiesResult, type ListDevicesParams, type ListDevicesResult, type PreviewSessionParams, type PreviewSessionResult, type ReloadConfigParams, type ReloadConfigResult, type SetBitrateParams, type SetBitrateResult, type StartParams, type StartResult, type StopParams, type StopResult, type SubscribeEventsParams, type SubscribeEventsResult, type SwitchInputParams, type SwitchInputResult } from './messages.js';
3
+ import { type ChangeConfigParams, type ChangeConfigResult, type GetCapabilitiesResult, type ListDevicesParams, type ListDevicesResult, type PreviewSessionParams, type PreviewSessionResult, type ReloadConfigParams, type ReloadConfigResult, type RequestKeyframeResult, type SetBitrateParams, type SetBitrateResult, type StartParams, type StartResult, type StopParams, type StopResult, type SubscribeEventsParams, type SubscribeEventsResult, type SwitchInputParams, type SwitchInputResult } from './messages.js';
4
4
  /** Options for {@link connect}. All optional — `connect({})` is valid. */
5
5
  export interface ConnectOptions {
6
6
  /** Control socket path override. Defaults to the resolved /run/cerastream/control.sock. */
@@ -64,6 +64,7 @@ export interface CerastreamClient {
64
64
  * @throws {CerastreamRpcError} when the value is out of the configured range.
65
65
  */
66
66
  setBitrate(params: SetBitrateParams): Promise<SetBitrateResult>;
67
+ requestKeyframe(): Promise<RequestKeyframeResult>;
67
68
  /**
68
69
  * Switch the active capture source (manual) or hand selection to failover (auto).
69
70
  * @param params The target input id and switch mode.
package/dist/client.js CHANGED
@@ -3,7 +3,7 @@ import { CONTROL_SOCKET_PATH, PROTOCOL_VERSION } from './constants.js';
3
3
  import { helloResultSchema, rpcErrorSchema, rpcResponseSchema, } from './envelope.js';
4
4
  import { CerastreamConnectionError, CerastreamRpcError, CerastreamTimeoutError, } from './errors.js';
5
5
  import { eventParamsSchema } from './events.js';
6
- import { changeConfigParamsSchema, changeConfigResultSchema, getCapabilitiesResultSchema, requestSchemas, } from './messages.js';
6
+ import { changeConfigParamsSchema, changeConfigResultSchema, getCapabilitiesResultSchema, requestKeyframeResultSchema, requestSchemas, } from './messages.js';
7
7
  import { controlSocketPath } from './paths.js';
8
8
  import { LineSocket } from './transport.js';
9
9
  const DEFAULTS = {
@@ -70,6 +70,9 @@ class ClientImpl {
70
70
  setBitrate(params) {
71
71
  return this.call('set-bitrate', params);
72
72
  }
73
+ async requestKeyframe() {
74
+ return requestKeyframeResultSchema.parse(await this.rawRequest('request-keyframe', {}));
75
+ }
73
76
  switchInput(params) {
74
77
  return this.call('switch-input', params);
75
78
  }
@@ -8,7 +8,7 @@ export declare const PROTOCOL_VERSION: 'cerastream-ipc/1';
8
8
  * additive-only within protocol major `cerastream-ipc/1` (ADR-0002 §4); this value
9
9
  * only moves when the wire schema itself does, in lockstep across both languages.
10
10
  */
11
- export declare const SCHEMA_VERSION: '0.13.0';
11
+ export declare const SCHEMA_VERSION: '0.16.0';
12
12
  /** Runtime dir holding both control + preview sockets. systemd `RuntimeDirectory=cerastream`. */
13
13
  export declare const DEFAULT_IPC_DIR: '/run/cerastream';
14
14
  /** Env override for the IPC dir (tests/dev). Defaults to {@link DEFAULT_IPC_DIR}. */
@@ -65,6 +65,8 @@ export declare const PROFILE_CATALOG_VERSION: '1.0.0';
65
65
  * the Rust `PIPEWIRE_CAPTURE_FEATURE`.
66
66
  */
67
67
  export declare const PIPEWIRE_CAPTURE_FEATURE: 'pipewire-capture';
68
+ /** Two-leg RK3588 composition, emitted only after `rgacompositor` passes READY. */
69
+ export declare const COMPOSITION_FEATURE: 'composition';
68
70
  /**
69
71
  * Named engine features `get-capabilities` advertises in `features`. This is the
70
72
  * fail-closed negotiation contract: CeraUI sends a new out-of-schema field ONLY
@@ -76,7 +78,7 @@ export declare const PIPEWIRE_CAPTURE_FEATURE: 'pipewire-capture';
76
78
  * array, never on membership here — a configuration-dependent token is filtered
77
79
  * out of the response the engine actually sends.
78
80
  */
79
- export declare const ENGINE_FEATURES: readonly ['video-passthrough', 'input-mode', 'audio-pcm-spec', "pipewire-capture"];
81
+ export declare const ENGINE_FEATURES: readonly ['video-passthrough', 'input-mode', 'audio-pcm-spec', "pipewire-capture", "composition"];
80
82
  /** Engine binary name (systemd-owned; CeraUI never spawns it — ADR-0005). */
81
83
  export declare const CERASTREAM_BIN: 'cerastream';
82
84
  export declare const DEFAULT_MIN_BITRATE = 300;
package/dist/constants.js CHANGED
@@ -11,7 +11,7 @@ export const PROTOCOL_VERSION = 'cerastream-ipc/1';
11
11
  * additive-only within protocol major `cerastream-ipc/1` (ADR-0002 §4); this value
12
12
  * only moves when the wire schema itself does, in lockstep across both languages.
13
13
  */
14
- export const SCHEMA_VERSION = '0.13.0';
14
+ export const SCHEMA_VERSION = '0.16.0';
15
15
  /** Runtime dir holding both control + preview sockets. systemd `RuntimeDirectory=cerastream`. */
16
16
  export const DEFAULT_IPC_DIR = '/run/cerastream';
17
17
  /** Env override for the IPC dir (tests/dev). Defaults to {@link DEFAULT_IPC_DIR}. */
@@ -74,6 +74,8 @@ export const PROFILE_CATALOG_VERSION = '1.0.0';
74
74
  * the Rust `PIPEWIRE_CAPTURE_FEATURE`.
75
75
  */
76
76
  export const PIPEWIRE_CAPTURE_FEATURE = 'pipewire-capture';
77
+ /** Two-leg RK3588 composition, emitted only after `rgacompositor` passes READY. */
78
+ export const COMPOSITION_FEATURE = 'composition';
77
79
  /**
78
80
  * Named engine features `get-capabilities` advertises in `features`. This is the
79
81
  * fail-closed negotiation contract: CeraUI sends a new out-of-schema field ONLY
@@ -90,6 +92,7 @@ export const ENGINE_FEATURES = [
90
92
  'input-mode',
91
93
  'audio-pcm-spec',
92
94
  PIPEWIRE_CAPTURE_FEATURE,
95
+ COMPOSITION_FEATURE,
93
96
  ];
94
97
  /** Engine binary name (systemd-owned; CeraUI never spawns it — ADR-0005). */
95
98
  export const CERASTREAM_BIN = 'cerastream';
package/dist/errors.d.ts CHANGED
@@ -96,19 +96,27 @@ export declare const processErrorCodeSchema: z.ZodEnum<{
96
96
  }>;
97
97
  export type ProcessErrorCode = z.infer<typeof processErrorCodeSchema>;
98
98
  export declare const captureCauseSchema: z.ZodEnum<{
99
+ "composition-unsupported": "composition-unsupported";
100
+ "decoder-unavailable": "decoder-unavailable";
99
101
  device_busy: "device_busy";
100
102
  negotiation_failed: "negotiation_failed";
101
103
  no_signal: "no_signal";
102
104
  no_silicon_converter: "no_silicon_converter";
105
+ "secondary-unavailable": "secondary-unavailable";
106
+ "software-pixel-path-rejected": "software-pixel-path-rejected";
103
107
  }>;
104
108
  export type CaptureCause = z.infer<typeof captureCauseSchema>;
105
109
  export declare const captureCauseEntrySchema: z.ZodObject<{
106
110
  device: z.ZodString;
107
111
  cause: z.ZodEnum<{
112
+ "composition-unsupported": "composition-unsupported";
113
+ "decoder-unavailable": "decoder-unavailable";
108
114
  device_busy: "device_busy";
109
115
  negotiation_failed: "negotiation_failed";
110
116
  no_signal: "no_signal";
111
117
  no_silicon_converter: "no_silicon_converter";
118
+ "secondary-unavailable": "secondary-unavailable";
119
+ "software-pixel-path-rejected": "software-pixel-path-rejected";
112
120
  }>;
113
121
  }, z.core.$strip>;
114
122
  export type CaptureCauseEntry = z.infer<typeof captureCauseEntrySchema>;
package/dist/errors.js CHANGED
@@ -143,6 +143,10 @@ export const captureCauseSchema = z.enum([
143
143
  'no_signal',
144
144
  'device_busy',
145
145
  'no_silicon_converter',
146
+ 'decoder-unavailable',
147
+ 'software-pixel-path-rejected',
148
+ 'composition-unsupported',
149
+ 'secondary-unavailable',
146
150
  ]);
147
151
  export const captureCauseEntrySchema = z.object({
148
152
  device: z.string(),
package/dist/events.d.ts CHANGED
@@ -240,10 +240,14 @@ export declare const runtimeErrorEventSchema: z.ZodObject<{
240
240
  reason: z.ZodOptional<z.ZodString>;
241
241
  selected: z.ZodOptional<z.ZodBoolean>;
242
242
  capture_cause: z.ZodOptional<z.ZodEnum<{
243
+ "composition-unsupported": "composition-unsupported";
244
+ "decoder-unavailable": "decoder-unavailable";
243
245
  device_busy: "device_busy";
244
246
  negotiation_failed: "negotiation_failed";
245
247
  no_signal: "no_signal";
246
248
  no_silicon_converter: "no_silicon_converter";
249
+ "secondary-unavailable": "secondary-unavailable";
250
+ "software-pixel-path-rejected": "software-pixel-path-rejected";
247
251
  }>>;
248
252
  }, z.core.$strip>;
249
253
  /** Payload of a {@link runtimeErrorEventSchema} event. */
@@ -464,10 +468,14 @@ export declare const eventParamsSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
464
468
  reason: z.ZodOptional<z.ZodString>;
465
469
  selected: z.ZodOptional<z.ZodBoolean>;
466
470
  capture_cause: z.ZodOptional<z.ZodEnum<{
471
+ "composition-unsupported": "composition-unsupported";
472
+ "decoder-unavailable": "decoder-unavailable";
467
473
  device_busy: "device_busy";
468
474
  negotiation_failed: "negotiation_failed";
469
475
  no_signal: "no_signal";
470
476
  no_silicon_converter: "no_silicon_converter";
477
+ "secondary-unavailable": "secondary-unavailable";
478
+ "software-pixel-path-rejected": "software-pixel-path-rejected";
471
479
  }>>;
472
480
  }, z.core.$strip>, z.ZodObject<{
473
481
  type: z.ZodLiteral<"preview">;
@@ -662,10 +670,14 @@ export declare const cerastreamEventSchema: z.ZodObject<{
662
670
  reason: z.ZodOptional<z.ZodString>;
663
671
  selected: z.ZodOptional<z.ZodBoolean>;
664
672
  capture_cause: z.ZodOptional<z.ZodEnum<{
673
+ "composition-unsupported": "composition-unsupported";
674
+ "decoder-unavailable": "decoder-unavailable";
665
675
  device_busy: "device_busy";
666
676
  negotiation_failed: "negotiation_failed";
667
677
  no_signal: "no_signal";
668
678
  no_silicon_converter: "no_silicon_converter";
679
+ "secondary-unavailable": "secondary-unavailable";
680
+ "software-pixel-path-rejected": "software-pixel-path-rejected";
669
681
  }>>;
670
682
  }, z.core.$strip>, z.ZodObject<{
671
683
  type: z.ZodLiteral<"preview">;
@@ -869,10 +881,14 @@ export declare const eventSchemas: {
869
881
  reason: z.ZodOptional<z.ZodString>;
870
882
  selected: z.ZodOptional<z.ZodBoolean>;
871
883
  capture_cause: z.ZodOptional<z.ZodEnum<{
884
+ "composition-unsupported": "composition-unsupported";
885
+ "decoder-unavailable": "decoder-unavailable";
872
886
  device_busy: "device_busy";
873
887
  negotiation_failed: "negotiation_failed";
874
888
  no_signal: "no_signal";
875
889
  no_silicon_converter: "no_silicon_converter";
890
+ "secondary-unavailable": "secondary-unavailable";
891
+ "software-pixel-path-rejected": "software-pixel-path-rejected";
876
892
  }>>;
877
893
  }, z.core.$strip>;
878
894
  readonly preview: z.ZodObject<{
@@ -22,6 +22,7 @@ export declare const startParamsSchema: z.ZodObject<{
22
22
  }, z.core.$strip>;
23
23
  input_id: z.ZodOptional<z.ZodString>;
24
24
  codec: z.ZodOptional<z.ZodEnum<{
25
+ av1: "av1";
25
26
  h264: "h264";
26
27
  h265: "h265";
27
28
  }>>;
@@ -56,6 +57,18 @@ export declare const startParamsSchema: z.ZodObject<{
56
57
  uvc_h264: "uvc_h264";
57
58
  uvc_h265: "uvc_h265";
58
59
  }>>;
60
+ composition: z.ZodOptional<z.ZodObject<{
61
+ secondary_input_id: z.ZodString;
62
+ layout: z.ZodEnum<{
63
+ "pbp-left-right": "pbp-left-right";
64
+ "pbp-top-bottom": "pbp-top-bottom";
65
+ "pip-bottom-left": "pip-bottom-left";
66
+ "pip-bottom-right": "pip-bottom-right";
67
+ "pip-top-left": "pip-top-left";
68
+ "pip-top-right": "pip-top-right";
69
+ }>;
70
+ alpha: z.ZodOptional<z.ZodNumber>;
71
+ }, z.core.$strip>>;
59
72
  }, z.core.$strip>;
60
73
  export type StartParams = z.infer<typeof startParamsSchema>;
61
74
  export declare const startResultSchema: z.ZodObject<{
@@ -160,6 +173,12 @@ export declare const setBitrateResultSchema: z.ZodObject<{
160
173
  reason: z.ZodOptional<z.ZodString>;
161
174
  }, z.core.$strip>;
162
175
  export type SetBitrateResult = z.infer<typeof setBitrateResultSchema>;
176
+ export declare const requestKeyframeParamsSchema: z.ZodObject<{}, z.core.$strip>;
177
+ export type RequestKeyframeParams = z.infer<typeof requestKeyframeParamsSchema>;
178
+ export declare const requestKeyframeResultSchema: z.ZodObject<{
179
+ applied: z.ZodLiteral<true>;
180
+ }, z.core.$strip>;
181
+ export type RequestKeyframeResult = z.infer<typeof requestKeyframeResultSchema>;
163
182
  export declare const switchInputParamsSchema: z.ZodObject<{
164
183
  input_id: z.ZodString;
165
184
  mode: z.ZodDefault<z.ZodEnum<{
@@ -359,6 +378,27 @@ export declare const encoderCapsSchema: z.ZodObject<{
359
378
  }, z.core.$strip>;
360
379
  }, z.core.$strip>;
361
380
  export type EncoderCaps = z.infer<typeof encoderCapsSchema>;
381
+ export declare const encoderGateStatusSchema: z.ZodEnum<{
382
+ kept: "kept";
383
+ measured: "measured";
384
+ untested: "untested";
385
+ }>;
386
+ export type EncoderGateStatus = z.infer<typeof encoderGateStatusSchema>;
387
+ export declare const encoderCapabilitySchema: z.ZodObject<{
388
+ codec: z.ZodString;
389
+ max_resolution: z.ZodString;
390
+ max_framerate: z.ZodNumber;
391
+ formats: z.ZodArray<z.ZodString>;
392
+ gates: z.ZodObject<{
393
+ '4k60': z.ZodEnum<{
394
+ kept: "kept";
395
+ measured: "measured";
396
+ untested: "untested";
397
+ }>;
398
+ reason: z.ZodOptional<z.ZodString>;
399
+ }, z.core.$strip>;
400
+ }, z.core.$strip>;
401
+ export type EncoderCapability = z.infer<typeof encoderCapabilitySchema>;
362
402
  export declare const platformConverterSchema: z.ZodEnum<{
363
403
  librga: "librga";
364
404
  none: "none";
@@ -422,6 +462,20 @@ export declare const getCapabilitiesResultSchema: z.ZodObject<{
422
462
  unit: z.ZodString;
423
463
  }, z.core.$strip>;
424
464
  }, z.core.$strip>;
465
+ encoders: z.ZodOptional<z.ZodArray<z.ZodObject<{
466
+ codec: z.ZodString;
467
+ max_resolution: z.ZodString;
468
+ max_framerate: z.ZodNumber;
469
+ formats: z.ZodArray<z.ZodString>;
470
+ gates: z.ZodObject<{
471
+ '4k60': z.ZodEnum<{
472
+ kept: "kept";
473
+ measured: "measured";
474
+ untested: "untested";
475
+ }>;
476
+ reason: z.ZodOptional<z.ZodString>;
477
+ }, z.core.$strip>;
478
+ }, z.core.$strip>>>;
425
479
  sources: z.ZodArray<z.ZodObject<{
426
480
  id: z.ZodString;
427
481
  supports_audio: z.ZodBoolean;
@@ -457,6 +511,7 @@ export declare const getCapabilitiesResultSchema: z.ZodObject<{
457
511
  }, z.core.$strip>>;
458
512
  network_embedded_audio: z.ZodOptional<z.ZodBoolean>;
459
513
  features: z.ZodOptional<z.ZodArray<z.ZodString>>;
514
+ pixel_paths: z.ZodOptional<z.ZodLiteral<"silicon-only">>;
460
515
  }, z.core.$strip>;
461
516
  export type GetCapabilitiesResult = z.infer<typeof getCapabilitiesResultSchema>;
462
517
  export declare const changeConfigParamsSchema: z.ZodObject<{
@@ -464,6 +519,7 @@ export declare const changeConfigParamsSchema: z.ZodObject<{
464
519
  resolution: z.ZodOptional<z.ZodString>;
465
520
  framerate: z.ZodOptional<z.ZodNumber>;
466
521
  codec: z.ZodOptional<z.ZodEnum<{
522
+ av1: "av1";
467
523
  h264: "h264";
468
524
  h265: "h265";
469
525
  }>>;
@@ -478,6 +534,18 @@ export declare const changeConfigParamsSchema: z.ZodObject<{
478
534
  uvc_h264: "uvc_h264";
479
535
  uvc_h265: "uvc_h265";
480
536
  }>>;
537
+ composition: z.ZodOptional<z.ZodObject<{
538
+ secondary_input_id: z.ZodString;
539
+ layout: z.ZodEnum<{
540
+ "pbp-left-right": "pbp-left-right";
541
+ "pbp-top-bottom": "pbp-top-bottom";
542
+ "pip-bottom-left": "pip-bottom-left";
543
+ "pip-bottom-right": "pip-bottom-right";
544
+ "pip-top-left": "pip-top-left";
545
+ "pip-top-right": "pip-top-right";
546
+ }>;
547
+ alpha: z.ZodOptional<z.ZodNumber>;
548
+ }, z.core.$strip>>;
481
549
  }, z.core.$strip>;
482
550
  export type ChangeConfigParams = z.infer<typeof changeConfigParamsSchema>;
483
551
  export declare const changeConfigResultSchema: z.ZodObject<{
@@ -549,6 +617,7 @@ export declare const requestSchemas: {
549
617
  }, z.core.$strip>;
550
618
  input_id: z.ZodOptional<z.ZodString>;
551
619
  codec: z.ZodOptional<z.ZodEnum<{
620
+ av1: "av1";
552
621
  h264: "h264";
553
622
  h265: "h265";
554
623
  }>>;
@@ -583,6 +652,18 @@ export declare const requestSchemas: {
583
652
  uvc_h264: "uvc_h264";
584
653
  uvc_h265: "uvc_h265";
585
654
  }>>;
655
+ composition: z.ZodOptional<z.ZodObject<{
656
+ secondary_input_id: z.ZodString;
657
+ layout: z.ZodEnum<{
658
+ "pbp-left-right": "pbp-left-right";
659
+ "pbp-top-bottom": "pbp-top-bottom";
660
+ "pip-bottom-left": "pip-bottom-left";
661
+ "pip-bottom-right": "pip-bottom-right";
662
+ "pip-top-left": "pip-top-left";
663
+ "pip-top-right": "pip-top-right";
664
+ }>;
665
+ alpha: z.ZodOptional<z.ZodNumber>;
666
+ }, z.core.$strip>>;
586
667
  }, z.core.$strip>;
587
668
  readonly result: z.ZodObject<{
588
669
  session_id: z.ZodString;
package/dist/messages.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { z } from 'zod';
2
2
  import { AUDIO_DELAY_MAX_MS } from './constants.js';
3
3
  import { helloParamsSchema, helloResultSchema } from './envelope.js';
4
- import { audioBackendSchema, balancerAlgorithmSchema, bitrateControlSchema, captureDeviceKindSchema, captureDeviceSchema, cerastreamConfigSchema, configChangePhaseSchema, inputModeSchema, mediaClassSchema, previewEncodeModeSchema, previewTierSchema, streamStateSchema, videoCodecSchema, } from './types.js';
4
+ import { audioBackendSchema, balancerAlgorithmSchema, bitrateControlSchema, captureDeviceKindSchema, captureDeviceSchema, cerastreamConfigSchema, compositionConfigSchema, configChangePhaseSchema, inputModeSchema, mediaClassSchema, previewEncodeModeSchema, previewTierSchema, streamStateSchema, videoCodecSchema, } from './types.js';
5
5
  // The eight v1 control methods (schema.md "v1 messages"). Each is matched
6
6
  // byte-for-byte to schema.md: the JSON shape on the wire is the contract.
7
7
  // ---- 1. start ----
@@ -72,6 +72,8 @@ export const setBitrateResultSchema = z.object({
72
72
  bitrate_control: bitrateControlSchema.optional(),
73
73
  reason: z.string().optional(),
74
74
  });
75
+ export const requestKeyframeParamsSchema = z.object({});
76
+ export const requestKeyframeResultSchema = z.object({ applied: z.literal(true) });
75
77
  // ---- 5. switch-input ----
76
78
  export const switchInputParamsSchema = z.object({
77
79
  input_id: z.string(), // device/input identifier from list-devices
@@ -172,6 +174,17 @@ export const encoderCapsSchema = z.object({
172
174
  codecs: z.array(z.string()),
173
175
  bitrate_range: bitrateRangeCapsSchema,
174
176
  });
177
+ export const encoderGateStatusSchema = z.enum(['measured', 'kept', 'untested']);
178
+ export const encoderCapabilitySchema = z.object({
179
+ codec: z.string(),
180
+ max_resolution: z.string(),
181
+ max_framerate: z.number().int().positive(),
182
+ formats: z.array(z.string()),
183
+ gates: z.object({
184
+ '4k60': encoderGateStatusSchema,
185
+ reason: z.string().optional(),
186
+ }),
187
+ });
175
188
  export const platformConverterSchema = z.enum(['librga', 'v4l2-rga2', 'none']);
176
189
  export const platformCapsSchema = z.object({
177
190
  supports_h265: z.boolean(),
@@ -202,6 +215,7 @@ export const previewAvailabilitySchema = z.object({
202
215
  export const getCapabilitiesResultSchema = z.object({
203
216
  platform: platformCapsSchema,
204
217
  encoder: encoderCapsSchema,
218
+ encoders: z.array(encoderCapabilitySchema).optional(),
205
219
  sources: z.array(videoSourceCapSchema),
206
220
  audio_live_switch: z.boolean().optional(),
207
221
  audio_backends: z
@@ -217,6 +231,7 @@ export const getCapabilitiesResultSchema = z.object({
217
231
  preview: previewAvailabilitySchema.optional(), // preview-server availability (unbound vs down)
218
232
  network_embedded_audio: z.boolean().optional(), // engine routes network-ingest embedded audio to the mux
219
233
  features: z.array(z.string()).optional(), // named engine features (e.g. "video-passthrough") for fail-closed negotiation
234
+ pixel_paths: z.literal('silicon-only').optional(),
220
235
  });
221
236
  // ---- 10. change-config (0.10.0, additive) ----
222
237
  // Deliberately absent from V1_METHODS / requestSchemas, like get-capabilities and
@@ -239,6 +254,7 @@ export const changeConfigParamsSchema = z
239
254
  // engine runs a release → re-enumeration-barrier → open transaction and
240
255
  // rolls back honestly (reason: mode_barrier_timeout) if the barrier expires.
241
256
  input_mode: captureDeviceKindSchema.optional(),
257
+ composition: compositionConfigSchema.optional(),
242
258
  })
243
259
  .refine((delta) => Object.keys(delta).length > 0, {
244
260
  message: 'change-config delta must carry at least one field',
package/dist/types.d.ts CHANGED
@@ -40,6 +40,7 @@ export declare const previewEncodeFallbackSchema: z.ZodDiscriminatedUnion<[z.Zod
40
40
  }, z.core.$strip>], "code">;
41
41
  export type PreviewEncodeFallback = z.infer<typeof previewEncodeFallbackSchema>;
42
42
  export declare const videoCodecSchema: z.ZodEnum<{
43
+ av1: "av1";
43
44
  h264: "h264";
44
45
  h265: "h265";
45
46
  }>;
@@ -50,6 +51,30 @@ export declare const videoPassthroughSchema: z.ZodEnum<{
50
51
  off: "off";
51
52
  }>;
52
53
  export type VideoPassthrough = z.infer<typeof videoPassthroughSchema>;
54
+ /** Exact preset nicks accepted by the first-party `rgacompositor` element. */
55
+ export declare const compositionLayoutSchema: z.ZodEnum<{
56
+ "pbp-left-right": "pbp-left-right";
57
+ "pbp-top-bottom": "pbp-top-bottom";
58
+ "pip-bottom-left": "pip-bottom-left";
59
+ "pip-bottom-right": "pip-bottom-right";
60
+ "pip-top-left": "pip-top-left";
61
+ "pip-top-right": "pip-top-right";
62
+ }>;
63
+ export type CompositionLayout = z.infer<typeof compositionLayoutSchema>;
64
+ /** One secondary capture leg composited with the primary session input. */
65
+ export declare const compositionConfigSchema: z.ZodObject<{
66
+ secondary_input_id: z.ZodString;
67
+ layout: z.ZodEnum<{
68
+ "pbp-left-right": "pbp-left-right";
69
+ "pbp-top-bottom": "pbp-top-bottom";
70
+ "pip-bottom-left": "pip-bottom-left";
71
+ "pip-bottom-right": "pip-bottom-right";
72
+ "pip-top-left": "pip-top-left";
73
+ "pip-top-right": "pip-top-right";
74
+ }>;
75
+ alpha: z.ZodOptional<z.ZodNumber>;
76
+ }, z.core.$strip>;
77
+ export type CompositionConfig = z.infer<typeof compositionConfigSchema>;
53
78
  export declare const bitrateControlSchema: z.ZodEnum<{
54
79
  encoder: "encoder";
55
80
  "source-fixed": "source-fixed";
@@ -165,6 +190,7 @@ export declare const cerastreamConfigSchema: z.ZodObject<{
165
190
  }, z.core.$strip>;
166
191
  input_id: z.ZodOptional<z.ZodString>;
167
192
  codec: z.ZodOptional<z.ZodEnum<{
193
+ av1: "av1";
168
194
  h264: "h264";
169
195
  h265: "h265";
170
196
  }>>;
@@ -199,6 +225,18 @@ export declare const cerastreamConfigSchema: z.ZodObject<{
199
225
  uvc_h264: "uvc_h264";
200
226
  uvc_h265: "uvc_h265";
201
227
  }>>;
228
+ composition: z.ZodOptional<z.ZodObject<{
229
+ secondary_input_id: z.ZodString;
230
+ layout: z.ZodEnum<{
231
+ "pbp-left-right": "pbp-left-right";
232
+ "pbp-top-bottom": "pbp-top-bottom";
233
+ "pip-bottom-left": "pip-bottom-left";
234
+ "pip-bottom-right": "pip-bottom-right";
235
+ "pip-top-left": "pip-top-left";
236
+ "pip-top-right": "pip-top-right";
237
+ }>;
238
+ alpha: z.ZodOptional<z.ZodNumber>;
239
+ }, z.core.$strip>>;
202
240
  }, z.core.$strip>;
203
241
  export type CerastreamConfig = z.infer<typeof cerastreamConfigSchema>;
204
242
  export type PartialCerastreamConfig = z.input<typeof cerastreamConfigSchema>;
package/dist/types.js CHANGED
@@ -28,12 +28,27 @@ export const previewEncodeFallbackSchema = z.discriminatedUnion('code', [
28
28
  // Requested egress video codec (0.4.0, additive). Absent ⇒ the engine picks its
29
29
  // platform default. Wire values are the codec id strings the encoder caps also
30
30
  // advertise ("h264"/"h265") — never an encoder element name.
31
- export const videoCodecSchema = z.enum(['h264', 'h265']);
31
+ export const videoCodecSchema = z.enum(['h264', 'h265', 'av1']);
32
32
  // Same-codec passthrough policy (0.5.0, additive). Absent ⇒ "auto". "auto" =
33
33
  // passthrough only when adaptive bitrate is inactive and eligibility holds;
34
34
  // "force" = passthrough whenever eligible (typed start failure otherwise);
35
35
  // "off" = always transcode. See schema.md and the engine's layer-C matrix.
36
36
  export const videoPassthroughSchema = z.enum(['auto', 'force', 'off']);
37
+ /** Exact preset nicks accepted by the first-party `rgacompositor` element. */
38
+ export const compositionLayoutSchema = z.enum([
39
+ 'pip-top-right',
40
+ 'pip-top-left',
41
+ 'pip-bottom-right',
42
+ 'pip-bottom-left',
43
+ 'pbp-left-right',
44
+ 'pbp-top-bottom',
45
+ ]);
46
+ /** One secondary capture leg composited with the primary session input. */
47
+ export const compositionConfigSchema = z.object({
48
+ secondary_input_id: z.string().min(1),
49
+ layout: compositionLayoutSchema,
50
+ alpha: z.number().min(0).max(1).optional(),
51
+ });
37
52
  // Which surface owns the running bitrate, reported additively on a set-bitrate /
38
53
  // reload-config response (0.5.0). "encoder" = applied; "source-fixed" = a
39
54
  // passthrough graph fixes the bitrate at the source, so the request was NOT
@@ -138,6 +153,7 @@ export const cerastreamConfigSchema = z.object({
138
153
  audio: audioConfigSchema.optional(), // additive (0.4.0): audio device/codec/signed delay
139
154
  video_passthrough: videoPassthroughSchema.optional(), // additive (0.5.0): auto|force|off; absent ⇒ auto
140
155
  input_mode: captureDeviceKindSchema.optional(), // additive (0.11.0): which MODE family of the selected device to capture in, naming a list-devices modes[].pipeline_kind. Absent ⇒ the engine's precedence pick (h265 → h264 → mjpeg → raw). The ONLY way to reach the non-precedence family of a dual-format camera; a family the device does not expose is a typed cerastream.params.invalid, never a silent fallback
156
+ composition: compositionConfigSchema.optional(),
141
157
  });
142
158
  // convenience defaults for building a config client-side
143
159
  export const DEFAULT_BITRATE_CONFIG = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ceralive/cerastream",
3
- "version": "2026.9.2",
3
+ "version": "2026.9.4",
4
4
  "description": "Type-safe TypeScript schema + IPC client for the cerastream streaming engine (JSON-RPC 2.0 / NDJSON over a Unix domain socket).",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",