obsbot-mcp 0.1.1 → 0.3.0

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
@@ -127,10 +127,78 @@ need ffmpeg — it grabs the frame through the native helper.
127
127
 
128
128
  - **Windows x64** — supported today. The native helper is built from source in `native/windows/`
129
129
  (CMake + MSVC); the published npm package ships a prebuilt binary so end users need no toolchain.
130
- - **Linux / macOS** — not yet implemented. The design is platform-agnostic (see [`PROTOCOL.md`](./PROTOCOL.md));
131
- adding support means writing an equivalent native helper for each OS's UVC control APIs
132
- (`V4L2` on Linux, `AVFoundation`/`IOKit` on macOS) behind the same JSON-RPC-over-stdio contract used by
133
- the Windows helper. Contributions welcome.
130
+ - **Linux x64** — supported from v0.2. The native helper is in `native/linux/` (CMake + GCC);
131
+ it uses **V4L2** for standard UVC controls (zoom, focus, exposure, pan/tilt, white balance,
132
+ image controls) and `UVCIOC_CTRL_QUERY` for vendor Extension Unit commands (gimbal, AI tracking,
133
+ wake/sleep, HDR, FOV). Snapshots capture a MJPEG or YUYV frame via V4L2 mmap streaming and encode
134
+ to JPEG using **libjpeg**. The `linux-x64` prebuilt binary ships with the published npm package.
135
+ Build dependencies: `build-essential cmake libjpeg-dev libv4l-dev`.
136
+ - **macOS 14+ (Apple Silicon and Intel)** — supported. The native helper is in `native/macos/`
137
+ (Objective-C + **IOKit**/**AVFoundation**). It uses IOKit USB control transfers for both standard
138
+ UVC controls and vendor Extension Unit commands, and AVFoundation for enumeration and snapshots.
139
+ Both `darwin-arm64` and `darwin-x64` prebuilt binaries ship with the published npm package
140
+ (`darwin-x64` also covers Apple Silicon running Node under Rosetta, where `process.arch` reports
141
+ `x64`). macOS 14 is the floor because the helper uses `AVCaptureDeviceTypeExternal`; the build
142
+ pins `-mmacosx-version-min` so the binary does not inherit the build machine's OS as its
143
+ minimum.
144
+
145
+ Note on macOS specifically: `UVCAssistant` (a DriverKit system extension) owns the camera's UVC
146
+ *interfaces* exclusively, so `USBInterfaceOpen` — and even `USBInterfaceOpenSeize` — fail with
147
+ `kIOReturnExclusiveAccess`. The helper therefore opens the USB *device*, which is not locked, and
148
+ issues UVC control requests on its default control endpoint. This coexists with `UVCAssistant`:
149
+ the camera keeps working as a normal webcam while under control, so no driver-replacement step
150
+ is needed.
151
+
152
+ ### Building the native helper (Linux)
153
+
154
+ ```bash
155
+ cd native/linux
156
+ mkdir build && cd build
157
+ cmake ..
158
+ make -j$(nproc)
159
+ make install # copies to native/prebuilt/linux-x64/
160
+ ```
161
+
162
+ ### Building the native helper (macOS)
163
+
164
+ ```bash
165
+ make -C native/macos # -> native/prebuilt/darwin-arm64/obsbot-helper
166
+ ```
167
+
168
+ Requires the Xcode command line tools. CMake works too (`cmake -S native/macos -B
169
+ native/macos/build && cmake --build native/macos/build`), which is what CI uses.
170
+
171
+ ## Known limitations
172
+
173
+ What has actually been exercised against hardware, and what hasn't:
174
+
175
+ | Platform | Status |
176
+ |---|---|
177
+ | `win32-x64` | Builds in CI |
178
+ | `linux-x64` | Builds in CI |
179
+ | `darwin-arm64` | **Hardware-verified** — control, gimbal, zoom, and snapshot on a real Tiny 2 |
180
+ | `darwin-x64` | **Build-verified only** — compiles with the right architecture and deployment target, never executed |
181
+
182
+ - **The Intel (`darwin-x64`) helper has never been run.** No Intel Mac was available to test it. It
183
+ cross-compiles cleanly and is packaged, but nothing has confirmed it talks to a camera. It also
184
+ covers Apple Silicon running Node under Rosetta, where `process.arch` reports `x64` — likewise
185
+ untested. Reports from Intel users are welcome.
186
+ - **macOS 14 or newer is required**, and macOS runtime is verified on **26.5 only**. The helper uses
187
+ `AVCaptureDeviceTypeExternal` (macOS 14+), so the build pins `-mmacosx-version-min=14.0`. The
188
+ binary will *load* on 14 through 25, but behavior there is untested — in particular the UVC
189
+ control path relies on `UVCAssistant` holding the camera's UVC interfaces while leaving the USB
190
+ device itself openable. That is how current macOS behaves; older releases are unconfirmed.
191
+ - **The first snapshot on macOS raises a camera permission prompt.** The helper is a plain CLI tool
192
+ with no bundle identifier, so macOS attributes camera access to whichever app spawned it — your
193
+ MCP client — and that app is named in the prompt and holds the grant. Approve once; the grant
194
+ survives helper updates, since it is keyed to the client rather than to the helper's signature.
195
+ - **The camera may not enumerate through a USB hub or dock.** A Tiny 2 connected through a USB-C
196
+ dock was invisible to `ioreg` and `system_profiler` entirely — not just to this server. If
197
+ `obsbot_list_devices` comes back empty, try a direct connection before assuming a software fault.
198
+ - **Only the OBSBOT Tiny 2 is supported.** On macOS the USB vendor/product IDs are hardcoded
199
+ (`0x3564`/`0xFEF8`), so no other model is detected at all. Windows and Linux match devices by
200
+ name, so a different OBSBOT may be *found* — but the vendor command set is Tiny 2 specific
201
+ either way.
134
202
 
135
203
  ## No proprietary SDK
136
204
 
@@ -151,11 +219,11 @@ mediating access and the camera remains usable as a normal webcam at the same ti
151
219
  are sent through the camera's UVC Extension Unit, driven via `IKsControl::KsProperty` against the
152
220
  XU's topology node on Windows.
153
221
 
154
- Both are issued through a small native helper process (`obsbot-helper.exe` on Windows) that the Node
155
- server spawns and talks to over a line-delimited JSON-RPC protocol on stdin/stdout. The helper is the
156
- only platform-specific piece; the codec (frame encoding, CRC-16/USB checksum, command table), transport
157
- abstraction, device manager, and MCP tool definitions are all pure TypeScript/JavaScript and shared across
158
- platforms.
222
+ Both are issued through a small native helper process (`obsbot-helper.exe` on Windows, `obsbot-helper`
223
+ on Linux) that the Node server spawns and talks to over a line-delimited JSON-RPC protocol on
224
+ stdin/stdout. The helper is the only platform-specific piece; the codec (frame encoding, CRC-16/USB
225
+ checksum, command table), transport abstraction, device manager, and MCP tool definitions are all pure
226
+ TypeScript/JavaScript and shared across platforms.
159
227
 
160
228
  ## Verifying against real hardware
161
229
 
@@ -3,9 +3,20 @@ export interface DshowDevices {
3
3
  video: string[];
4
4
  audio: string[];
5
5
  }
6
+ export interface V4l2DeviceInfo {
7
+ path: string;
8
+ card: string;
9
+ }
10
+ export interface V4l2Devices {
11
+ video: V4l2DeviceInfo[];
12
+ audio: string[];
13
+ }
14
+ export type DeviceList = DshowDevices | V4l2Devices;
6
15
  export declare function parseDshowDevices(stderr: string): DshowDevices;
7
- export declare function resolveVideoName(devices: DshowDevices, source: CaptureSource): string | undefined;
8
- export declare function resolveAudioName(devices: DshowDevices): string | undefined;
16
+ export declare function resolveVideoName(devices: DeviceList, source: CaptureSource): string | undefined;
17
+ export declare function resolveAudioName(devices: DeviceList): string | undefined;
18
+ /** Parse the v4l2 device name from `ffmpeg -f v4l2 -i /dev/videoN` stderr. */
19
+ export declare function parseV4l2DeviceName(stderr: string): string | undefined;
9
20
  export declare function buildRecordArgs(o: {
10
21
  videoName: string;
11
22
  audioName?: string;
@@ -15,3 +26,26 @@ export declare function buildRecordArgs(o: {
15
26
  export declare function buildPreviewArgs(o: {
16
27
  videoName: string;
17
28
  }): string[];
29
+ export interface AvfDevices {
30
+ /** Device indices, keyed by display name (the name shown by ffmpeg). */
31
+ video: Record<string, number>;
32
+ audio: Record<string, number>;
33
+ }
34
+ export declare function parseAvfDevices(stderr: string): AvfDevices;
35
+ export declare function resolveAvfVideoName(devices: AvfDevices, source: CaptureSource): {
36
+ name: string;
37
+ index: number;
38
+ } | undefined;
39
+ export declare function resolveAvfAudioName(devices: AvfDevices): {
40
+ name: string;
41
+ index: number;
42
+ } | undefined;
43
+ export declare function buildAvfRecordArgs(o: {
44
+ videoIndex: number;
45
+ audioIndex?: number;
46
+ durationSec: number;
47
+ outputPath: string;
48
+ }): string[];
49
+ export declare function buildAvfPreviewArgs(o: {
50
+ videoIndex: number;
51
+ }): string[];
@@ -1,6 +1,9 @@
1
+ // Pure helpers for the recording/preview subsystem: parse ffmpeg's dshow
2
+ // (Windows), v4l2 (Linux), or avfoundation (macOS) device listing and build the
3
+ // exact ffmpeg/ffplay argv arrays. No side effects.
4
+ // ---------- Windows (dshow) helpers ----------
1
5
  // ffmpeg -f dshow -list_devices prints one line per device on stderr:
2
6
  // [dshow @ ..] "Friendly Name" (video)
3
- // The name is the first quoted span; the trailing "(video)"/"(audio)" is the type.
4
7
  export function parseDshowDevices(stderr) {
5
8
  const video = [];
6
9
  const audio = [];
@@ -16,16 +19,61 @@ export function parseDshowDevices(stderr) {
16
19
  return { video, audio };
17
20
  }
18
21
  export function resolveVideoName(devices, source) {
19
- if (source === "virtual")
22
+ const isV4l = (d) => "video" in d && d.video.length > 0 && typeof d.video[0] !== "string";
23
+ if (source === "virtual") {
24
+ if (isV4l(devices)) {
25
+ return devices.video.find((n) => /OBSBOT Virtual Camera/i.test(n.card))?.path;
26
+ }
20
27
  return devices.video.find((n) => /OBSBOT Virtual Camera/i.test(n));
21
- if (source === "ndi")
28
+ }
29
+ if (source === "ndi") {
30
+ if (isV4l(devices)) {
31
+ return devices.video.find((n) => /NDI Webcam/i.test(n.card))?.path;
32
+ }
22
33
  return devices.video.find((n) => /NDI Webcam/i.test(n));
34
+ }
35
+ // Platform-specific device matching
36
+ if (isV4l(devices)) {
37
+ const found = devices.video.find((n) => /OBSBOT/i.test(n.card));
38
+ return found ? found.path : undefined;
39
+ }
40
+ // dshow on Windows
23
41
  return devices.video.find((n) => /OBSBOT Tiny 2/i.test(n) && !/Virtual/i.test(n));
24
42
  }
25
43
  export function resolveAudioName(devices) {
26
- return devices.audio.find((n) => /OBSBOT.*Mic/i.test(n));
44
+ if ("audio" in devices && Array.isArray(devices.audio)) {
45
+ return devices.audio.find((n) => /OBSBOT.*Mic/i.test(n));
46
+ }
47
+ // Linux v4l2 audio is typically a separate ALSA device
48
+ // Return undefined — callers should check and warn
49
+ return undefined;
50
+ }
51
+ // ---------- Linux (v4l2) helpers ----------
52
+ // ffmpeg -f v4l2 -list_formats all -i /dev/videoN lists formats on stderr.
53
+ /** Parse the v4l2 device name from `ffmpeg -f v4l2 -i /dev/videoN` stderr. */
54
+ export function parseV4l2DeviceName(stderr) {
55
+ // ffmpeg prints something like:
56
+ // [video4linux2,v4l2 @ 0x...] VideoDevice: /dev/videoN
57
+ // [video4linux2,v4l2 @ 0x...] driver : uvcvideo
58
+ // [video4linux2,v4l2 @ 0x...] card : OBSBOT Tiny 2 ...
59
+ const m = stderr.match(/card\s+:\s+(.+)/);
60
+ return m ? m[1].trim() : undefined;
27
61
  }
28
62
  export function buildRecordArgs(o) {
63
+ const isV4l2 = o.videoName.startsWith("/dev/");
64
+ if (isV4l2) {
65
+ return [
66
+ "-hide_banner", "-loglevel", "warning",
67
+ "-f", "v4l2",
68
+ "-i", o.videoName,
69
+ ...(o.audioName ? ["-f", "alsa", "-i", o.audioName] : []),
70
+ "-t", String(o.durationSec),
71
+ "-c:v", "libx264", "-pix_fmt", "yuv420p",
72
+ ...(o.audioName ? ["-c:a", "aac"] : []),
73
+ "-y", o.outputPath,
74
+ ];
75
+ }
76
+ // dshow path (Windows)
29
77
  const input = o.audioName
30
78
  ? `video=${o.videoName}:audio=${o.audioName}`
31
79
  : `video=${o.videoName}`;
@@ -39,10 +87,95 @@ export function buildRecordArgs(o) {
39
87
  ];
40
88
  }
41
89
  export function buildPreviewArgs(o) {
90
+ const isV4l2 = o.videoName.startsWith("/dev/");
91
+ if (isV4l2) {
92
+ return [
93
+ "-hide_banner", "-loglevel", "warning",
94
+ "-f", "v4l2",
95
+ "-input_format", "mjpeg",
96
+ "-video_size", "1920x1080",
97
+ "-i", o.videoName,
98
+ "-window_title", "OBSBOT preview",
99
+ ];
100
+ }
101
+ // dshow path
42
102
  return [
43
103
  "-hide_banner", "-loglevel", "warning", "-f", "dshow",
44
104
  "-i", `video=${o.videoName}`,
45
105
  "-window_title", "OBSBOT preview",
46
106
  ];
47
107
  }
108
+ // ffmpeg -f avfoundation -list_devices true -i "" prints on stderr:
109
+ // [AVFoundation indev @ 0x...] AVFoundation video devices:
110
+ // [AVFoundation indev @ 0x...] [0] FaceTime HD Camera
111
+ // [AVFoundation indev @ 0x...] [1] OBSBOT Tiny 2
112
+ // [AVFoundation indev @ 0x...] AVFoundation audio devices:
113
+ // [AVFoundation indev @ 0x...] [0] Built-in Microphone
114
+ // [AVFoundation indev @ 0x...] [1] OBSBOT Tiny 2 Microphone
115
+ export function parseAvfDevices(stderr) {
116
+ const video = {};
117
+ const audio = {};
118
+ let section = null;
119
+ for (const line of stderr.split(/\r?\n/)) {
120
+ if (/AVFoundation video devices/i.test(line)) {
121
+ section = "video";
122
+ continue;
123
+ }
124
+ if (/AVFoundation audio devices/i.test(line)) {
125
+ section = "audio";
126
+ continue;
127
+ }
128
+ if (!section)
129
+ continue;
130
+ const m = line.match(/\[\s*(\d+)\]\s+(.+)/);
131
+ if (m) {
132
+ const idx = parseInt(m[1], 10);
133
+ const name = m[2].trim();
134
+ if (section === "video")
135
+ video[name] = idx;
136
+ else
137
+ audio[name] = idx;
138
+ }
139
+ }
140
+ return { video, audio };
141
+ }
142
+ export function resolveAvfVideoName(devices, source) {
143
+ const names = Object.keys(devices.video);
144
+ let match;
145
+ if (source === "virtual")
146
+ match = names.find((n) => /OBSBOT Virtual Camera/i.test(n));
147
+ else if (source === "ndi")
148
+ match = names.find((n) => /NDI Webcam/i.test(n));
149
+ else
150
+ match = names.find((n) => /OBSBOT/i.test(n) && !/Virtual/i.test(n));
151
+ if (!match)
152
+ return undefined;
153
+ return { name: match, index: devices.video[match] };
154
+ }
155
+ export function resolveAvfAudioName(devices) {
156
+ const entry = Object.entries(devices.audio).find(([name]) => /OBSBOT.*Mic/i.test(name));
157
+ if (!entry)
158
+ return undefined;
159
+ return { name: entry[0], index: entry[1] };
160
+ }
161
+ export function buildAvfRecordArgs(o) {
162
+ const input = o.audioIndex !== undefined
163
+ ? `${o.videoIndex}:${o.audioIndex}`
164
+ : `${o.videoIndex}`;
165
+ return [
166
+ "-hide_banner", "-loglevel", "warning", "-f", "avfoundation",
167
+ "-i", input,
168
+ "-t", String(o.durationSec),
169
+ "-c:v", "libx264", "-pix_fmt", "yuv420p",
170
+ ...(o.audioIndex !== undefined ? ["-c:a", "aac"] : []),
171
+ "-y", o.outputPath,
172
+ ];
173
+ }
174
+ export function buildAvfPreviewArgs(o) {
175
+ return [
176
+ "-hide_banner", "-loglevel", "warning", "-f", "avfoundation",
177
+ "-i", `${o.videoIndex}`,
178
+ "-window_title", "OBSBOT preview",
179
+ ];
180
+ }
48
181
  //# sourceMappingURL=ffmpeg-args.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ffmpeg-args.js","sourceRoot":"","sources":["../../src/capture/ffmpeg-args.ts"],"names":[],"mappings":"AASA,sEAAsE;AACtE,yCAAyC;AACzC,mFAAmF;AACnF,MAAM,UAAU,iBAAiB,CAAC,MAAc;IAC9C,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;QACzC,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,8BAA8B,CAAC,CAAC;QACrD,IAAI,CAAC,CAAC;YAAE,SAAS;QACjB,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,OAAO;YAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;;YAClC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACxB,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,gBAAgB,CAC9B,OAAqB,EACrB,MAAqB;IAErB,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,wBAAwB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7F,IAAI,MAAM,KAAK,KAAK;QAAE,OAAO,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9E,OAAO,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;AACpF,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,OAAqB;IACpD,OAAO,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;AAC3D,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,CAK/B;IACC,MAAM,KAAK,GAAG,CAAC,CAAC,SAAS;QACvB,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS,UAAU,CAAC,CAAC,SAAS,EAAE;QAC7C,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS,EAAE,CAAC;IAC3B,OAAO;QACL,cAAc,EAAE,WAAW,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO;QACrD,IAAI,EAAE,KAAK;QACX,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC;QAC3B,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS;QACxC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACvC,IAAI,EAAE,CAAC,CAAC,UAAU;KACnB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,CAAwB;IACvD,OAAO;QACL,cAAc,EAAE,WAAW,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO;QACrD,IAAI,EAAE,SAAS,CAAC,CAAC,SAAS,EAAE;QAC5B,eAAe,EAAE,gBAAgB;KAClC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"ffmpeg-args.js","sourceRoot":"","sources":["../../src/capture/ffmpeg-args.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { spawn as realSpawn } from "node:child_process";
2
- import { type CaptureSource } from "./ffmpeg-args.js";
2
+ import { type CaptureSource, type DeviceList, type AvfDevices } from "./ffmpeg-args.js";
3
3
  export interface CaptureSession {
4
4
  id: string;
5
5
  kind: "record" | "preview";
@@ -27,18 +27,30 @@ interface Deps {
27
27
  clock?: () => string;
28
28
  hasBinary?: (name: string) => boolean;
29
29
  fs?: FsLike;
30
+ /** Override platform detection for testing. */
31
+ platform?: "darwin" | "win32" | "linux";
32
+ /** Override for device probe logic (used by tests to avoid real V4L2/dshow/AVF probing). */
33
+ probeDevices?: () => Promise<PlatformDevices>;
30
34
  }
35
+ /** Union of all platform device-list shapes. */
36
+ type PlatformDevices = DeviceList | AvfDevices;
31
37
  export declare class CaptureManager {
32
38
  private readonly spawn;
33
39
  private readonly clock;
34
40
  private readonly hasBinary;
35
41
  private readonly fs;
42
+ private readonly platform;
43
+ private readonly probeFn;
36
44
  private readonly sessions;
37
45
  private devices?;
38
46
  private seq;
39
47
  constructor(deps?: Deps);
40
48
  private ensureFfmpeg;
41
49
  private probeDevices;
50
+ private probeV4l2Devices;
51
+ private probeV4l2Card;
52
+ private probeAvfDevices;
53
+ private probeDshowDevices;
42
54
  private timestampName;
43
55
  startRecord(o: {
44
56
  source: CaptureSource;
@@ -1,8 +1,8 @@
1
1
  import { spawn as realSpawn, spawnSync } from "node:child_process";
2
- import { existsSync, mkdirSync } from "node:fs";
3
- import { homedir } from "node:os";
2
+ import { existsSync, mkdirSync, readFileSync, readdirSync } from "node:fs";
3
+ import { homedir, platform } from "node:os";
4
4
  import { dirname, join } from "node:path";
5
- import { parseDshowDevices, resolveVideoName, resolveAudioName, buildRecordArgs, buildPreviewArgs, } from "./ffmpeg-args.js";
5
+ import { parseDshowDevices, resolveVideoName, resolveAudioName, buildRecordArgs, buildPreviewArgs, parseAvfDevices, resolveAvfVideoName, resolveAvfAudioName, buildAvfRecordArgs, buildAvfPreviewArgs, } from "./ffmpeg-args.js";
6
6
  /** Expected operational failure (surfaced to the user as text, not thrown to the client). */
7
7
  export class CaptureError extends Error {
8
8
  constructor(message) {
@@ -24,11 +24,16 @@ function defaultHasBinary(name) {
24
24
  const r = spawnSync(name, ["-version"], { stdio: "ignore" });
25
25
  return !r.error;
26
26
  }
27
+ function isAvfDevices(d) {
28
+ return "video" in d && typeof d.video === "object" && !Array.isArray(d.video);
29
+ }
27
30
  export class CaptureManager {
28
31
  spawn;
29
32
  clock;
30
33
  hasBinary;
31
34
  fs;
35
+ platform;
36
+ probeFn;
32
37
  sessions = new Map();
33
38
  devices;
34
39
  seq = 0;
@@ -37,6 +42,8 @@ export class CaptureManager {
37
42
  this.clock = deps.clock ?? (() => new Date().toISOString());
38
43
  this.hasBinary = deps.hasBinary ?? defaultHasBinary;
39
44
  this.fs = deps.fs ?? { existsSync, mkdirSync };
45
+ this.platform = deps.platform ?? platform();
46
+ this.probeFn = deps.probeDevices;
40
47
  }
41
48
  ensureFfmpeg() {
42
49
  if (!this.hasBinary("ffmpeg") || !this.hasBinary("ffplay")) {
@@ -46,19 +53,77 @@ export class CaptureManager {
46
53
  probeDevices() {
47
54
  if (this.devices)
48
55
  return Promise.resolve(this.devices);
56
+ // Allow tests to inject a mock probe
57
+ if (this.probeFn)
58
+ return this.probeFn();
49
59
  return new Promise((resolve, reject) => {
50
- const child = this.spawn("ffmpeg", ["-hide_banner", "-f", "dshow", "-list_devices", "true", "-i", "dummy"]);
51
- let err = "";
52
- child.stderr?.on("data", (d) => { err += d.toString(); });
53
- child.on("error", (e) => reject(new CaptureError(`failed to run ffmpeg for device probe: ${e.message}`)));
54
- child.on("close", () => {
55
- this.devices = parseDshowDevices(err);
56
- resolve(this.devices);
57
- });
60
+ if (this.platform === "linux") {
61
+ // On Linux, list /dev/video* devices and probe each one
62
+ this.probeV4l2Devices().then(resolve).catch(reject);
63
+ }
64
+ else if (this.platform === "darwin") {
65
+ this.probeAvfDevices(resolve, reject);
66
+ }
67
+ else {
68
+ this.probeDshowDevices(resolve, reject);
69
+ }
70
+ });
71
+ }
72
+ async probeV4l2Devices() {
73
+ const video = [];
74
+ try {
75
+ const files = readdirSync("/dev");
76
+ const videoDevs = files
77
+ .filter((f) => /^video\d+$/.test(f))
78
+ .map((f) => `/dev/${f}`)
79
+ .sort();
80
+ for (const dev of videoDevs) {
81
+ const name = await this.probeV4l2Card(dev);
82
+ if (name)
83
+ video.push({ path: dev, card: name });
84
+ }
85
+ }
86
+ catch {
87
+ // /dev not readable
88
+ }
89
+ return { video, audio: [] };
90
+ }
91
+ probeV4l2Card(dev) {
92
+ return new Promise((resolve) => {
93
+ try {
94
+ const idx = dev.match(/video(\d+)$/)?.[1];
95
+ if (!idx)
96
+ return resolve(undefined);
97
+ const sysfs = `/sys/class/video4linux/video${idx}/name`;
98
+ const name = readFileSync(sysfs, 'utf-8').trim();
99
+ resolve(name || undefined);
100
+ }
101
+ catch {
102
+ resolve(undefined);
103
+ }
104
+ });
105
+ }
106
+ probeAvfDevices(resolve, reject) {
107
+ const child = this.spawn("ffmpeg", ["-hide_banner", "-f", "avfoundation", "-list_devices", "true", "-i", ""], { stdio: ["pipe", "pipe", "pipe"] });
108
+ let err = "";
109
+ child.stderr?.on("data", (d) => { err += d.toString(); });
110
+ child.on("error", (e) => reject(new CaptureError(`failed to run ffmpeg for device probe: ${e.message}`)));
111
+ child.on("close", () => {
112
+ this.devices = parseAvfDevices(err);
113
+ resolve(this.devices);
114
+ });
115
+ }
116
+ probeDshowDevices(resolve, reject) {
117
+ const child = this.spawn("ffmpeg", ["-hide_banner", "-f", "dshow", "-list_devices", "true", "-i", "dummy"], { stdio: ["pipe", "pipe", "pipe"] });
118
+ let err = "";
119
+ child.stderr?.on("data", (d) => { err += d.toString(); });
120
+ child.on("error", (e) => reject(new CaptureError(`failed to run ffmpeg for device probe: ${e.message}`)));
121
+ child.on("close", () => {
122
+ this.devices = parseDshowDevices(err);
123
+ resolve(this.devices);
58
124
  });
59
125
  }
60
126
  timestampName() {
61
- // clock() -> "2026-07-13T09:33:58.000Z"; make obsbot-YYYYMMDD-HHMMSS.mp4
62
127
  const iso = this.clock();
63
128
  const compact = iso.replace(/[-:]/g, "").replace("T", "-").replace(/\..*$/, "");
64
129
  return `obsbot-${compact}.mp4`;
@@ -66,6 +131,36 @@ export class CaptureManager {
66
131
  async startRecord(o) {
67
132
  this.ensureFfmpeg();
68
133
  const devices = await this.probeDevices();
134
+ if (isAvfDevices(devices)) {
135
+ const videoInfo = resolveAvfVideoName(devices, o.source);
136
+ if (!videoInfo)
137
+ throw new CaptureError(`no '${o.source}' video source found (is OBSBOT Center / NDI running?)`);
138
+ let audioIndex;
139
+ if (o.audio) {
140
+ const audioInfo = resolveAvfAudioName(devices);
141
+ if (!audioInfo)
142
+ throw new CaptureError("OBSBOT microphone not found; retry with audio:false for a silent clip");
143
+ audioIndex = audioInfo.index;
144
+ }
145
+ const outputPath = o.outputPath ?? join(homedir(), "Videos", "OBSBOT", this.timestampName());
146
+ if (o.outputPath && this.fs.existsSync(o.outputPath)) {
147
+ throw new CaptureError(`output file already exists: ${o.outputPath}`);
148
+ }
149
+ this.fs.mkdirSync(dirname(outputPath), { recursive: true });
150
+ const durationSec = o.durationSec ?? OPEN_ENDED_CAP_SEC;
151
+ const args = buildAvfRecordArgs({ videoIndex: videoInfo.index, audioIndex, durationSec, outputPath });
152
+ const child = this.spawn("ffmpeg", args, { stdio: ["pipe", "ignore", "ignore"] });
153
+ const session = {
154
+ id: `cap${++this.seq}`, kind: "record", pid: child.pid ?? -1,
155
+ source: o.source, outputPath, durationSec, startedAtIso: this.clock(),
156
+ };
157
+ this.sessions.set(session.id, { session, child });
158
+ child.once("exit", () => this.sessions.delete(session.id));
159
+ child.on("error", () => this.sessions.delete(session.id));
160
+ return session;
161
+ }
162
+ // Windows (dshow) or Linux (v4l2) path — resolveVideoName/buildRecordArgs
163
+ // handle both via the DeviceList union and /dev/ prefix check.
69
164
  const videoName = resolveVideoName(devices, o.source);
70
165
  if (!videoName)
71
166
  throw new CaptureError(`no '${o.source}' video source found (is OBSBOT Center / NDI running?)`);
@@ -95,6 +190,22 @@ export class CaptureManager {
95
190
  async startPreview(o) {
96
191
  this.ensureFfmpeg();
97
192
  const devices = await this.probeDevices();
193
+ if (isAvfDevices(devices)) {
194
+ const videoInfo = resolveAvfVideoName(devices, o.source);
195
+ if (!videoInfo)
196
+ throw new CaptureError(`no '${o.source}' video source found (is OBSBOT Center / NDI running?)`);
197
+ const args = buildAvfPreviewArgs({ videoIndex: videoInfo.index });
198
+ const child = this.spawn("ffplay", args, { stdio: "ignore" });
199
+ const session = {
200
+ id: `cap${++this.seq}`, kind: "preview", pid: child.pid ?? -1,
201
+ source: o.source, startedAtIso: this.clock(),
202
+ };
203
+ this.sessions.set(session.id, { session, child });
204
+ child.once("exit", () => this.sessions.delete(session.id));
205
+ child.on("error", () => this.sessions.delete(session.id));
206
+ return session;
207
+ }
208
+ // Windows (dshow) or Linux (v4l2) path
98
209
  const videoName = resolveVideoName(devices, o.source);
99
210
  if (!videoName)
100
211
  throw new CaptureError(`no '${o.source}' video source found (is OBSBOT Center / NDI running?)`);
@@ -116,7 +227,6 @@ export class CaptureManager {
116
227
  const { session, child } = entry;
117
228
  let graceful = true;
118
229
  if (session.kind === "record") {
119
- // 'q' on stdin is ffmpeg's clean stop (finalizes the MP4 moov atom).
120
230
  graceful = await new Promise((resolve) => {
121
231
  let done = false;
122
232
  const timer = setTimeout(() => { if (!done) {
@@ -142,12 +252,10 @@ export class CaptureManager {
142
252
  return { kind: session.kind, outputPath: session.outputPath, graceful };
143
253
  }
144
254
  list() {
145
- return [...this.sessions.values()].map((e) => e.session);
255
+ return Array.from(this.sessions.values()).map((e) => e.session);
146
256
  }
147
- // Hard-kill every child. Wired to server shutdown so nothing orphans; this is
148
- // last-resort cleanup, not a graceful stop.
149
257
  stopAll() {
150
- for (const { child } of this.sessions.values()) {
258
+ for (const { child } of Array.from(this.sessions.values())) {
151
259
  try {
152
260
  child.kill();
153
261
  }
@@ -1 +1 @@
1
- {"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/capture/manager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/capture/manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,SAAS,EAAqB,MAAM,oBAAoB,CAAC;AACtF,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAC3E,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EAChB,eAAe,EAAE,mBAAmB,EAAE,mBAAmB,EACzD,kBAAkB,EAAE,mBAAmB,GAMxC,MAAM,kBAAkB,CAAC;AAY1B,6FAA6F;AAC7F,MAAM,OAAO,YAAa,SAAQ,KAAK;IACrC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,cAAc,CAAC;IAC7B,CAAC;CACF;AAED,MAAM,OAAO,kBAAmB,SAAQ,YAAY;IAClD;QACE,KAAK,CACH,qEAAqE;YACnE,mFAAmF;YACnF,6BAA6B,CAChC,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;IACnC,CAAC;CACF;AAED,MAAM,kBAAkB,GAAG,IAAI,CAAC;AAChC,MAAM,gBAAgB,GAAG,IAAI,CAAC;AAE9B,SAAS,gBAAgB,CAAC,IAAY;IACpC,MAAM,CAAC,GAAG,SAAS,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;IAC7D,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC;AAClB,CAAC;AAqBD,SAAS,YAAY,CAAC,CAAkB;IACtC,OAAO,OAAO,IAAI,CAAC,IAAI,OAAO,CAAC,CAAC,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;AAChF,CAAC;AAED,MAAM,OAAO,cAAc;IACR,KAAK,CAAmB;IACxB,KAAK,CAAe;IACpB,SAAS,CAA4B;IACrC,EAAE,CAAS;IACX,QAAQ,CAAS;IACjB,OAAO,CAA+C;IACtD,QAAQ,GAAG,IAAI,GAAG,EAA4D,CAAC;IACxF,OAAO,CAAmB;IAC1B,GAAG,GAAG,CAAC,CAAC;IAEhB,YAAY,OAAa,EAAE;QACzB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,SAAS,CAAC;QACrC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC;QAC5D,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,gBAAgB,CAAC;QACpD,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC;QAC/C,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,QAAQ,EAAE,CAAC;QAC5C,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,YAAY,CAAC;IACnC,CAAC;IAEO,YAAY;QAClB,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC3D,MAAM,IAAI,kBAAkB,EAAE,CAAC;QACjC,CAAC;IACH,CAAC;IAEO,YAAY;QAClB,IAAI,IAAI,CAAC,OAAO;YAAE,OAAO,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACvD,qCAAqC;QACrC,IAAI,IAAI,CAAC,OAAO;YAAE,OAAO,IAAI,CAAC,OAAO,EAAE,CAAC;QACxC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,IAAI,IAAI,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;gBAC9B,wDAAwD;gBACxD,IAAI,CAAC,gBAAgB,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YACtD,CAAC;iBAAM,IAAI,IAAI,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;gBACtC,IAAI,CAAC,eAAe,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YACxC,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,iBAAiB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YAC1C,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,KAAK,CAAC,gBAAgB;QAC5B,MAAM,KAAK,GAAqB,EAAE,CAAC;QACnC,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;YAClC,MAAM,SAAS,GAAG,KAAK;iBACpB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;iBACnC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC;iBACvB,IAAI,EAAE,CAAC;YAEV,KAAK,MAAM,GAAG,IAAI,SAAS,EAAE,CAAC;gBAC5B,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;gBAC3C,IAAI,IAAI;oBAAE,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;YAClD,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,oBAAoB;QACtB,CAAC;QACD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;IAC9B,CAAC;IAEO,aAAa,CAAC,GAAW;QAC/B,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;YAC7B,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;gBAC1C,IAAI,CAAC,GAAG;oBAAE,OAAO,OAAO,CAAC,SAAS,CAAC,CAAC;gBACpC,MAAM,KAAK,GAAG,+BAA+B,GAAG,OAAO,CAAC;gBACxD,MAAM,IAAI,GAAG,YAAY,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;gBACjD,OAAO,CAAC,IAAI,IAAI,SAAS,CAAC,CAAC;YAC7B,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,CAAC,SAAS,CAAC,CAAC;YACrB,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,eAAe,CACrB,OAA2C,EAC3C,MAA4B;QAE5B,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CACtB,QAAQ,EACR,CAAC,cAAc,EAAE,IAAI,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,CAAC,EACzE,EAAE,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,CACpC,CAAC;QACF,IAAI,GAAG,GAAG,EAAE,CAAC;QACb,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,CAAS,EAAE,EAAE,GAAG,GAAG,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAClE,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,YAAY,CAAC,0CAA0C,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC;QAC1G,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;YACrB,IAAI,CAAC,OAAO,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;YACpC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACxB,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,iBAAiB,CACvB,OAA2C,EAC3C,MAA4B;QAE5B,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CACtB,QAAQ,EACR,CAAC,cAAc,EAAE,IAAI,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,EACvE,EAAE,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,CACpC,CAAC;QACF,IAAI,GAAG,GAAG,EAAE,CAAC;QACb,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,CAAS,EAAE,EAAE,GAAG,GAAG,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAClE,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,YAAY,CAAC,0CAA0C,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC;QAC1G,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;YACrB,IAAI,CAAC,OAAO,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC;YACtC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACxB,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,aAAa;QACnB,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;QACzB,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QAChF,OAAO,UAAU,OAAO,MAAM,CAAC;IACjC,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,CAEjB;QACC,IAAI,CAAC,YAAY,EAAE,CAAC;QACpB,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,YAAY,EAAE,CAAC;QAE1C,IAAI,YAAY,CAAC,OAAO,CAAC,EAAE,CAAC;YAC1B,MAAM,SAAS,GAAG,mBAAmB,CAAC,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC;YACzD,IAAI,CAAC,SAAS;gBAAE,MAAM,IAAI,YAAY,CAAC,OAAO,CAAC,CAAC,MAAM,wDAAwD,CAAC,CAAC;YAChH,IAAI,UAA8B,CAAC;YACnC,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC;gBACZ,MAAM,SAAS,GAAG,mBAAmB,CAAC,OAAO,CAAC,CAAC;gBAC/C,IAAI,CAAC,SAAS;oBAAE,MAAM,IAAI,YAAY,CAAC,uEAAuE,CAAC,CAAC;gBAChH,UAAU,GAAG,SAAS,CAAC,KAAK,CAAC;YAC/B,CAAC;YACD,MAAM,UAAU,GAAG,CAAC,CAAC,UAAU,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,aAAa,EAAE,CAAC,CAAC;YAC7F,IAAI,CAAC,CAAC,UAAU,IAAI,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC;gBACrD,MAAM,IAAI,YAAY,CAAC,+BAA+B,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC;YACxE,CAAC;YACD,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAC5D,MAAM,WAAW,GAAG,CAAC,CAAC,WAAW,IAAI,kBAAkB,CAAC;YACxD,MAAM,IAAI,GAAG,kBAAkB,CAAC,EAAE,UAAU,EAAE,SAAS,CAAC,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,CAAC,CAAC;YACtG,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC;YAClF,MAAM,OAAO,GAAmB;gBAC9B,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,IAAI,CAAC,CAAC;gBAC5D,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,IAAI,CAAC,KAAK,EAAE;aACtE,CAAC;YACF,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;YAClD,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;YAC3D,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;YAC1D,OAAO,OAAO,CAAC;QACjB,CAAC;QAED,0EAA0E;QAC1E,+DAA+D;QAC/D,MAAM,SAAS,GAAG,gBAAgB,CAAC,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC;QACtD,IAAI,CAAC,SAAS;YAAE,MAAM,IAAI,YAAY,CAAC,OAAO,CAAC,CAAC,MAAM,wDAAwD,CAAC,CAAC;QAChH,IAAI,SAA6B,CAAC;QAClC,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC;YACZ,SAAS,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;YACtC,IAAI,CAAC,SAAS;gBAAE,MAAM,IAAI,YAAY,CAAC,uEAAuE,CAAC,CAAC;QAClH,CAAC;QACD,MAAM,UAAU,GAAG,CAAC,CAAC,UAAU,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,aAAa,EAAE,CAAC,CAAC;QAC7F,IAAI,CAAC,CAAC,UAAU,IAAI,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC;YACrD,MAAM,IAAI,YAAY,CAAC,+BAA+B,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC;QACxE,CAAC;QACD,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5D,MAAM,WAAW,GAAG,CAAC,CAAC,WAAW,IAAI,kBAAkB,CAAC;QACxD,MAAM,IAAI,GAAG,eAAe,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,UAAU,EAAE,CAAC,CAAC;QAChF,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC;QAClF,MAAM,OAAO,GAAmB;YAC9B,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,IAAI,CAAC,CAAC;YAC5D,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,IAAI,CAAC,KAAK,EAAE;SACtE,CAAC;QACF,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;QAClD,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;QAC3D,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;QAC1D,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,CAA4B;QAC7C,IAAI,CAAC,YAAY,EAAE,CAAC;QACpB,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,YAAY,EAAE,CAAC;QAE1C,IAAI,YAAY,CAAC,OAAO,CAAC,EAAE,CAAC;YAC1B,MAAM,SAAS,GAAG,mBAAmB,CAAC,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC;YACzD,IAAI,CAAC,SAAS;gBAAE,MAAM,IAAI,YAAY,CAAC,OAAO,CAAC,CAAC,MAAM,wDAAwD,CAAC,CAAC;YAChH,MAAM,IAAI,GAAG,mBAAmB,CAAC,EAAE,UAAU,EAAE,SAAS,CAAC,KAAK,EAAE,CAAC,CAAC;YAClE,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;YAC9D,MAAM,OAAO,GAAmB;gBAC9B,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,IAAI,CAAC,CAAC;gBAC7D,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,YAAY,EAAE,IAAI,CAAC,KAAK,EAAE;aAC7C,CAAC;YACF,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;YAClD,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;YAC3D,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;YAC1D,OAAO,OAAO,CAAC;QACjB,CAAC;QAED,uCAAuC;QACvC,MAAM,SAAS,GAAG,gBAAgB,CAAC,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC;QACtD,IAAI,CAAC,SAAS;YAAE,MAAM,IAAI,YAAY,CAAC,OAAO,CAAC,CAAC,MAAM,wDAAwD,CAAC,CAAC;QAChH,MAAM,IAAI,GAAG,gBAAgB,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC;QAC7C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;QAC9D,MAAM,OAAO,GAAmB;YAC9B,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,IAAI,CAAC,CAAC;YAC7D,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,YAAY,EAAE,IAAI,CAAC,KAAK,EAAE;SAC7C,CAAC;QACF,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;QAClD,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;QAC3D,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;QAC1D,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,EAAU;QACnB,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACpC,IAAI,CAAC,KAAK;YAAE,MAAM,IAAI,YAAY,CAAC,4BAA4B,EAAE,EAAE,CAAC,CAAC;QACrE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,KAAK,CAAC;QACjC,IAAI,QAAQ,GAAG,IAAI,CAAC;QACpB,IAAI,OAAO,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC9B,QAAQ,GAAG,MAAM,IAAI,OAAO,CAAU,CAAC,OAAO,EAAE,EAAE;gBAChD,IAAI,IAAI,GAAG,KAAK,CAAC;gBACjB,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;oBAAC,IAAI,GAAG,IAAI,CAAC;oBAAC,KAAK,CAAC,IAAI,EAAE,CAAC;oBAAC,OAAO,CAAC,KAAK,CAAC,CAAC;gBAAC,CAAC,CAAC,CAAC,EAAE,gBAAgB,CAAC,CAAC;gBAChH,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;oBAAC,IAAI,GAAG,IAAI,CAAC;oBAAC,YAAY,CAAC,KAAK,CAAC,CAAC;oBAAC,OAAO,CAAC,IAAI,CAAC,CAAC;gBAAC,CAAC,CAAC,CAAC,CAAC,CAAC;gBAC9F,IAAI,CAAC;oBAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;gBAAC,CAAC;gBAAC,MAAM,CAAC,CAAC,kBAAkB,CAAC,CAAC;YAC/D,CAAC,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,IAAI,EAAE,CAAC;QACf,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACzB,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,UAAU,EAAE,OAAO,CAAC,UAAU,EAAE,QAAQ,EAAE,CAAC;IAC1E,CAAC;IAED,IAAI;QACF,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;IAClE,CAAC;IAED,OAAO;QACL,KAAK,MAAM,EAAE,KAAK,EAAE,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC;YAC3D,IAAI,CAAC;gBAAC,KAAK,CAAC,IAAI,EAAE,CAAC;YAAC,CAAC;YAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;QAC9C,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;IACxB,CAAC;CACF"}
@@ -25,6 +25,16 @@ export declare const AI_TRACK_SPEEDS: AiTrackSpeed[];
25
25
  export declare const encodeAiTrackSpeed: (speed: AiTrackSpeed) => VendorFrame;
26
26
  export declare const encodeZoomWithSpeed: (ratioX100: number, speed: number) => VendorFrame;
27
27
  export declare const encodeFaceFocus: (enable: boolean) => VendorFrame;
28
+ export declare const encodeSetExposureMode: (manual: boolean) => VendorFrame;
29
+ export declare const encodeSetExposureValue: (raw: number) => VendorFrame;
30
+ export declare const encodeGetExposureMode: () => VendorFrame;
31
+ export declare const encodeGetExposureValue: () => VendorFrame;
32
+ export declare const encodeGetExposureRange: () => VendorFrame;
33
+ export interface ExposureRange {
34
+ min: number;
35
+ max: number;
36
+ }
37
+ export declare const decodeExposureRange: (payload: Buffer) => ExposureRange;
28
38
  /** Request the current face-priority autofocus state (CAM_GET_FACE_FOCUS, cmd 0x35c2). */
29
39
  export declare const encodeGetFaceFocus: () => VendorFrame;
30
40
  export interface FaceFocusState {