@appium/coresim 1.6.0 → 1.8.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/CHANGELOG.md +12 -0
- package/README.md +5 -3
- package/binding.gyp +2 -1
- package/lib/src/commands/jpeg-stream.d.ts +44 -0
- package/lib/src/commands/jpeg-stream.d.ts.map +1 -0
- package/lib/src/commands/jpeg-stream.js +198 -0
- package/lib/src/commands/jpeg-stream.js.map +1 -0
- package/lib/src/commands/video-recording.d.ts +12 -3
- package/lib/src/commands/video-recording.d.ts.map +1 -1
- package/lib/src/commands/video-recording.js +19 -5
- package/lib/src/commands/video-recording.js.map +1 -1
- package/lib/src/index.d.ts +2 -1
- package/lib/src/index.d.ts.map +1 -1
- package/lib/src/index.js +1 -0
- package/lib/src/index.js.map +1 -1
- package/lib/src/native-simctl.d.ts +2 -0
- package/lib/src/native-simctl.d.ts.map +1 -1
- package/lib/src/native-simctl.js +3 -0
- package/lib/src/native-simctl.js.map +1 -1
- package/lib/src/types.d.ts +65 -2
- package/lib/src/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/prebuilds/darwin-arm64/@appium+coresim.node +0 -0
- package/src/commands/jpeg-stream.ts +233 -0
- package/src/commands/video-recording.ts +27 -7
- package/src/coresim.mm +170 -6
- package/src/index.ts +4 -0
- package/src/native/audio_encoder.mm +1 -1
- package/src/native/av_recording.mm +1 -1
- package/src/native/sim_audio_tap.mm +3 -3
- package/src/native/sim_jpeg_stream.h +69 -0
- package/src/native/sim_jpeg_stream.mm +322 -0
- package/src/native/sim_pasteboard.mm +3 -3
- package/src/native/sim_process.mm +1 -1
- package/src/native/sim_screenshot.h +8 -0
- package/src/native/sim_screenshot.mm +29 -25
- package/src/native/sim_video_recording.mm +1 -1
- package/src/native/tcc_privacy.mm +1 -1
- package/src/native/video_encoder.h +2 -2
- package/src/native/video_encoder.mm +2 -2
- package/src/native-simctl.ts +3 -0
- package/src/types.ts +70 -2
package/lib/src/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
Binary file
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
import {EventEmitter} from 'node:events';
|
|
2
|
+
|
|
3
|
+
import {logger} from '@appium/support';
|
|
4
|
+
|
|
5
|
+
import type {NativeSimctl} from '../native-simctl.js';
|
|
6
|
+
import type {JpegFrame, JpegStreamOptions, NativeJpegStreamHandle} from '../types.js';
|
|
7
|
+
import {runCatchingAsync, toTypedError} from '../utils/index.js';
|
|
8
|
+
|
|
9
|
+
declare module '../native-simctl.js' {
|
|
10
|
+
interface NativeSimctl {
|
|
11
|
+
startJpegStream(udid: string, options?: JpegStreamOptions): Promise<JpegStream>;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const log = logger.getLogger('CoreSim');
|
|
16
|
+
|
|
17
|
+
// Matches the native side's own ThreadSafeFunction queue bound (see coresim.mm's kFrameQueueSize).
|
|
18
|
+
const MAX_BUFFERED_FRAMES = 60;
|
|
19
|
+
|
|
20
|
+
const SINGLE_CONSUMER_ERROR =
|
|
21
|
+
'JpegStream.frames() supports only one active consumer at a time — a second concurrent call rejects.';
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Single-consumer FIFO between native's per-frame callback and `frames()`. Simpler than
|
|
25
|
+
* `AccessUnitQueue` (video-stream.ts): every JPEG frame is independently decodable, so there's no
|
|
26
|
+
* reference chain to protect — overflow just drops the oldest buffered frame(s), keeping delivery
|
|
27
|
+
* as close to real time as possible instead of falling further behind.
|
|
28
|
+
*/
|
|
29
|
+
class JpegFrameQueue {
|
|
30
|
+
private readonly buffer: JpegFrame[] = [];
|
|
31
|
+
private waiter: {resolve: (result: IteratorResult<JpegFrame>) => void; reject: (err: unknown) => void} | undefined;
|
|
32
|
+
private ended = false;
|
|
33
|
+
private error: unknown;
|
|
34
|
+
|
|
35
|
+
push(frame: JpegFrame): void {
|
|
36
|
+
if (this.ended) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
if (this.waiter) {
|
|
40
|
+
const {resolve} = this.waiter;
|
|
41
|
+
this.waiter = undefined;
|
|
42
|
+
resolve({value: frame, done: false});
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
this.buffer.push(frame);
|
|
46
|
+
if (this.buffer.length > MAX_BUFFERED_FRAMES) {
|
|
47
|
+
this.buffer.shift();
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Ends the queue with an error — any pending or future `next()` rejects with it. */
|
|
52
|
+
fail(err: unknown): void {
|
|
53
|
+
if (this.ended) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
this.ended = true;
|
|
57
|
+
this.error = err;
|
|
58
|
+
this.buffer.length = 0;
|
|
59
|
+
if (this.waiter) {
|
|
60
|
+
const {reject} = this.waiter;
|
|
61
|
+
this.waiter = undefined;
|
|
62
|
+
reject(err);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** Ends the queue cleanly — any pending or future `next()` resolves `done`. */
|
|
67
|
+
end(): void {
|
|
68
|
+
if (this.ended) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
this.ended = true;
|
|
72
|
+
this.buffer.length = 0;
|
|
73
|
+
if (this.waiter) {
|
|
74
|
+
const {resolve} = this.waiter;
|
|
75
|
+
this.waiter = undefined;
|
|
76
|
+
resolve({value: undefined, done: true});
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Resolves `done` (not rejects) if `signal` aborts while waiting, mirroring `events.on()`.
|
|
82
|
+
* Checks cancellation/end *before* dequeuing, so an already-aborted signal or an already-ended
|
|
83
|
+
* queue never hands out a stale buffered frame.
|
|
84
|
+
*/
|
|
85
|
+
next(signal: AbortSignal): Promise<IteratorResult<JpegFrame>> {
|
|
86
|
+
if (signal.aborted) {
|
|
87
|
+
return Promise.resolve({value: undefined, done: true});
|
|
88
|
+
}
|
|
89
|
+
if (this.ended) {
|
|
90
|
+
return this.error ? Promise.reject(this.error) : Promise.resolve({value: undefined, done: true});
|
|
91
|
+
}
|
|
92
|
+
const buffered = this.buffer.shift();
|
|
93
|
+
if (buffered !== undefined) {
|
|
94
|
+
return Promise.resolve({value: buffered, done: false});
|
|
95
|
+
}
|
|
96
|
+
return new Promise((resolve, reject) => {
|
|
97
|
+
const onAbort = () => {
|
|
98
|
+
this.waiter = undefined;
|
|
99
|
+
resolve({value: undefined, done: true});
|
|
100
|
+
};
|
|
101
|
+
signal.addEventListener('abort', onAbort, {once: true});
|
|
102
|
+
this.waiter = {
|
|
103
|
+
resolve: (result) => {
|
|
104
|
+
signal.removeEventListener('abort', onAbort);
|
|
105
|
+
resolve(result);
|
|
106
|
+
},
|
|
107
|
+
reject: (err) => {
|
|
108
|
+
signal.removeEventListener('abort', onAbort);
|
|
109
|
+
reject(err);
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* A live JPEG frame stream from `NativeSimctl.startJpegStream` — polls the device's display and
|
|
118
|
+
* delivers each changed frame as a standalone JPEG image, at a configurable fps/quality. Unlike
|
|
119
|
+
* `startVideoStream`, this produces no video codec bitstream — it's meant for callers that want to
|
|
120
|
+
* build their own MJPEG (`multipart/x-mixed-replace`) HTTP stream, or otherwise just want a plain
|
|
121
|
+
* sequence of images, out of `frames()` themselves.
|
|
122
|
+
*/
|
|
123
|
+
export class JpegStream extends EventEmitter {
|
|
124
|
+
private handle: NativeJpegStreamHandle | undefined;
|
|
125
|
+
private readonly stopController = new AbortController();
|
|
126
|
+
private stopPromise: Promise<void> | undefined;
|
|
127
|
+
private readonly queue = new JpegFrameQueue();
|
|
128
|
+
private activeConsumers = 0;
|
|
129
|
+
|
|
130
|
+
/** @internal */
|
|
131
|
+
_handleFrame(frame: JpegFrame): void {
|
|
132
|
+
this.queue.push(frame);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* @internal
|
|
137
|
+
* An active `frames()` consumer receives the error via the queue itself (thrown out of its
|
|
138
|
+
* `for await` loop, per that method's contract) rather than the `'error'` event, so `emit` is
|
|
139
|
+
* only used for an explicit external listener; with neither, it's logged instead of lost.
|
|
140
|
+
*/
|
|
141
|
+
_handleError(err: unknown): void {
|
|
142
|
+
const error = toTypedError(err);
|
|
143
|
+
this.queue.fail(error);
|
|
144
|
+
if (this.listenerCount('error') > 0) {
|
|
145
|
+
this.emit('error', error);
|
|
146
|
+
} else if (this.activeConsumers === 0) {
|
|
147
|
+
log.error(`Unhandled JpegStream error: ${error.stack ?? error}`);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/** @internal */
|
|
152
|
+
_attachHandle(handle: NativeJpegStreamHandle): void {
|
|
153
|
+
this.handle = handle;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Yields each JPEG frame as it's produced, until {@link stop} is called or the stream errors (in
|
|
158
|
+
* which case the error is thrown out of the loop). Pass `signal` to stop iterating without
|
|
159
|
+
* treating that as an error.
|
|
160
|
+
*
|
|
161
|
+
* Only one active consumer is supported at a time — a second concurrent call rejects rather than
|
|
162
|
+
* silently sharing (and corrupting) the first one's single internal waiter slot.
|
|
163
|
+
*/
|
|
164
|
+
async *frames(signal?: AbortSignal): AsyncGenerator<JpegFrame> {
|
|
165
|
+
if (this.activeConsumers > 0) {
|
|
166
|
+
throw new Error(SINGLE_CONSUMER_ERROR);
|
|
167
|
+
}
|
|
168
|
+
const combined = signal ? AbortSignal.any([signal, this.stopController.signal]) : this.stopController.signal;
|
|
169
|
+
this.activeConsumers++;
|
|
170
|
+
try {
|
|
171
|
+
for (;;) {
|
|
172
|
+
const result = await this.queue.next(combined);
|
|
173
|
+
if (result.done) {
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
yield result.value;
|
|
177
|
+
}
|
|
178
|
+
} finally {
|
|
179
|
+
this.activeConsumers--;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/** Stops the stream and releases the underlying encoder. Idempotent, including concurrently. */
|
|
184
|
+
async stop(): Promise<void> {
|
|
185
|
+
this.stopPromise ??= (async () => {
|
|
186
|
+
this.stopController.abort();
|
|
187
|
+
this.queue.end();
|
|
188
|
+
await this.handle?.stop();
|
|
189
|
+
})();
|
|
190
|
+
return this.stopPromise;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Starts polling the device's display and JPEG-encoding each changed frame in real time. Resolves
|
|
196
|
+
* once the encoder has actually started; the returned {@link JpegStream}'s `frames()` then yields
|
|
197
|
+
* each frame as it arrives. Independent of `startVideoStream`/`startVideoRecording` — any number of
|
|
198
|
+
* concurrent streams/recordings can run on the same device at once.
|
|
199
|
+
*
|
|
200
|
+
* @param udid — UDID of the device to stream; must be booted
|
|
201
|
+
* @param options — `displayId`, `fps`, `quality`, `scale` — see {@link JpegStreamOptions}
|
|
202
|
+
*/
|
|
203
|
+
export async function startJpegStream(
|
|
204
|
+
this: NativeSimctl,
|
|
205
|
+
udid: string,
|
|
206
|
+
options: JpegStreamOptions = {},
|
|
207
|
+
): Promise<JpegStream> {
|
|
208
|
+
// The native poller clamps below 1 fps to 1 fps rather than actually polling that slowly, so a
|
|
209
|
+
// sub-1 value here would silently poll far more often than requested — rejected instead.
|
|
210
|
+
if (options.fps !== undefined && (!Number.isFinite(options.fps) || options.fps < 1)) {
|
|
211
|
+
throw new RangeError(`fps must be a finite number >= 1, got ${options.fps}`);
|
|
212
|
+
}
|
|
213
|
+
if (
|
|
214
|
+
options.quality !== undefined &&
|
|
215
|
+
(!Number.isFinite(options.quality) || options.quality < 0 || options.quality > 100)
|
|
216
|
+
) {
|
|
217
|
+
throw new RangeError(`quality must be a number between 0 and 100, got ${options.quality}`);
|
|
218
|
+
}
|
|
219
|
+
if (options.scale !== undefined && (!Number.isFinite(options.scale) || options.scale <= 0 || options.scale > 100)) {
|
|
220
|
+
throw new RangeError(`scale must be a number greater than 0 and no greater than 100, got ${options.scale}`);
|
|
221
|
+
}
|
|
222
|
+
const device = await runCatchingAsync(() => this._findDevice(udid));
|
|
223
|
+
const stream = new JpegStream();
|
|
224
|
+
const handle = await runCatchingAsync(() =>
|
|
225
|
+
device.startJpegStream(
|
|
226
|
+
options,
|
|
227
|
+
(frame) => stream._handleFrame(frame),
|
|
228
|
+
(err) => stream._handleError(err),
|
|
229
|
+
),
|
|
230
|
+
);
|
|
231
|
+
stream._attachHandle(handle);
|
|
232
|
+
return stream;
|
|
233
|
+
}
|
|
@@ -3,13 +3,13 @@ import path from 'node:path';
|
|
|
3
3
|
import {logger} from '@appium/support';
|
|
4
4
|
|
|
5
5
|
import type {NativeSimctl} from '../native-simctl.js';
|
|
6
|
-
import type {NativeVideoRecordingHandle, VideoRecordingOptions} from '../types.js';
|
|
6
|
+
import type {NativeVideoRecordingHandle, StopVideoRecordingOptions, VideoRecordingOptions} from '../types.js';
|
|
7
7
|
import {runCatchingAsync, toTypedError} from '../utils/index.js';
|
|
8
8
|
|
|
9
9
|
declare module '../native-simctl.js' {
|
|
10
10
|
interface NativeSimctl {
|
|
11
11
|
startVideoRecording(udid: string, outputFile: string, options?: VideoRecordingOptions): Promise<void>;
|
|
12
|
-
stopVideoRecording(udid: string): Promise<void>;
|
|
12
|
+
stopVideoRecording(udid: string, options?: StopVideoRecordingOptions): Promise<void>;
|
|
13
13
|
isVideoRecording(udid: string): Promise<boolean>;
|
|
14
14
|
}
|
|
15
15
|
}
|
|
@@ -112,10 +112,23 @@ export async function startVideoRecording(
|
|
|
112
112
|
* device-lookup error — leaves the recording tracked as still active so a retry can reach the
|
|
113
113
|
* native call rather than the caller losing the ability to stop it at all.
|
|
114
114
|
*
|
|
115
|
+
* That retryability is a liability if nothing ever *does* retry — e.g. a best-effort teardown path
|
|
116
|
+
* that must not throw, so it logs a failed stop and moves on — since without `options.force` there
|
|
117
|
+
* is no other way to release the entry, permanently blocking a new `startVideoRecording` for this
|
|
118
|
+
* device. Pass `options.force: true` in that situation: it still attempts the native stop (so the
|
|
119
|
+
* encoder/file gets a chance to finalize cleanly) but releases the entry unconditionally afterward
|
|
120
|
+
* and never rejects, even if that attempt failed — understand that this can leave a native
|
|
121
|
+
* resource dangling if the stop genuinely never lands.
|
|
122
|
+
*
|
|
115
123
|
* @param udid — UDID of the device to stop recording
|
|
124
|
+
* @param options — `force` (see above)
|
|
116
125
|
* @throws {Error} if no recording is currently in progress for this device
|
|
117
126
|
*/
|
|
118
|
-
export async function stopVideoRecording(
|
|
127
|
+
export async function stopVideoRecording(
|
|
128
|
+
this: NativeSimctl,
|
|
129
|
+
udid: string,
|
|
130
|
+
options: StopVideoRecordingOptions = {},
|
|
131
|
+
): Promise<void> {
|
|
119
132
|
const key = udid.toLowerCase();
|
|
120
133
|
const state = activeRecordings.get(key);
|
|
121
134
|
if (!state) {
|
|
@@ -134,13 +147,20 @@ export async function stopVideoRecording(this: NativeSimctl, udid: string): Prom
|
|
|
134
147
|
try {
|
|
135
148
|
await stopPromise;
|
|
136
149
|
} catch (e) {
|
|
137
|
-
// Only clear our own attempt, and only if it's still the current one — a future
|
|
138
|
-
// able to retry the native stop rather than replaying this same rejection
|
|
139
|
-
// not clobber a newer attempt another concurrent caller may have already
|
|
150
|
+
// Only clear our own attempt, and only if it's still the current one — a future (non-forced)
|
|
151
|
+
// call must be able to retry the native stop rather than replaying this same rejection
|
|
152
|
+
// forever, but must not clobber a newer attempt another concurrent caller may have already
|
|
153
|
+
// started instead.
|
|
140
154
|
if (state.stop === stopPromise) {
|
|
141
155
|
state.stop = undefined;
|
|
142
156
|
}
|
|
143
|
-
|
|
157
|
+
if (!options.force) {
|
|
158
|
+
throw e;
|
|
159
|
+
}
|
|
160
|
+
log.warn(
|
|
161
|
+
`Force-releasing video recording bookkeeping for device '${udid}' despite a failed native stop: ` +
|
|
162
|
+
`${toTypedError(e).stack ?? e}`,
|
|
163
|
+
);
|
|
144
164
|
}
|
|
145
165
|
if (activeRecordings.get(key) === state) {
|
|
146
166
|
activeRecordings.delete(key);
|
package/src/coresim.mm
CHANGED
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
#include "native/objc_runtime.h"
|
|
32
32
|
#include "native/sim_device.h"
|
|
33
33
|
#include "native/sim_device_set.h"
|
|
34
|
+
#include "native/sim_jpeg_stream.h"
|
|
34
35
|
#include "native/sim_pasteboard.h"
|
|
35
36
|
#include "native/sim_process.h"
|
|
36
37
|
#include "native/sim_screenshot.h"
|
|
@@ -99,7 +100,7 @@ NSError* MakeDescriptorError(NSString* which, int savedErrno) {
|
|
|
99
100
|
}
|
|
100
101
|
|
|
101
102
|
NSError* MakeSpawnPathError(NSString* message) {
|
|
102
|
-
return [NSError errorWithDomain:@"
|
|
103
|
+
return [NSError errorWithDomain:@"io.appium.coresim.spawn" code:1 userInfo:@{NSLocalizedDescriptionKey : message}];
|
|
103
104
|
}
|
|
104
105
|
|
|
105
106
|
// Standard bin dirs to search, in order, when `path` is a bare command name (no `/`) — mirrors
|
|
@@ -258,9 +259,11 @@ struct AddonInstanceData {
|
|
|
258
259
|
Napi::FunctionReference avStreamConstructor;
|
|
259
260
|
Napi::FunctionReference avRecordingConstructor;
|
|
260
261
|
Napi::FunctionReference privateRecordingConstructor;
|
|
262
|
+
Napi::FunctionReference jpegStreamConstructor;
|
|
261
263
|
ActiveSessionRegistry<coresim::VideoStreamSession> activeVideoStreams;
|
|
262
264
|
ActiveSessionRegistry<coresim::AVStreamSession> activeAVStreams;
|
|
263
265
|
ActiveSessionRegistry<coresim::AVRecordingSession> activeAVRecordings;
|
|
266
|
+
ActiveSessionRegistry<coresim::JpegStreamSession> activeJpegStreams;
|
|
264
267
|
};
|
|
265
268
|
|
|
266
269
|
} // namespace
|
|
@@ -326,6 +329,58 @@ Napi::Object NativeVideoStream::NewInstance(Napi::Env env, std::shared_ptr<cores
|
|
|
326
329
|
env, boxed, [](Napi::Env /*env*/, std::shared_ptr<coresim::VideoStreamSession>* data) { delete data; })});
|
|
327
330
|
}
|
|
328
331
|
|
|
332
|
+
// Wraps a live coresim::JpegStreamSession — same shape as NativeVideoStream minus
|
|
333
|
+
// `requestKeyFrame()` (meaningless here: every JPEG frame is already independently decodable, see
|
|
334
|
+
// sim_jpeg_stream.h). Frames/errors are delivered live via the callbacks passed directly to
|
|
335
|
+
// startJpegStream, not through this object — it only exposes `stop()`.
|
|
336
|
+
class NativeJpegStream : public Napi::ObjectWrap<NativeJpegStream> {
|
|
337
|
+
public:
|
|
338
|
+
static void Init(Napi::Env env);
|
|
339
|
+
static Napi::Object NewInstance(Napi::Env env, std::shared_ptr<coresim::JpegStreamSession> session);
|
|
340
|
+
explicit NativeJpegStream(const Napi::CallbackInfo& info);
|
|
341
|
+
|
|
342
|
+
private:
|
|
343
|
+
std::shared_ptr<coresim::JpegStreamSession> session_;
|
|
344
|
+
|
|
345
|
+
Napi::Value Stop(const Napi::CallbackInfo& info) {
|
|
346
|
+
Napi::Env env = info.Env();
|
|
347
|
+
auto session = session_;
|
|
348
|
+
return RunAsyncVoid(env, [session]() { session->Stop(); });
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// See NativeVideoStream::Finalize for why this hands off to a background queue.
|
|
352
|
+
void Finalize(Napi::Env env) override {
|
|
353
|
+
auto session = std::move(session_);
|
|
354
|
+
if (session) {
|
|
355
|
+
env.GetInstanceData<AddonInstanceData>()->activeJpegStreams.Deregister(session);
|
|
356
|
+
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
|
357
|
+
session->Stop();
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
};
|
|
362
|
+
|
|
363
|
+
NativeJpegStream::NativeJpegStream(const Napi::CallbackInfo& info) : Napi::ObjectWrap<NativeJpegStream>(info) {
|
|
364
|
+
auto* boxed = info[0].As<Napi::External<std::shared_ptr<coresim::JpegStreamSession>>>().Data();
|
|
365
|
+
session_ = *boxed;
|
|
366
|
+
info.Env().GetInstanceData<AddonInstanceData>()->activeJpegStreams.Register(session_);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
void NativeJpegStream::Init(Napi::Env env) {
|
|
370
|
+
Napi::Function ctor = DefineClass(env, "NativeJpegStream",
|
|
371
|
+
{
|
|
372
|
+
InstanceMethod<&NativeJpegStream::Stop>("stop"),
|
|
373
|
+
});
|
|
374
|
+
env.GetInstanceData<AddonInstanceData>()->jpegStreamConstructor = Napi::Persistent(ctor);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
Napi::Object NativeJpegStream::NewInstance(Napi::Env env, std::shared_ptr<coresim::JpegStreamSession> session) {
|
|
378
|
+
auto* boxed = new std::shared_ptr<coresim::JpegStreamSession>(std::move(session));
|
|
379
|
+
Napi::Function ctor = env.GetInstanceData<AddonInstanceData>()->jpegStreamConstructor.Value();
|
|
380
|
+
return ctor.New({Napi::External<std::shared_ptr<coresim::JpegStreamSession>>::New(
|
|
381
|
+
env, boxed, [](Napi::Env /*env*/, std::shared_ptr<coresim::JpegStreamSession>* data) { delete data; })});
|
|
382
|
+
}
|
|
383
|
+
|
|
329
384
|
// Wraps a live coresim::AVStreamSession — the combined-AV counterpart to NativeVideoStream above,
|
|
330
385
|
// same shape (only `stop()`/`requestKeyFrame()`; access units/errors are delivered live via the
|
|
331
386
|
// callbacks passed directly to startAVStream).
|
|
@@ -473,7 +528,7 @@ class NativePrivateRecordingHandle : public Napi::ObjectWrap<NativePrivateRecord
|
|
|
473
528
|
id device = device_;
|
|
474
529
|
return RunAsyncVoid(env, [device]() {
|
|
475
530
|
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
|
|
476
|
-
dispatch_queue_t queue = dispatch_queue_create("
|
|
531
|
+
dispatch_queue_t queue = dispatch_queue_create("io.appium.coresim.stopRecordVideo", DISPATCH_QUEUE_SERIAL);
|
|
477
532
|
__block NSError* capturedError = nil;
|
|
478
533
|
NSError* resolveError = nil;
|
|
479
534
|
BOOL ok = coresim::StopVideoRecording(
|
|
@@ -573,7 +628,7 @@ class NativeDevice : public Napi::ObjectWrap<NativeDevice> {
|
|
|
573
628
|
NSDictionary* options = OptionsArg(info, 0);
|
|
574
629
|
return RunAsyncVoid(env, [device, options]() {
|
|
575
630
|
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
|
|
576
|
-
dispatch_queue_t queue = dispatch_queue_create("
|
|
631
|
+
dispatch_queue_t queue = dispatch_queue_create("io.appium.coresim.boot", DISPATCH_QUEUE_SERIAL);
|
|
577
632
|
__block NSError* capturedError = nil;
|
|
578
633
|
BootAsync(device, options, queue, ^(NSError* error) {
|
|
579
634
|
capturedError = error;
|
|
@@ -1048,8 +1103,8 @@ class NativeDevice : public Napi::ObjectWrap<NativeDevice> {
|
|
|
1048
1103
|
static coresim::VideoEncoderOptions ParseVideoEncoderOptions(const Napi::CallbackInfo& info, size_t argIndex) {
|
|
1049
1104
|
NSString* displayId = nil;
|
|
1050
1105
|
coresim::VideoStreamCodec codec = coresim::VideoStreamCodec::kH264;
|
|
1051
|
-
double fps =
|
|
1052
|
-
int bitrate =
|
|
1106
|
+
double fps = 60.0;
|
|
1107
|
+
int bitrate = 4000000;
|
|
1053
1108
|
if (info.Length() > argIndex && info[argIndex].IsObject()) {
|
|
1054
1109
|
Napi::Object options = info[argIndex].As<Napi::Object>();
|
|
1055
1110
|
if (options.Has("displayId") && options.Get("displayId").IsString()) {
|
|
@@ -1069,6 +1124,37 @@ class NativeDevice : public Napi::ObjectWrap<NativeDevice> {
|
|
|
1069
1124
|
return coresim::VideoEncoderOptions{codec, displayId, fps, bitrate};
|
|
1070
1125
|
}
|
|
1071
1126
|
|
|
1127
|
+
// `quality`/`displayId`/`fps` are this addon's own options, not a CoreSimulator options
|
|
1128
|
+
// dictionary — the TS layer (commands/jpeg-stream.ts) already constrains them, so anything else
|
|
1129
|
+
// (including absent) is just defaulted here rather than validated again (mirrors Screenshot's
|
|
1130
|
+
// identical comment above).
|
|
1131
|
+
static coresim::JpegStreamOptions ParseJpegStreamOptions(const Napi::CallbackInfo& info, size_t argIndex) {
|
|
1132
|
+
NSString* displayId = nil;
|
|
1133
|
+
double fps = 60.0;
|
|
1134
|
+
// Defaults to 80, not ImageIO's own (near-lossless, much larger) default — see
|
|
1135
|
+
// JpegStreamOptions's own comment (sim_jpeg_stream.h) for why.
|
|
1136
|
+
NSNumber* jpegQualityPercent = @80;
|
|
1137
|
+
double scale = 1.0;
|
|
1138
|
+
if (info.Length() > argIndex && info[argIndex].IsObject()) {
|
|
1139
|
+
Napi::Object options = info[argIndex].As<Napi::Object>();
|
|
1140
|
+
if (options.Has("displayId") && options.Get("displayId").IsString()) {
|
|
1141
|
+
displayId = @(options.Get("displayId").As<Napi::String>().Utf8Value().c_str());
|
|
1142
|
+
}
|
|
1143
|
+
if (options.Has("fps") && options.Get("fps").IsNumber()) {
|
|
1144
|
+
fps = options.Get("fps").As<Napi::Number>().DoubleValue();
|
|
1145
|
+
}
|
|
1146
|
+
if (options.Has("quality") && options.Get("quality").IsNumber()) {
|
|
1147
|
+
jpegQualityPercent = @(options.Get("quality").As<Napi::Number>().DoubleValue());
|
|
1148
|
+
}
|
|
1149
|
+
// JS-facing `scale` is a 1-100 percent (commands/jpeg-stream.ts already validates the
|
|
1150
|
+
// range), converted here to the 0.0-1.0 fraction JpegStreamSession actually applies.
|
|
1151
|
+
if (options.Has("scale") && options.Get("scale").IsNumber()) {
|
|
1152
|
+
scale = options.Get("scale").As<Napi::Number>().DoubleValue() / 100.0;
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1155
|
+
return coresim::JpegStreamOptions{displayId, fps, jpegQualityPercent, scale};
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1072
1158
|
static bool OptionsWantAudio(const Napi::CallbackInfo& info, size_t argIndex) {
|
|
1073
1159
|
return info.Length() > argIndex && info[argIndex].IsObject() && info[argIndex].As<Napi::Object>().Has("audio") &&
|
|
1074
1160
|
info[argIndex].As<Napi::Object>().Get("audio").IsBoolean() &&
|
|
@@ -1132,7 +1218,7 @@ class NativeDevice : public Napi::ObjectWrap<NativeDevice> {
|
|
|
1132
1218
|
env,
|
|
1133
1219
|
[device, displayId, mask, assetWriterOutputSettings, outputFile]() -> id {
|
|
1134
1220
|
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
|
|
1135
|
-
dispatch_queue_t queue = dispatch_queue_create("
|
|
1221
|
+
dispatch_queue_t queue = dispatch_queue_create("io.appium.coresim.recordVideo", DISPATCH_QUEUE_SERIAL);
|
|
1136
1222
|
__block NSError* capturedError = nil;
|
|
1137
1223
|
NSError* resolveError = nil;
|
|
1138
1224
|
BOOL ok = coresim::StartVideoRecording(
|
|
@@ -1380,6 +1466,81 @@ class NativeDevice : public Napi::ObjectWrap<NativeDevice> {
|
|
|
1380
1466
|
});
|
|
1381
1467
|
}
|
|
1382
1468
|
|
|
1469
|
+
// Real-time JPEG frame stream via ImageIO (see sim_jpeg_stream.mm) — a client-side MJPEG stream
|
|
1470
|
+
// is just this frame sequence multipart-boundary-framed over HTTP, which coresim itself has no
|
|
1471
|
+
// opinion about. Same TSFN/registry/teardown shape as StartVideoStream's audio-less branch,
|
|
1472
|
+
// minus keyframes/resync (every JPEG frame is independently decodable).
|
|
1473
|
+
Napi::Value StartJpegStream(const Napi::CallbackInfo& info) {
|
|
1474
|
+
Napi::Env env = info.Env();
|
|
1475
|
+
id device = device_;
|
|
1476
|
+
coresim::JpegStreamOptions options = ParseJpegStreamOptions(info, 0);
|
|
1477
|
+
Napi::Function onFrame = info[1].As<Napi::Function>();
|
|
1478
|
+
Napi::Function onError = info[2].As<Napi::Function>();
|
|
1479
|
+
|
|
1480
|
+
// See StartVideoStream's identical comment on accessUnitTsfn — bounded so a slow-draining
|
|
1481
|
+
// consumer throttles the encoder via BlockingCall instead of letting queued frames grow
|
|
1482
|
+
// unbounded.
|
|
1483
|
+
static constexpr size_t kFrameQueueSize = 60;
|
|
1484
|
+
Napi::ThreadSafeFunction frameTsfn =
|
|
1485
|
+
Napi::ThreadSafeFunction::New(env, onFrame, "coresim jpeg stream frame", kFrameQueueSize, 1);
|
|
1486
|
+
Napi::ThreadSafeFunction errorTsfn = Napi::ThreadSafeFunction::New(env, onError, "coresim jpeg stream error", 0, 1);
|
|
1487
|
+
auto tsfnGuard = std::make_shared<TsfnReleaseGuard>();
|
|
1488
|
+
|
|
1489
|
+
return RunAsync<std::shared_ptr<coresim::JpegStreamSession>>(
|
|
1490
|
+
env,
|
|
1491
|
+
[device, options, frameTsfn, errorTsfn, tsfnGuard]() mutable -> std::shared_ptr<coresim::JpegStreamSession> {
|
|
1492
|
+
auto session = std::make_shared<coresim::JpegStreamSession>(
|
|
1493
|
+
device, options,
|
|
1494
|
+
[frameTsfn](coresim::JpegFrame frame) mutable {
|
|
1495
|
+
frameTsfn.BlockingCall([frame = std::move(frame)](Napi::Env env, Napi::Function jsCallback) mutable {
|
|
1496
|
+
// See StartVideoStream's identical comment on why this is wrapped in try/catch.
|
|
1497
|
+
try {
|
|
1498
|
+
Napi::Object obj = Napi::Object::New(env);
|
|
1499
|
+
obj.Set("data", Napi::Buffer<uint8_t>::Copy(env, frame.data.data(), frame.data.size()));
|
|
1500
|
+
obj.Set("sequence", Napi::Number::New(env, static_cast<double>(frame.sequence)));
|
|
1501
|
+
obj.Set("timestampMicros", Napi::Number::New(env, static_cast<double>(frame.timestampMicros)));
|
|
1502
|
+
jsCallback.Call({obj});
|
|
1503
|
+
} catch (...) {
|
|
1504
|
+
}
|
|
1505
|
+
});
|
|
1506
|
+
},
|
|
1507
|
+
[errorTsfn](NSError* error) mutable {
|
|
1508
|
+
NSErrorException exception(error);
|
|
1509
|
+
errorTsfn.BlockingCall([exception](Napi::Env env, Napi::Function jsCallback) {
|
|
1510
|
+
try {
|
|
1511
|
+
jsCallback.Call({NSErrorExceptionToJsError(env, exception).Value()});
|
|
1512
|
+
} catch (...) {
|
|
1513
|
+
}
|
|
1514
|
+
});
|
|
1515
|
+
},
|
|
1516
|
+
[frameTsfn, errorTsfn, tsfnGuard]() mutable {
|
|
1517
|
+
ReleaseTsfnOnce(tsfnGuard, [&]() mutable {
|
|
1518
|
+
frameTsfn.Release();
|
|
1519
|
+
errorTsfn.Release();
|
|
1520
|
+
});
|
|
1521
|
+
},
|
|
1522
|
+
[frameTsfn, errorTsfn, tsfnGuard]() mutable {
|
|
1523
|
+
ReleaseTsfnOnce(tsfnGuard, [&]() mutable {
|
|
1524
|
+
frameTsfn.Abort();
|
|
1525
|
+
errorTsfn.Abort();
|
|
1526
|
+
});
|
|
1527
|
+
});
|
|
1528
|
+
try {
|
|
1529
|
+
session->Start();
|
|
1530
|
+
} catch (...) {
|
|
1531
|
+
ReleaseTsfnOnce(tsfnGuard, [&]() mutable {
|
|
1532
|
+
frameTsfn.Release();
|
|
1533
|
+
errorTsfn.Release();
|
|
1534
|
+
});
|
|
1535
|
+
throw;
|
|
1536
|
+
}
|
|
1537
|
+
return session;
|
|
1538
|
+
},
|
|
1539
|
+
[](Napi::Env env, std::shared_ptr<coresim::JpegStreamSession> session) -> Napi::Value {
|
|
1540
|
+
return NativeJpegStream::NewInstance(env, session);
|
|
1541
|
+
});
|
|
1542
|
+
}
|
|
1543
|
+
|
|
1383
1544
|
// Option dictionary keys for `spawnWithPath:options:...` aren't part of the ObjC runtime
|
|
1384
1545
|
// metadata this addon resolves selectors from (they're string literals inside CoreSimulator's
|
|
1385
1546
|
// own implementation) — confirmed by resolving each `SimDeviceSpawnKey*` symbol at runtime via
|
|
@@ -1567,6 +1728,7 @@ void NativeDevice::Init(Napi::Env env) {
|
|
|
1567
1728
|
InstanceMethod<&NativeDevice::GetDisplays>("getDisplays"),
|
|
1568
1729
|
InstanceMethod<&NativeDevice::StartVideoRecording>("startVideoRecording"),
|
|
1569
1730
|
InstanceMethod<&NativeDevice::StartVideoStream>("startVideoStream"),
|
|
1731
|
+
InstanceMethod<&NativeDevice::StartJpegStream>("startJpegStream"),
|
|
1570
1732
|
InstanceMethod<&NativeDevice::Spawn>("spawn"),
|
|
1571
1733
|
});
|
|
1572
1734
|
env.GetInstanceData<AddonInstanceData>()->deviceConstructor = Napi::Persistent(ctor);
|
|
@@ -1818,6 +1980,7 @@ void CleanupActiveSessions(AddonInstanceData* instanceData) {
|
|
|
1818
1980
|
};
|
|
1819
1981
|
instanceData->activeVideoStreams.StopAll(stopStream);
|
|
1820
1982
|
instanceData->activeAVStreams.StopAll(stopStream);
|
|
1983
|
+
instanceData->activeJpegStreams.StopAll(stopStream);
|
|
1821
1984
|
instanceData->activeAVRecordings.StopAll([](auto& session) {
|
|
1822
1985
|
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
|
|
1823
1986
|
session->Stop([sema](NSError*) { dispatch_semaphore_signal(sema); });
|
|
@@ -1850,6 +2013,7 @@ Napi::Object Init(Napi::Env env, Napi::Object exports) {
|
|
|
1850
2013
|
NativeAVStream::Init(env);
|
|
1851
2014
|
NativeAVRecording::Init(env);
|
|
1852
2015
|
NativePrivateRecordingHandle::Init(env);
|
|
2016
|
+
NativeJpegStream::Init(env);
|
|
1853
2017
|
exports.Set("sharedServiceContext", Napi::Function::New(env, SharedServiceContextBinding));
|
|
1854
2018
|
exports.Set("frameworkVersion", Napi::Function::New(env, FrameworkVersionBinding));
|
|
1855
2019
|
exports.Set("flushActiveSessions", Napi::Function::New(env, FlushActiveSessionsBinding));
|
package/src/index.ts
CHANGED
|
@@ -2,6 +2,7 @@ export {NativeSimError, NativeSimUnavailableError, NativeSimDispatchError, Nativ
|
|
|
2
2
|
export {NativeSimctl} from './native-simctl.js';
|
|
3
3
|
export {SpawnedProcess} from './commands/spawn.js';
|
|
4
4
|
export {VideoStream} from './commands/video-stream.js';
|
|
5
|
+
export {JpegStream} from './commands/jpeg-stream.js';
|
|
5
6
|
export type {AppContainerType} from './commands/app.js';
|
|
6
7
|
export type {BiometricName} from './commands/biometric.js';
|
|
7
8
|
export {
|
|
@@ -10,6 +11,8 @@ export {
|
|
|
10
11
|
type ApnsAlert,
|
|
11
12
|
type ApnsPayload,
|
|
12
13
|
type ApnsSound,
|
|
14
|
+
type JpegFrame,
|
|
15
|
+
type JpegStreamOptions,
|
|
13
16
|
type PushNotificationPayload,
|
|
14
17
|
type ScreenshotOptions,
|
|
15
18
|
type SimBootInfo,
|
|
@@ -21,6 +24,7 @@ export {
|
|
|
21
24
|
type SimProcessInfo,
|
|
22
25
|
type SimRuntimeInfo,
|
|
23
26
|
type SpawnOptions,
|
|
27
|
+
type StopVideoRecordingOptions,
|
|
24
28
|
type VideoAccessUnit,
|
|
25
29
|
type VideoRecordingOptions,
|
|
26
30
|
type VideoStreamOptions,
|
|
@@ -12,7 +12,7 @@ namespace coresim {
|
|
|
12
12
|
|
|
13
13
|
namespace {
|
|
14
14
|
|
|
15
|
-
NSString* const kAudioEncoderErrorDomain = @"
|
|
15
|
+
NSString* const kAudioEncoderErrorDomain = @"io.appium.coresim.AudioEncoder";
|
|
16
16
|
|
|
17
17
|
NSError* MakeError(NSInteger code, NSString* message) {
|
|
18
18
|
return [NSError errorWithDomain:kAudioEncoderErrorDomain code:code userInfo:@{NSLocalizedDescriptionKey : message}];
|
|
@@ -13,7 +13,7 @@ namespace coresim {
|
|
|
13
13
|
|
|
14
14
|
namespace {
|
|
15
15
|
|
|
16
|
-
NSString* const kAVRecordingErrorDomain = @"
|
|
16
|
+
NSString* const kAVRecordingErrorDomain = @"io.appium.coresim.AVRecording";
|
|
17
17
|
|
|
18
18
|
NSError* MakeError(NSInteger code, NSString* message) {
|
|
19
19
|
return [NSError errorWithDomain:kAVRecordingErrorDomain code:code userInfo:@{NSLocalizedDescriptionKey : message}];
|