@midscene/android 1.12.1-beta-20260827032340.0 → 1.12.1
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/dist/es/cli.mjs +56 -79
- package/dist/es/index.mjs +55 -78
- package/dist/lib/cli.js +57 -80
- package/dist/lib/index.js +56 -79
- package/dist/types/index.d.ts +10 -16
- package/package.json +4 -4
package/dist/es/cli.mjs
CHANGED
|
@@ -32,10 +32,11 @@ var __webpack_modules__ = {
|
|
|
32
32
|
ScrcpyScreenshotManager: ()=>ScrcpyScreenshotManager,
|
|
33
33
|
ov: ()=>DEFAULT_SCRCPY_CONFIG
|
|
34
34
|
});
|
|
35
|
-
var
|
|
36
|
-
var
|
|
37
|
-
var
|
|
38
|
-
var
|
|
35
|
+
var node_fs__rspack_import_0 = __webpack_require__("node:fs");
|
|
36
|
+
var node_module__rspack_import_1 = __webpack_require__("node:module");
|
|
37
|
+
var node_path__rspack_import_2 = __webpack_require__("node:path");
|
|
38
|
+
var _midscene_shared_logger__rspack_import_3 = __webpack_require__("@midscene/shared/logger");
|
|
39
|
+
var _resource_path__rspack_import_4 = __webpack_require__("./src/resource-path.ts");
|
|
39
40
|
function _define_property(obj, key, value) {
|
|
40
41
|
if (key in obj) Object.defineProperty(obj, key, {
|
|
41
42
|
value: value,
|
|
@@ -46,8 +47,8 @@ var __webpack_modules__ = {
|
|
|
46
47
|
else obj[key] = value;
|
|
47
48
|
return obj;
|
|
48
49
|
}
|
|
49
|
-
const debugScrcpy = (0,
|
|
50
|
-
const warnScrcpy = (0,
|
|
50
|
+
const debugScrcpy = (0, _midscene_shared_logger__rspack_import_3.getDebug)('android:scrcpy');
|
|
51
|
+
const warnScrcpy = (0, _midscene_shared_logger__rspack_import_3.getDebug)('android:scrcpy', {
|
|
51
52
|
console: true
|
|
52
53
|
});
|
|
53
54
|
const NAL_TYPE_IDR = 5;
|
|
@@ -146,9 +147,10 @@ var __webpack_modules__ = {
|
|
|
146
147
|
try {
|
|
147
148
|
debugScrcpy('Starting scrcpy connection...');
|
|
148
149
|
const { AdbScrcpyClient } = await import("@yume-chan/adb-scrcpy");
|
|
150
|
+
const { ReadableStream } = await import("@yume-chan/stream-extra");
|
|
149
151
|
const { DefaultServerPath } = await import("@yume-chan/scrcpy");
|
|
150
152
|
const serverBinPath = this.resolveServerBinPath();
|
|
151
|
-
await
|
|
153
|
+
await AdbScrcpyClient.pushServer(this.adb, ReadableStream.from((0, node_fs__rspack_import_0.createReadStream)(serverBinPath)));
|
|
152
154
|
const scrcpyOptions = await this.createScrcpyOptions();
|
|
153
155
|
await this.ensureFrameClockCalibration();
|
|
154
156
|
this.scrcpyClient = await AdbScrcpyClient.start(this.adb, DefaultServerPath, scrcpyOptions);
|
|
@@ -232,12 +234,12 @@ var __webpack_modules__ = {
|
|
|
232
234
|
return output.filter((line)=>'string' == typeof line);
|
|
233
235
|
}
|
|
234
236
|
resolveServerBinPath() {
|
|
235
|
-
const androidPkgJson = (0,
|
|
236
|
-
return (0,
|
|
237
|
+
const androidPkgJson = (0, node_module__rspack_import_1.createRequire)(import.meta.url).resolve('@midscene/android/package.json');
|
|
238
|
+
return (0, _resource_path__rspack_import_4.J)(node_path__rspack_import_2["default"].join(node_path__rspack_import_2["default"].dirname(androidPkgJson), 'bin', 'scrcpy-server'));
|
|
237
239
|
}
|
|
238
240
|
getFfmpegPath() {
|
|
239
241
|
try {
|
|
240
|
-
const dynamicRequire = (0,
|
|
242
|
+
const dynamicRequire = (0, node_module__rspack_import_1.createRequire)(import.meta.url);
|
|
241
243
|
const ffmpegInstaller = dynamicRequire('@ffmpeg-installer/ffmpeg');
|
|
242
244
|
debugScrcpy(`Using ffmpeg from npm package: ${ffmpegInstaller.path}`);
|
|
243
245
|
return ffmpegInstaller.path;
|
|
@@ -776,63 +778,36 @@ var __webpack_modules__ = {
|
|
|
776
778
|
isConnected() {
|
|
777
779
|
return this.isInitialized && null !== this.scrcpyClient;
|
|
778
780
|
}
|
|
779
|
-
constructor(adb,
|
|
780
|
-
_define_property(this, "pushServer", void 0);
|
|
781
|
+
constructor(adb, options = {}){
|
|
781
782
|
_define_property(this, "adb", void 0);
|
|
782
|
-
_define_property(this, "scrcpyClient",
|
|
783
|
-
_define_property(this, "videoStream",
|
|
784
|
-
_define_property(this, "spsHeader",
|
|
785
|
-
_define_property(this, "idleTimer",
|
|
786
|
-
_define_property(this, "connectionPromise",
|
|
787
|
-
_define_property(this, "disposed",
|
|
788
|
-
_define_property(this, "isInitialized",
|
|
783
|
+
_define_property(this, "scrcpyClient", null);
|
|
784
|
+
_define_property(this, "videoStream", null);
|
|
785
|
+
_define_property(this, "spsHeader", null);
|
|
786
|
+
_define_property(this, "idleTimer", null);
|
|
787
|
+
_define_property(this, "connectionPromise", null);
|
|
788
|
+
_define_property(this, "disposed", false);
|
|
789
|
+
_define_property(this, "isInitialized", false);
|
|
789
790
|
_define_property(this, "options", void 0);
|
|
790
|
-
_define_property(this, "ffmpegAvailable",
|
|
791
|
-
_define_property(this, "keyframeResolvers",
|
|
792
|
-
_define_property(this, "keyframeListeners",
|
|
793
|
-
_define_property(this, "lastRawKeyframe",
|
|
794
|
-
_define_property(this, "lastRawKeyframeAt",
|
|
791
|
+
_define_property(this, "ffmpegAvailable", null);
|
|
792
|
+
_define_property(this, "keyframeResolvers", []);
|
|
793
|
+
_define_property(this, "keyframeListeners", new Set());
|
|
794
|
+
_define_property(this, "lastRawKeyframe", null);
|
|
795
|
+
_define_property(this, "lastRawKeyframeAt", 0);
|
|
795
796
|
_define_property(this, "lastRawKeyframePtsUs", void 0);
|
|
796
797
|
_define_property(this, "lastRawKeyframeEstimatedAgeMs", void 0);
|
|
797
|
-
_define_property(this, "videoResolution",
|
|
798
|
-
_define_property(this, "streamReader",
|
|
799
|
-
_define_property(this, "frameFreshnessBarrierPtsUs",
|
|
800
|
-
_define_property(this, "frameFreshnessBarrierReason",
|
|
801
|
-
_define_property(this, "streamStartupWindow",
|
|
802
|
-
_define_property(this, "frameFreshnessBarrierPending",
|
|
803
|
-
_define_property(this, "frameFreshnessBarrierGeneration",
|
|
804
|
-
_define_property(this, "deviceClockCalibration",
|
|
805
|
-
_define_property(this, "deviceClockCalibrationPromise",
|
|
806
|
-
_define_property(this, "lastFramePtsUs",
|
|
807
|
-
_define_property(this, "frameFreshnessError",
|
|
808
|
-
_define_property(this, "lastFrameFreshnessWarningAt",
|
|
809
|
-
_define_property(this, "disposePromise",
|
|
810
|
-
this.pushServer = pushServer;
|
|
811
|
-
this.scrcpyClient = null;
|
|
812
|
-
this.videoStream = null;
|
|
813
|
-
this.spsHeader = null;
|
|
814
|
-
this.idleTimer = null;
|
|
815
|
-
this.connectionPromise = null;
|
|
816
|
-
this.disposed = false;
|
|
817
|
-
this.isInitialized = false;
|
|
818
|
-
this.ffmpegAvailable = null;
|
|
819
|
-
this.keyframeResolvers = [];
|
|
820
|
-
this.keyframeListeners = new Set();
|
|
821
|
-
this.lastRawKeyframe = null;
|
|
822
|
-
this.lastRawKeyframeAt = 0;
|
|
823
|
-
this.videoResolution = null;
|
|
824
|
-
this.streamReader = null;
|
|
825
|
-
this.frameFreshnessBarrierPtsUs = null;
|
|
826
|
-
this.frameFreshnessBarrierReason = null;
|
|
827
|
-
this.streamStartupWindow = null;
|
|
828
|
-
this.frameFreshnessBarrierPending = false;
|
|
829
|
-
this.frameFreshnessBarrierGeneration = 0;
|
|
830
|
-
this.deviceClockCalibration = null;
|
|
831
|
-
this.deviceClockCalibrationPromise = null;
|
|
832
|
-
this.lastFramePtsUs = null;
|
|
833
|
-
this.frameFreshnessError = null;
|
|
834
|
-
this.lastFrameFreshnessWarningAt = 0;
|
|
835
|
-
this.disposePromise = null;
|
|
798
|
+
_define_property(this, "videoResolution", null);
|
|
799
|
+
_define_property(this, "streamReader", null);
|
|
800
|
+
_define_property(this, "frameFreshnessBarrierPtsUs", null);
|
|
801
|
+
_define_property(this, "frameFreshnessBarrierReason", null);
|
|
802
|
+
_define_property(this, "streamStartupWindow", null);
|
|
803
|
+
_define_property(this, "frameFreshnessBarrierPending", false);
|
|
804
|
+
_define_property(this, "frameFreshnessBarrierGeneration", 0);
|
|
805
|
+
_define_property(this, "deviceClockCalibration", null);
|
|
806
|
+
_define_property(this, "deviceClockCalibrationPromise", null);
|
|
807
|
+
_define_property(this, "lastFramePtsUs", null);
|
|
808
|
+
_define_property(this, "frameFreshnessError", null);
|
|
809
|
+
_define_property(this, "lastFrameFreshnessWarningAt", 0);
|
|
810
|
+
_define_property(this, "disposePromise", null);
|
|
836
811
|
this.adb = adb;
|
|
837
812
|
const requestedBitRate = options.videoBitRate ?? DEFAULT_VIDEO_BIT_RATE;
|
|
838
813
|
const clampedBitRate = Math.min(requestedBitRate, MAX_VIDEO_BIT_RATE);
|
|
@@ -1068,6 +1043,10 @@ function formatScrcpyFreshFrameFailure(error) {
|
|
|
1068
1043
|
const bitRateDescription = Number.isFinite(videoBitRate) ? ` Current videoBitRate: ${videoBitRate} bps (${videoBitRate / 1000000} Mbps).` : '';
|
|
1069
1044
|
return `No usable scrcpy frame crossed the active freshness target within ${timeoutMs}ms. This can happen when a static screen emits no new encoded frame, or when the video stream or transport is interrupted. This timeout does not by itself identify bandwidth or the configured video bitrate as the cause.${bitRateDescription}`;
|
|
1070
1045
|
}
|
|
1046
|
+
const DEFAULT_ADB_SERVER_ENDPOINT = {
|
|
1047
|
+
host: '127.0.0.1',
|
|
1048
|
+
port: 5037
|
|
1049
|
+
};
|
|
1071
1050
|
class ScrcpyDeviceAdapter {
|
|
1072
1051
|
isEnabled() {
|
|
1073
1052
|
if (!this.isConfigured()) return false;
|
|
@@ -1132,18 +1111,13 @@ class ScrcpyDeviceAdapter {
|
|
|
1132
1111
|
const { Adb, AdbServerClient } = await import("@yume-chan/adb");
|
|
1133
1112
|
const { AdbServerNodeTcpConnector } = await import("@yume-chan/adb-server-node-tcp");
|
|
1134
1113
|
const { ScrcpyScreenshotManager: ScrcpyManager } = await Promise.resolve().then(__webpack_require__.bind(__webpack_require__, "./src/scrcpy-manager.ts"));
|
|
1135
|
-
const
|
|
1136
|
-
const adbClient = new AdbServerClient(new AdbServerNodeTcpConnector(
|
|
1137
|
-
host: adbBackend.adbHost ?? '127.0.0.1',
|
|
1138
|
-
port: adbBackend.adbPort ?? 5037
|
|
1139
|
-
}));
|
|
1114
|
+
const adbServerEndpoint = await this.resolveAdbServerEndpoint();
|
|
1115
|
+
const adbClient = new AdbServerClient(new AdbServerNodeTcpConnector(adbServerEndpoint));
|
|
1140
1116
|
adb = new Adb(await adbClient.createTransport({
|
|
1141
1117
|
serial: this.deviceId
|
|
1142
1118
|
}));
|
|
1143
1119
|
const config = this.resolveConfig();
|
|
1144
|
-
manager = new ScrcpyManager(adb,
|
|
1145
|
-
await adbBackend.push(localPath, remotePath);
|
|
1146
|
-
}, {
|
|
1120
|
+
manager = new ScrcpyManager(adb, {
|
|
1147
1121
|
maxSize: config.maxSize,
|
|
1148
1122
|
videoBitRate: config.videoBitRate,
|
|
1149
1123
|
idleTimeoutMs: config.idleTimeoutMs
|
|
@@ -1337,13 +1311,10 @@ class ScrcpyDeviceAdapter {
|
|
|
1337
1311
|
this.resolvedConfig = null;
|
|
1338
1312
|
this.clearFailure();
|
|
1339
1313
|
}
|
|
1340
|
-
constructor(deviceId, scrcpyConfig,
|
|
1341
|
-
adbExecTimeout: 60000,
|
|
1342
|
-
deviceId
|
|
1343
|
-
})){
|
|
1314
|
+
constructor(deviceId, scrcpyConfig, resolveAdbServerEndpoint = ()=>DEFAULT_ADB_SERVER_ENDPOINT){
|
|
1344
1315
|
_define_property(this, "deviceId", void 0);
|
|
1345
1316
|
_define_property(this, "scrcpyConfig", void 0);
|
|
1346
|
-
_define_property(this, "
|
|
1317
|
+
_define_property(this, "resolveAdbServerEndpoint", void 0);
|
|
1347
1318
|
_define_property(this, "manager", void 0);
|
|
1348
1319
|
_define_property(this, "managerPromise", void 0);
|
|
1349
1320
|
_define_property(this, "resolvedConfig", void 0);
|
|
@@ -1356,7 +1327,7 @@ class ScrcpyDeviceAdapter {
|
|
|
1356
1327
|
_define_property(this, "keyframeUnsubscribers", void 0);
|
|
1357
1328
|
this.deviceId = deviceId;
|
|
1358
1329
|
this.scrcpyConfig = scrcpyConfig;
|
|
1359
|
-
this.
|
|
1330
|
+
this.resolveAdbServerEndpoint = resolveAdbServerEndpoint;
|
|
1360
1331
|
this.manager = null;
|
|
1361
1332
|
this.managerPromise = null;
|
|
1362
1333
|
this.resolvedConfig = null;
|
|
@@ -1856,7 +1827,13 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1856
1827
|
return adapter.getStatus();
|
|
1857
1828
|
}
|
|
1858
1829
|
getScrcpyAdapter() {
|
|
1859
|
-
if (!this.scrcpyAdapter) this.scrcpyAdapter = new ScrcpyDeviceAdapter(this.deviceId, this.options?.scrcpyConfig, ()=>
|
|
1830
|
+
if (!this.scrcpyAdapter) this.scrcpyAdapter = new ScrcpyDeviceAdapter(this.deviceId, this.options?.scrcpyConfig, async ()=>{
|
|
1831
|
+
const adb = await this.getAdb();
|
|
1832
|
+
return {
|
|
1833
|
+
host: adb.adbHost ?? '127.0.0.1',
|
|
1834
|
+
port: adb.adbPort ?? 5037
|
|
1835
|
+
};
|
|
1836
|
+
});
|
|
1860
1837
|
return this.scrcpyAdapter;
|
|
1861
1838
|
}
|
|
1862
1839
|
async openScrcpyFrameSource() {
|
|
@@ -3228,7 +3205,7 @@ class AndroidMidsceneTools extends BaseMidsceneTools {
|
|
|
3228
3205
|
const tools = new AndroidMidsceneTools();
|
|
3229
3206
|
runToolsCLI(tools, 'midscene-android', {
|
|
3230
3207
|
stripPrefix: 'android_',
|
|
3231
|
-
version: "1.12.1
|
|
3208
|
+
version: "1.12.1",
|
|
3232
3209
|
extraCommands: createReportCliCommands()
|
|
3233
3210
|
}).catch((e)=>{
|
|
3234
3211
|
process.exit(reportCLIError(e));
|
package/dist/es/index.mjs
CHANGED
|
@@ -31,10 +31,11 @@ var __webpack_modules__ = {
|
|
|
31
31
|
ScrcpyScreenshotManager: ()=>ScrcpyScreenshotManager,
|
|
32
32
|
ov: ()=>DEFAULT_SCRCPY_CONFIG
|
|
33
33
|
});
|
|
34
|
-
var
|
|
35
|
-
var
|
|
36
|
-
var
|
|
37
|
-
var
|
|
34
|
+
var node_fs__rspack_import_0 = __webpack_require__("node:fs");
|
|
35
|
+
var node_module__rspack_import_1 = __webpack_require__("node:module");
|
|
36
|
+
var node_path__rspack_import_2 = __webpack_require__("node:path");
|
|
37
|
+
var _midscene_shared_logger__rspack_import_3 = __webpack_require__("@midscene/shared/logger");
|
|
38
|
+
var _resource_path__rspack_import_4 = __webpack_require__("./src/resource-path.ts");
|
|
38
39
|
function _define_property(obj, key, value) {
|
|
39
40
|
if (key in obj) Object.defineProperty(obj, key, {
|
|
40
41
|
value: value,
|
|
@@ -45,8 +46,8 @@ var __webpack_modules__ = {
|
|
|
45
46
|
else obj[key] = value;
|
|
46
47
|
return obj;
|
|
47
48
|
}
|
|
48
|
-
const debugScrcpy = (0,
|
|
49
|
-
const warnScrcpy = (0,
|
|
49
|
+
const debugScrcpy = (0, _midscene_shared_logger__rspack_import_3.getDebug)('android:scrcpy');
|
|
50
|
+
const warnScrcpy = (0, _midscene_shared_logger__rspack_import_3.getDebug)('android:scrcpy', {
|
|
50
51
|
console: true
|
|
51
52
|
});
|
|
52
53
|
const NAL_TYPE_IDR = 5;
|
|
@@ -145,9 +146,10 @@ var __webpack_modules__ = {
|
|
|
145
146
|
try {
|
|
146
147
|
debugScrcpy('Starting scrcpy connection...');
|
|
147
148
|
const { AdbScrcpyClient } = await import("@yume-chan/adb-scrcpy");
|
|
149
|
+
const { ReadableStream } = await import("@yume-chan/stream-extra");
|
|
148
150
|
const { DefaultServerPath } = await import("@yume-chan/scrcpy");
|
|
149
151
|
const serverBinPath = this.resolveServerBinPath();
|
|
150
|
-
await
|
|
152
|
+
await AdbScrcpyClient.pushServer(this.adb, ReadableStream.from((0, node_fs__rspack_import_0.createReadStream)(serverBinPath)));
|
|
151
153
|
const scrcpyOptions = await this.createScrcpyOptions();
|
|
152
154
|
await this.ensureFrameClockCalibration();
|
|
153
155
|
this.scrcpyClient = await AdbScrcpyClient.start(this.adb, DefaultServerPath, scrcpyOptions);
|
|
@@ -231,12 +233,12 @@ var __webpack_modules__ = {
|
|
|
231
233
|
return output.filter((line)=>'string' == typeof line);
|
|
232
234
|
}
|
|
233
235
|
resolveServerBinPath() {
|
|
234
|
-
const androidPkgJson = (0,
|
|
235
|
-
return (0,
|
|
236
|
+
const androidPkgJson = (0, node_module__rspack_import_1.createRequire)(import.meta.url).resolve('@midscene/android/package.json');
|
|
237
|
+
return (0, _resource_path__rspack_import_4.J)(node_path__rspack_import_2["default"].join(node_path__rspack_import_2["default"].dirname(androidPkgJson), 'bin', 'scrcpy-server'));
|
|
236
238
|
}
|
|
237
239
|
getFfmpegPath() {
|
|
238
240
|
try {
|
|
239
|
-
const dynamicRequire = (0,
|
|
241
|
+
const dynamicRequire = (0, node_module__rspack_import_1.createRequire)(import.meta.url);
|
|
240
242
|
const ffmpegInstaller = dynamicRequire('@ffmpeg-installer/ffmpeg');
|
|
241
243
|
debugScrcpy(`Using ffmpeg from npm package: ${ffmpegInstaller.path}`);
|
|
242
244
|
return ffmpegInstaller.path;
|
|
@@ -775,63 +777,36 @@ var __webpack_modules__ = {
|
|
|
775
777
|
isConnected() {
|
|
776
778
|
return this.isInitialized && null !== this.scrcpyClient;
|
|
777
779
|
}
|
|
778
|
-
constructor(adb,
|
|
779
|
-
_define_property(this, "pushServer", void 0);
|
|
780
|
+
constructor(adb, options = {}){
|
|
780
781
|
_define_property(this, "adb", void 0);
|
|
781
|
-
_define_property(this, "scrcpyClient",
|
|
782
|
-
_define_property(this, "videoStream",
|
|
783
|
-
_define_property(this, "spsHeader",
|
|
784
|
-
_define_property(this, "idleTimer",
|
|
785
|
-
_define_property(this, "connectionPromise",
|
|
786
|
-
_define_property(this, "disposed",
|
|
787
|
-
_define_property(this, "isInitialized",
|
|
782
|
+
_define_property(this, "scrcpyClient", null);
|
|
783
|
+
_define_property(this, "videoStream", null);
|
|
784
|
+
_define_property(this, "spsHeader", null);
|
|
785
|
+
_define_property(this, "idleTimer", null);
|
|
786
|
+
_define_property(this, "connectionPromise", null);
|
|
787
|
+
_define_property(this, "disposed", false);
|
|
788
|
+
_define_property(this, "isInitialized", false);
|
|
788
789
|
_define_property(this, "options", void 0);
|
|
789
|
-
_define_property(this, "ffmpegAvailable",
|
|
790
|
-
_define_property(this, "keyframeResolvers",
|
|
791
|
-
_define_property(this, "keyframeListeners",
|
|
792
|
-
_define_property(this, "lastRawKeyframe",
|
|
793
|
-
_define_property(this, "lastRawKeyframeAt",
|
|
790
|
+
_define_property(this, "ffmpegAvailable", null);
|
|
791
|
+
_define_property(this, "keyframeResolvers", []);
|
|
792
|
+
_define_property(this, "keyframeListeners", new Set());
|
|
793
|
+
_define_property(this, "lastRawKeyframe", null);
|
|
794
|
+
_define_property(this, "lastRawKeyframeAt", 0);
|
|
794
795
|
_define_property(this, "lastRawKeyframePtsUs", void 0);
|
|
795
796
|
_define_property(this, "lastRawKeyframeEstimatedAgeMs", void 0);
|
|
796
|
-
_define_property(this, "videoResolution",
|
|
797
|
-
_define_property(this, "streamReader",
|
|
798
|
-
_define_property(this, "frameFreshnessBarrierPtsUs",
|
|
799
|
-
_define_property(this, "frameFreshnessBarrierReason",
|
|
800
|
-
_define_property(this, "streamStartupWindow",
|
|
801
|
-
_define_property(this, "frameFreshnessBarrierPending",
|
|
802
|
-
_define_property(this, "frameFreshnessBarrierGeneration",
|
|
803
|
-
_define_property(this, "deviceClockCalibration",
|
|
804
|
-
_define_property(this, "deviceClockCalibrationPromise",
|
|
805
|
-
_define_property(this, "lastFramePtsUs",
|
|
806
|
-
_define_property(this, "frameFreshnessError",
|
|
807
|
-
_define_property(this, "lastFrameFreshnessWarningAt",
|
|
808
|
-
_define_property(this, "disposePromise",
|
|
809
|
-
this.pushServer = pushServer;
|
|
810
|
-
this.scrcpyClient = null;
|
|
811
|
-
this.videoStream = null;
|
|
812
|
-
this.spsHeader = null;
|
|
813
|
-
this.idleTimer = null;
|
|
814
|
-
this.connectionPromise = null;
|
|
815
|
-
this.disposed = false;
|
|
816
|
-
this.isInitialized = false;
|
|
817
|
-
this.ffmpegAvailable = null;
|
|
818
|
-
this.keyframeResolvers = [];
|
|
819
|
-
this.keyframeListeners = new Set();
|
|
820
|
-
this.lastRawKeyframe = null;
|
|
821
|
-
this.lastRawKeyframeAt = 0;
|
|
822
|
-
this.videoResolution = null;
|
|
823
|
-
this.streamReader = null;
|
|
824
|
-
this.frameFreshnessBarrierPtsUs = null;
|
|
825
|
-
this.frameFreshnessBarrierReason = null;
|
|
826
|
-
this.streamStartupWindow = null;
|
|
827
|
-
this.frameFreshnessBarrierPending = false;
|
|
828
|
-
this.frameFreshnessBarrierGeneration = 0;
|
|
829
|
-
this.deviceClockCalibration = null;
|
|
830
|
-
this.deviceClockCalibrationPromise = null;
|
|
831
|
-
this.lastFramePtsUs = null;
|
|
832
|
-
this.frameFreshnessError = null;
|
|
833
|
-
this.lastFrameFreshnessWarningAt = 0;
|
|
834
|
-
this.disposePromise = null;
|
|
797
|
+
_define_property(this, "videoResolution", null);
|
|
798
|
+
_define_property(this, "streamReader", null);
|
|
799
|
+
_define_property(this, "frameFreshnessBarrierPtsUs", null);
|
|
800
|
+
_define_property(this, "frameFreshnessBarrierReason", null);
|
|
801
|
+
_define_property(this, "streamStartupWindow", null);
|
|
802
|
+
_define_property(this, "frameFreshnessBarrierPending", false);
|
|
803
|
+
_define_property(this, "frameFreshnessBarrierGeneration", 0);
|
|
804
|
+
_define_property(this, "deviceClockCalibration", null);
|
|
805
|
+
_define_property(this, "deviceClockCalibrationPromise", null);
|
|
806
|
+
_define_property(this, "lastFramePtsUs", null);
|
|
807
|
+
_define_property(this, "frameFreshnessError", null);
|
|
808
|
+
_define_property(this, "lastFrameFreshnessWarningAt", 0);
|
|
809
|
+
_define_property(this, "disposePromise", null);
|
|
835
810
|
this.adb = adb;
|
|
836
811
|
const requestedBitRate = options.videoBitRate ?? DEFAULT_VIDEO_BIT_RATE;
|
|
837
812
|
const clampedBitRate = Math.min(requestedBitRate, MAX_VIDEO_BIT_RATE);
|
|
@@ -971,6 +946,10 @@ function formatScrcpyFreshFrameFailure(error) {
|
|
|
971
946
|
const bitRateDescription = Number.isFinite(videoBitRate) ? ` Current videoBitRate: ${videoBitRate} bps (${videoBitRate / 1000000} Mbps).` : '';
|
|
972
947
|
return `No usable scrcpy frame crossed the active freshness target within ${timeoutMs}ms. This can happen when a static screen emits no new encoded frame, or when the video stream or transport is interrupted. This timeout does not by itself identify bandwidth or the configured video bitrate as the cause.${bitRateDescription}`;
|
|
973
948
|
}
|
|
949
|
+
const DEFAULT_ADB_SERVER_ENDPOINT = {
|
|
950
|
+
host: '127.0.0.1',
|
|
951
|
+
port: 5037
|
|
952
|
+
};
|
|
974
953
|
class ScrcpyDeviceAdapter {
|
|
975
954
|
isEnabled() {
|
|
976
955
|
if (!this.isConfigured()) return false;
|
|
@@ -1035,18 +1014,13 @@ class ScrcpyDeviceAdapter {
|
|
|
1035
1014
|
const { Adb, AdbServerClient } = await import("@yume-chan/adb");
|
|
1036
1015
|
const { AdbServerNodeTcpConnector } = await import("@yume-chan/adb-server-node-tcp");
|
|
1037
1016
|
const { ScrcpyScreenshotManager: ScrcpyManager } = await Promise.resolve().then(__webpack_require__.bind(__webpack_require__, "./src/scrcpy-manager.ts"));
|
|
1038
|
-
const
|
|
1039
|
-
const adbClient = new AdbServerClient(new AdbServerNodeTcpConnector(
|
|
1040
|
-
host: adbBackend.adbHost ?? '127.0.0.1',
|
|
1041
|
-
port: adbBackend.adbPort ?? 5037
|
|
1042
|
-
}));
|
|
1017
|
+
const adbServerEndpoint = await this.resolveAdbServerEndpoint();
|
|
1018
|
+
const adbClient = new AdbServerClient(new AdbServerNodeTcpConnector(adbServerEndpoint));
|
|
1043
1019
|
adb = new Adb(await adbClient.createTransport({
|
|
1044
1020
|
serial: this.deviceId
|
|
1045
1021
|
}));
|
|
1046
1022
|
const config = this.resolveConfig();
|
|
1047
|
-
manager = new ScrcpyManager(adb,
|
|
1048
|
-
await adbBackend.push(localPath, remotePath);
|
|
1049
|
-
}, {
|
|
1023
|
+
manager = new ScrcpyManager(adb, {
|
|
1050
1024
|
maxSize: config.maxSize,
|
|
1051
1025
|
videoBitRate: config.videoBitRate,
|
|
1052
1026
|
idleTimeoutMs: config.idleTimeoutMs
|
|
@@ -1240,13 +1214,10 @@ class ScrcpyDeviceAdapter {
|
|
|
1240
1214
|
this.resolvedConfig = null;
|
|
1241
1215
|
this.clearFailure();
|
|
1242
1216
|
}
|
|
1243
|
-
constructor(deviceId, scrcpyConfig,
|
|
1244
|
-
adbExecTimeout: 60000,
|
|
1245
|
-
deviceId
|
|
1246
|
-
})){
|
|
1217
|
+
constructor(deviceId, scrcpyConfig, resolveAdbServerEndpoint = ()=>DEFAULT_ADB_SERVER_ENDPOINT){
|
|
1247
1218
|
_define_property(this, "deviceId", void 0);
|
|
1248
1219
|
_define_property(this, "scrcpyConfig", void 0);
|
|
1249
|
-
_define_property(this, "
|
|
1220
|
+
_define_property(this, "resolveAdbServerEndpoint", void 0);
|
|
1250
1221
|
_define_property(this, "manager", void 0);
|
|
1251
1222
|
_define_property(this, "managerPromise", void 0);
|
|
1252
1223
|
_define_property(this, "resolvedConfig", void 0);
|
|
@@ -1259,7 +1230,7 @@ class ScrcpyDeviceAdapter {
|
|
|
1259
1230
|
_define_property(this, "keyframeUnsubscribers", void 0);
|
|
1260
1231
|
this.deviceId = deviceId;
|
|
1261
1232
|
this.scrcpyConfig = scrcpyConfig;
|
|
1262
|
-
this.
|
|
1233
|
+
this.resolveAdbServerEndpoint = resolveAdbServerEndpoint;
|
|
1263
1234
|
this.manager = null;
|
|
1264
1235
|
this.managerPromise = null;
|
|
1265
1236
|
this.resolvedConfig = null;
|
|
@@ -1759,7 +1730,13 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1759
1730
|
return adapter.getStatus();
|
|
1760
1731
|
}
|
|
1761
1732
|
getScrcpyAdapter() {
|
|
1762
|
-
if (!this.scrcpyAdapter) this.scrcpyAdapter = new ScrcpyDeviceAdapter(this.deviceId, this.options?.scrcpyConfig, ()=>
|
|
1733
|
+
if (!this.scrcpyAdapter) this.scrcpyAdapter = new ScrcpyDeviceAdapter(this.deviceId, this.options?.scrcpyConfig, async ()=>{
|
|
1734
|
+
const adb = await this.getAdb();
|
|
1735
|
+
return {
|
|
1736
|
+
host: adb.adbHost ?? '127.0.0.1',
|
|
1737
|
+
port: adb.adbPort ?? 5037
|
|
1738
|
+
};
|
|
1739
|
+
});
|
|
1763
1740
|
return this.scrcpyAdapter;
|
|
1764
1741
|
}
|
|
1765
1742
|
async openScrcpyFrameSource() {
|
package/dist/lib/cli.js
CHANGED
|
@@ -19,11 +19,12 @@ var __webpack_modules__ = {
|
|
|
19
19
|
ScrcpyScreenshotManager: ()=>ScrcpyScreenshotManager,
|
|
20
20
|
ov: ()=>DEFAULT_SCRCPY_CONFIG
|
|
21
21
|
});
|
|
22
|
-
var
|
|
23
|
-
var
|
|
24
|
-
var
|
|
25
|
-
var
|
|
26
|
-
var
|
|
22
|
+
var node_fs__rspack_import_0 = __webpack_require__("node:fs");
|
|
23
|
+
var node_module__rspack_import_1 = __webpack_require__("node:module");
|
|
24
|
+
var node_path__rspack_import_2 = __webpack_require__("node:path");
|
|
25
|
+
var node_path__rspack_import_2_default = /*#__PURE__*/ __webpack_require__.n(node_path__rspack_import_2);
|
|
26
|
+
var _midscene_shared_logger__rspack_import_3 = __webpack_require__("@midscene/shared/logger");
|
|
27
|
+
var _resource_path__rspack_import_4 = __webpack_require__("./src/resource-path.ts");
|
|
27
28
|
function _define_property(obj, key, value) {
|
|
28
29
|
if (key in obj) Object.defineProperty(obj, key, {
|
|
29
30
|
value: value,
|
|
@@ -34,8 +35,8 @@ var __webpack_modules__ = {
|
|
|
34
35
|
else obj[key] = value;
|
|
35
36
|
return obj;
|
|
36
37
|
}
|
|
37
|
-
const debugScrcpy = (0,
|
|
38
|
-
const warnScrcpy = (0,
|
|
38
|
+
const debugScrcpy = (0, _midscene_shared_logger__rspack_import_3.getDebug)('android:scrcpy');
|
|
39
|
+
const warnScrcpy = (0, _midscene_shared_logger__rspack_import_3.getDebug)('android:scrcpy', {
|
|
39
40
|
console: true
|
|
40
41
|
});
|
|
41
42
|
const NAL_TYPE_IDR = 5;
|
|
@@ -134,9 +135,10 @@ var __webpack_modules__ = {
|
|
|
134
135
|
try {
|
|
135
136
|
debugScrcpy('Starting scrcpy connection...');
|
|
136
137
|
const { AdbScrcpyClient } = await import("@yume-chan/adb-scrcpy");
|
|
138
|
+
const { ReadableStream } = await import("@yume-chan/stream-extra");
|
|
137
139
|
const { DefaultServerPath } = await import("@yume-chan/scrcpy");
|
|
138
140
|
const serverBinPath = this.resolveServerBinPath();
|
|
139
|
-
await
|
|
141
|
+
await AdbScrcpyClient.pushServer(this.adb, ReadableStream.from((0, node_fs__rspack_import_0.createReadStream)(serverBinPath)));
|
|
140
142
|
const scrcpyOptions = await this.createScrcpyOptions();
|
|
141
143
|
await this.ensureFrameClockCalibration();
|
|
142
144
|
this.scrcpyClient = await AdbScrcpyClient.start(this.adb, DefaultServerPath, scrcpyOptions);
|
|
@@ -220,12 +222,12 @@ var __webpack_modules__ = {
|
|
|
220
222
|
return output.filter((line)=>'string' == typeof line);
|
|
221
223
|
}
|
|
222
224
|
resolveServerBinPath() {
|
|
223
|
-
const androidPkgJson = (0,
|
|
224
|
-
return (0,
|
|
225
|
+
const androidPkgJson = (0, node_module__rspack_import_1.createRequire)(__rslib_import_meta_url__).resolve('@midscene/android/package.json');
|
|
226
|
+
return (0, _resource_path__rspack_import_4.J)(node_path__rspack_import_2_default().join(node_path__rspack_import_2_default().dirname(androidPkgJson), 'bin', 'scrcpy-server'));
|
|
225
227
|
}
|
|
226
228
|
getFfmpegPath() {
|
|
227
229
|
try {
|
|
228
|
-
const dynamicRequire = (0,
|
|
230
|
+
const dynamicRequire = (0, node_module__rspack_import_1.createRequire)(__rslib_import_meta_url__);
|
|
229
231
|
const ffmpegInstaller = dynamicRequire('@ffmpeg-installer/ffmpeg');
|
|
230
232
|
debugScrcpy(`Using ffmpeg from npm package: ${ffmpegInstaller.path}`);
|
|
231
233
|
return ffmpegInstaller.path;
|
|
@@ -764,63 +766,36 @@ var __webpack_modules__ = {
|
|
|
764
766
|
isConnected() {
|
|
765
767
|
return this.isInitialized && null !== this.scrcpyClient;
|
|
766
768
|
}
|
|
767
|
-
constructor(adb,
|
|
768
|
-
_define_property(this, "pushServer", void 0);
|
|
769
|
+
constructor(adb, options = {}){
|
|
769
770
|
_define_property(this, "adb", void 0);
|
|
770
|
-
_define_property(this, "scrcpyClient",
|
|
771
|
-
_define_property(this, "videoStream",
|
|
772
|
-
_define_property(this, "spsHeader",
|
|
773
|
-
_define_property(this, "idleTimer",
|
|
774
|
-
_define_property(this, "connectionPromise",
|
|
775
|
-
_define_property(this, "disposed",
|
|
776
|
-
_define_property(this, "isInitialized",
|
|
771
|
+
_define_property(this, "scrcpyClient", null);
|
|
772
|
+
_define_property(this, "videoStream", null);
|
|
773
|
+
_define_property(this, "spsHeader", null);
|
|
774
|
+
_define_property(this, "idleTimer", null);
|
|
775
|
+
_define_property(this, "connectionPromise", null);
|
|
776
|
+
_define_property(this, "disposed", false);
|
|
777
|
+
_define_property(this, "isInitialized", false);
|
|
777
778
|
_define_property(this, "options", void 0);
|
|
778
|
-
_define_property(this, "ffmpegAvailable",
|
|
779
|
-
_define_property(this, "keyframeResolvers",
|
|
780
|
-
_define_property(this, "keyframeListeners",
|
|
781
|
-
_define_property(this, "lastRawKeyframe",
|
|
782
|
-
_define_property(this, "lastRawKeyframeAt",
|
|
779
|
+
_define_property(this, "ffmpegAvailable", null);
|
|
780
|
+
_define_property(this, "keyframeResolvers", []);
|
|
781
|
+
_define_property(this, "keyframeListeners", new Set());
|
|
782
|
+
_define_property(this, "lastRawKeyframe", null);
|
|
783
|
+
_define_property(this, "lastRawKeyframeAt", 0);
|
|
783
784
|
_define_property(this, "lastRawKeyframePtsUs", void 0);
|
|
784
785
|
_define_property(this, "lastRawKeyframeEstimatedAgeMs", void 0);
|
|
785
|
-
_define_property(this, "videoResolution",
|
|
786
|
-
_define_property(this, "streamReader",
|
|
787
|
-
_define_property(this, "frameFreshnessBarrierPtsUs",
|
|
788
|
-
_define_property(this, "frameFreshnessBarrierReason",
|
|
789
|
-
_define_property(this, "streamStartupWindow",
|
|
790
|
-
_define_property(this, "frameFreshnessBarrierPending",
|
|
791
|
-
_define_property(this, "frameFreshnessBarrierGeneration",
|
|
792
|
-
_define_property(this, "deviceClockCalibration",
|
|
793
|
-
_define_property(this, "deviceClockCalibrationPromise",
|
|
794
|
-
_define_property(this, "lastFramePtsUs",
|
|
795
|
-
_define_property(this, "frameFreshnessError",
|
|
796
|
-
_define_property(this, "lastFrameFreshnessWarningAt",
|
|
797
|
-
_define_property(this, "disposePromise",
|
|
798
|
-
this.pushServer = pushServer;
|
|
799
|
-
this.scrcpyClient = null;
|
|
800
|
-
this.videoStream = null;
|
|
801
|
-
this.spsHeader = null;
|
|
802
|
-
this.idleTimer = null;
|
|
803
|
-
this.connectionPromise = null;
|
|
804
|
-
this.disposed = false;
|
|
805
|
-
this.isInitialized = false;
|
|
806
|
-
this.ffmpegAvailable = null;
|
|
807
|
-
this.keyframeResolvers = [];
|
|
808
|
-
this.keyframeListeners = new Set();
|
|
809
|
-
this.lastRawKeyframe = null;
|
|
810
|
-
this.lastRawKeyframeAt = 0;
|
|
811
|
-
this.videoResolution = null;
|
|
812
|
-
this.streamReader = null;
|
|
813
|
-
this.frameFreshnessBarrierPtsUs = null;
|
|
814
|
-
this.frameFreshnessBarrierReason = null;
|
|
815
|
-
this.streamStartupWindow = null;
|
|
816
|
-
this.frameFreshnessBarrierPending = false;
|
|
817
|
-
this.frameFreshnessBarrierGeneration = 0;
|
|
818
|
-
this.deviceClockCalibration = null;
|
|
819
|
-
this.deviceClockCalibrationPromise = null;
|
|
820
|
-
this.lastFramePtsUs = null;
|
|
821
|
-
this.frameFreshnessError = null;
|
|
822
|
-
this.lastFrameFreshnessWarningAt = 0;
|
|
823
|
-
this.disposePromise = null;
|
|
786
|
+
_define_property(this, "videoResolution", null);
|
|
787
|
+
_define_property(this, "streamReader", null);
|
|
788
|
+
_define_property(this, "frameFreshnessBarrierPtsUs", null);
|
|
789
|
+
_define_property(this, "frameFreshnessBarrierReason", null);
|
|
790
|
+
_define_property(this, "streamStartupWindow", null);
|
|
791
|
+
_define_property(this, "frameFreshnessBarrierPending", false);
|
|
792
|
+
_define_property(this, "frameFreshnessBarrierGeneration", 0);
|
|
793
|
+
_define_property(this, "deviceClockCalibration", null);
|
|
794
|
+
_define_property(this, "deviceClockCalibrationPromise", null);
|
|
795
|
+
_define_property(this, "lastFramePtsUs", null);
|
|
796
|
+
_define_property(this, "frameFreshnessError", null);
|
|
797
|
+
_define_property(this, "lastFrameFreshnessWarningAt", 0);
|
|
798
|
+
_define_property(this, "disposePromise", null);
|
|
824
799
|
this.adb = adb;
|
|
825
800
|
const requestedBitRate = options.videoBitRate ?? DEFAULT_VIDEO_BIT_RATE;
|
|
826
801
|
const clampedBitRate = Math.min(requestedBitRate, MAX_VIDEO_BIT_RATE);
|
|
@@ -1083,6 +1058,10 @@ ${stdout ? truncateAdbShellStream(stdout, 'stdout') : EMPTY_ADB_SHELL_STDOUT}`;
|
|
|
1083
1058
|
const bitRateDescription = Number.isFinite(videoBitRate) ? ` Current videoBitRate: ${videoBitRate} bps (${videoBitRate / 1000000} Mbps).` : '';
|
|
1084
1059
|
return `No usable scrcpy frame crossed the active freshness target within ${timeoutMs}ms. This can happen when a static screen emits no new encoded frame, or when the video stream or transport is interrupted. This timeout does not by itself identify bandwidth or the configured video bitrate as the cause.${bitRateDescription}`;
|
|
1085
1060
|
}
|
|
1061
|
+
const DEFAULT_ADB_SERVER_ENDPOINT = {
|
|
1062
|
+
host: '127.0.0.1',
|
|
1063
|
+
port: 5037
|
|
1064
|
+
};
|
|
1086
1065
|
class ScrcpyDeviceAdapter {
|
|
1087
1066
|
isEnabled() {
|
|
1088
1067
|
if (!this.isConfigured()) return false;
|
|
@@ -1147,18 +1126,13 @@ ${stdout ? truncateAdbShellStream(stdout, 'stdout') : EMPTY_ADB_SHELL_STDOUT}`;
|
|
|
1147
1126
|
const { Adb, AdbServerClient } = await import("@yume-chan/adb");
|
|
1148
1127
|
const { AdbServerNodeTcpConnector } = await import("@yume-chan/adb-server-node-tcp");
|
|
1149
1128
|
const { ScrcpyScreenshotManager: ScrcpyManager } = await Promise.resolve().then(__webpack_require__.bind(__webpack_require__, "./src/scrcpy-manager.ts"));
|
|
1150
|
-
const
|
|
1151
|
-
const adbClient = new AdbServerClient(new AdbServerNodeTcpConnector(
|
|
1152
|
-
host: adbBackend.adbHost ?? '127.0.0.1',
|
|
1153
|
-
port: adbBackend.adbPort ?? 5037
|
|
1154
|
-
}));
|
|
1129
|
+
const adbServerEndpoint = await this.resolveAdbServerEndpoint();
|
|
1130
|
+
const adbClient = new AdbServerClient(new AdbServerNodeTcpConnector(adbServerEndpoint));
|
|
1155
1131
|
adb = new Adb(await adbClient.createTransport({
|
|
1156
1132
|
serial: this.deviceId
|
|
1157
1133
|
}));
|
|
1158
1134
|
const config = this.resolveConfig();
|
|
1159
|
-
manager = new ScrcpyManager(adb,
|
|
1160
|
-
await adbBackend.push(localPath, remotePath);
|
|
1161
|
-
}, {
|
|
1135
|
+
manager = new ScrcpyManager(adb, {
|
|
1162
1136
|
maxSize: config.maxSize,
|
|
1163
1137
|
videoBitRate: config.videoBitRate,
|
|
1164
1138
|
idleTimeoutMs: config.idleTimeoutMs
|
|
@@ -1352,13 +1326,10 @@ ${stdout ? truncateAdbShellStream(stdout, 'stdout') : EMPTY_ADB_SHELL_STDOUT}`;
|
|
|
1352
1326
|
this.resolvedConfig = null;
|
|
1353
1327
|
this.clearFailure();
|
|
1354
1328
|
}
|
|
1355
|
-
constructor(deviceId, scrcpyConfig,
|
|
1356
|
-
adbExecTimeout: 60000,
|
|
1357
|
-
deviceId
|
|
1358
|
-
})){
|
|
1329
|
+
constructor(deviceId, scrcpyConfig, resolveAdbServerEndpoint = ()=>DEFAULT_ADB_SERVER_ENDPOINT){
|
|
1359
1330
|
_define_property(this, "deviceId", void 0);
|
|
1360
1331
|
_define_property(this, "scrcpyConfig", void 0);
|
|
1361
|
-
_define_property(this, "
|
|
1332
|
+
_define_property(this, "resolveAdbServerEndpoint", void 0);
|
|
1362
1333
|
_define_property(this, "manager", void 0);
|
|
1363
1334
|
_define_property(this, "managerPromise", void 0);
|
|
1364
1335
|
_define_property(this, "resolvedConfig", void 0);
|
|
@@ -1371,7 +1342,7 @@ ${stdout ? truncateAdbShellStream(stdout, 'stdout') : EMPTY_ADB_SHELL_STDOUT}`;
|
|
|
1371
1342
|
_define_property(this, "keyframeUnsubscribers", void 0);
|
|
1372
1343
|
this.deviceId = deviceId;
|
|
1373
1344
|
this.scrcpyConfig = scrcpyConfig;
|
|
1374
|
-
this.
|
|
1345
|
+
this.resolveAdbServerEndpoint = resolveAdbServerEndpoint;
|
|
1375
1346
|
this.manager = null;
|
|
1376
1347
|
this.managerPromise = null;
|
|
1377
1348
|
this.resolvedConfig = null;
|
|
@@ -1871,7 +1842,13 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1871
1842
|
return adapter.getStatus();
|
|
1872
1843
|
}
|
|
1873
1844
|
getScrcpyAdapter() {
|
|
1874
|
-
if (!this.scrcpyAdapter) this.scrcpyAdapter = new ScrcpyDeviceAdapter(this.deviceId, this.options?.scrcpyConfig, ()=>
|
|
1845
|
+
if (!this.scrcpyAdapter) this.scrcpyAdapter = new ScrcpyDeviceAdapter(this.deviceId, this.options?.scrcpyConfig, async ()=>{
|
|
1846
|
+
const adb = await this.getAdb();
|
|
1847
|
+
return {
|
|
1848
|
+
host: adb.adbHost ?? '127.0.0.1',
|
|
1849
|
+
port: adb.adbPort ?? 5037
|
|
1850
|
+
};
|
|
1851
|
+
});
|
|
1875
1852
|
return this.scrcpyAdapter;
|
|
1876
1853
|
}
|
|
1877
1854
|
async openScrcpyFrameSource() {
|
|
@@ -3243,7 +3220,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
3243
3220
|
const tools = new AndroidMidsceneTools();
|
|
3244
3221
|
(0, cli_namespaceObject.runToolsCLI)(tools, 'midscene-android', {
|
|
3245
3222
|
stripPrefix: 'android_',
|
|
3246
|
-
version: "1.12.1
|
|
3223
|
+
version: "1.12.1",
|
|
3247
3224
|
extraCommands: (0, core_namespaceObject.createReportCliCommands)()
|
|
3248
3225
|
}).catch((e)=>{
|
|
3249
3226
|
process.exit((0, cli_namespaceObject.reportCLIError)(e));
|
package/dist/lib/index.js
CHANGED
|
@@ -19,11 +19,12 @@ var __webpack_modules__ = {
|
|
|
19
19
|
ScrcpyScreenshotManager: ()=>ScrcpyScreenshotManager,
|
|
20
20
|
ov: ()=>DEFAULT_SCRCPY_CONFIG
|
|
21
21
|
});
|
|
22
|
-
var
|
|
23
|
-
var
|
|
24
|
-
var
|
|
25
|
-
var
|
|
26
|
-
var
|
|
22
|
+
var node_fs__rspack_import_0 = __webpack_require__("node:fs");
|
|
23
|
+
var node_module__rspack_import_1 = __webpack_require__("node:module");
|
|
24
|
+
var node_path__rspack_import_2 = __webpack_require__("node:path");
|
|
25
|
+
var node_path__rspack_import_2_default = /*#__PURE__*/ __webpack_require__.n(node_path__rspack_import_2);
|
|
26
|
+
var _midscene_shared_logger__rspack_import_3 = __webpack_require__("@midscene/shared/logger");
|
|
27
|
+
var _resource_path__rspack_import_4 = __webpack_require__("./src/resource-path.ts");
|
|
27
28
|
function _define_property(obj, key, value) {
|
|
28
29
|
if (key in obj) Object.defineProperty(obj, key, {
|
|
29
30
|
value: value,
|
|
@@ -34,8 +35,8 @@ var __webpack_modules__ = {
|
|
|
34
35
|
else obj[key] = value;
|
|
35
36
|
return obj;
|
|
36
37
|
}
|
|
37
|
-
const debugScrcpy = (0,
|
|
38
|
-
const warnScrcpy = (0,
|
|
38
|
+
const debugScrcpy = (0, _midscene_shared_logger__rspack_import_3.getDebug)('android:scrcpy');
|
|
39
|
+
const warnScrcpy = (0, _midscene_shared_logger__rspack_import_3.getDebug)('android:scrcpy', {
|
|
39
40
|
console: true
|
|
40
41
|
});
|
|
41
42
|
const NAL_TYPE_IDR = 5;
|
|
@@ -134,9 +135,10 @@ var __webpack_modules__ = {
|
|
|
134
135
|
try {
|
|
135
136
|
debugScrcpy('Starting scrcpy connection...');
|
|
136
137
|
const { AdbScrcpyClient } = await import("@yume-chan/adb-scrcpy");
|
|
138
|
+
const { ReadableStream } = await import("@yume-chan/stream-extra");
|
|
137
139
|
const { DefaultServerPath } = await import("@yume-chan/scrcpy");
|
|
138
140
|
const serverBinPath = this.resolveServerBinPath();
|
|
139
|
-
await
|
|
141
|
+
await AdbScrcpyClient.pushServer(this.adb, ReadableStream.from((0, node_fs__rspack_import_0.createReadStream)(serverBinPath)));
|
|
140
142
|
const scrcpyOptions = await this.createScrcpyOptions();
|
|
141
143
|
await this.ensureFrameClockCalibration();
|
|
142
144
|
this.scrcpyClient = await AdbScrcpyClient.start(this.adb, DefaultServerPath, scrcpyOptions);
|
|
@@ -220,12 +222,12 @@ var __webpack_modules__ = {
|
|
|
220
222
|
return output.filter((line)=>'string' == typeof line);
|
|
221
223
|
}
|
|
222
224
|
resolveServerBinPath() {
|
|
223
|
-
const androidPkgJson = (0,
|
|
224
|
-
return (0,
|
|
225
|
+
const androidPkgJson = (0, node_module__rspack_import_1.createRequire)(__rslib_import_meta_url__).resolve('@midscene/android/package.json');
|
|
226
|
+
return (0, _resource_path__rspack_import_4.J)(node_path__rspack_import_2_default().join(node_path__rspack_import_2_default().dirname(androidPkgJson), 'bin', 'scrcpy-server'));
|
|
225
227
|
}
|
|
226
228
|
getFfmpegPath() {
|
|
227
229
|
try {
|
|
228
|
-
const dynamicRequire = (0,
|
|
230
|
+
const dynamicRequire = (0, node_module__rspack_import_1.createRequire)(__rslib_import_meta_url__);
|
|
229
231
|
const ffmpegInstaller = dynamicRequire('@ffmpeg-installer/ffmpeg');
|
|
230
232
|
debugScrcpy(`Using ffmpeg from npm package: ${ffmpegInstaller.path}`);
|
|
231
233
|
return ffmpegInstaller.path;
|
|
@@ -764,63 +766,36 @@ var __webpack_modules__ = {
|
|
|
764
766
|
isConnected() {
|
|
765
767
|
return this.isInitialized && null !== this.scrcpyClient;
|
|
766
768
|
}
|
|
767
|
-
constructor(adb,
|
|
768
|
-
_define_property(this, "pushServer", void 0);
|
|
769
|
+
constructor(adb, options = {}){
|
|
769
770
|
_define_property(this, "adb", void 0);
|
|
770
|
-
_define_property(this, "scrcpyClient",
|
|
771
|
-
_define_property(this, "videoStream",
|
|
772
|
-
_define_property(this, "spsHeader",
|
|
773
|
-
_define_property(this, "idleTimer",
|
|
774
|
-
_define_property(this, "connectionPromise",
|
|
775
|
-
_define_property(this, "disposed",
|
|
776
|
-
_define_property(this, "isInitialized",
|
|
771
|
+
_define_property(this, "scrcpyClient", null);
|
|
772
|
+
_define_property(this, "videoStream", null);
|
|
773
|
+
_define_property(this, "spsHeader", null);
|
|
774
|
+
_define_property(this, "idleTimer", null);
|
|
775
|
+
_define_property(this, "connectionPromise", null);
|
|
776
|
+
_define_property(this, "disposed", false);
|
|
777
|
+
_define_property(this, "isInitialized", false);
|
|
777
778
|
_define_property(this, "options", void 0);
|
|
778
|
-
_define_property(this, "ffmpegAvailable",
|
|
779
|
-
_define_property(this, "keyframeResolvers",
|
|
780
|
-
_define_property(this, "keyframeListeners",
|
|
781
|
-
_define_property(this, "lastRawKeyframe",
|
|
782
|
-
_define_property(this, "lastRawKeyframeAt",
|
|
779
|
+
_define_property(this, "ffmpegAvailable", null);
|
|
780
|
+
_define_property(this, "keyframeResolvers", []);
|
|
781
|
+
_define_property(this, "keyframeListeners", new Set());
|
|
782
|
+
_define_property(this, "lastRawKeyframe", null);
|
|
783
|
+
_define_property(this, "lastRawKeyframeAt", 0);
|
|
783
784
|
_define_property(this, "lastRawKeyframePtsUs", void 0);
|
|
784
785
|
_define_property(this, "lastRawKeyframeEstimatedAgeMs", void 0);
|
|
785
|
-
_define_property(this, "videoResolution",
|
|
786
|
-
_define_property(this, "streamReader",
|
|
787
|
-
_define_property(this, "frameFreshnessBarrierPtsUs",
|
|
788
|
-
_define_property(this, "frameFreshnessBarrierReason",
|
|
789
|
-
_define_property(this, "streamStartupWindow",
|
|
790
|
-
_define_property(this, "frameFreshnessBarrierPending",
|
|
791
|
-
_define_property(this, "frameFreshnessBarrierGeneration",
|
|
792
|
-
_define_property(this, "deviceClockCalibration",
|
|
793
|
-
_define_property(this, "deviceClockCalibrationPromise",
|
|
794
|
-
_define_property(this, "lastFramePtsUs",
|
|
795
|
-
_define_property(this, "frameFreshnessError",
|
|
796
|
-
_define_property(this, "lastFrameFreshnessWarningAt",
|
|
797
|
-
_define_property(this, "disposePromise",
|
|
798
|
-
this.pushServer = pushServer;
|
|
799
|
-
this.scrcpyClient = null;
|
|
800
|
-
this.videoStream = null;
|
|
801
|
-
this.spsHeader = null;
|
|
802
|
-
this.idleTimer = null;
|
|
803
|
-
this.connectionPromise = null;
|
|
804
|
-
this.disposed = false;
|
|
805
|
-
this.isInitialized = false;
|
|
806
|
-
this.ffmpegAvailable = null;
|
|
807
|
-
this.keyframeResolvers = [];
|
|
808
|
-
this.keyframeListeners = new Set();
|
|
809
|
-
this.lastRawKeyframe = null;
|
|
810
|
-
this.lastRawKeyframeAt = 0;
|
|
811
|
-
this.videoResolution = null;
|
|
812
|
-
this.streamReader = null;
|
|
813
|
-
this.frameFreshnessBarrierPtsUs = null;
|
|
814
|
-
this.frameFreshnessBarrierReason = null;
|
|
815
|
-
this.streamStartupWindow = null;
|
|
816
|
-
this.frameFreshnessBarrierPending = false;
|
|
817
|
-
this.frameFreshnessBarrierGeneration = 0;
|
|
818
|
-
this.deviceClockCalibration = null;
|
|
819
|
-
this.deviceClockCalibrationPromise = null;
|
|
820
|
-
this.lastFramePtsUs = null;
|
|
821
|
-
this.frameFreshnessError = null;
|
|
822
|
-
this.lastFrameFreshnessWarningAt = 0;
|
|
823
|
-
this.disposePromise = null;
|
|
786
|
+
_define_property(this, "videoResolution", null);
|
|
787
|
+
_define_property(this, "streamReader", null);
|
|
788
|
+
_define_property(this, "frameFreshnessBarrierPtsUs", null);
|
|
789
|
+
_define_property(this, "frameFreshnessBarrierReason", null);
|
|
790
|
+
_define_property(this, "streamStartupWindow", null);
|
|
791
|
+
_define_property(this, "frameFreshnessBarrierPending", false);
|
|
792
|
+
_define_property(this, "frameFreshnessBarrierGeneration", 0);
|
|
793
|
+
_define_property(this, "deviceClockCalibration", null);
|
|
794
|
+
_define_property(this, "deviceClockCalibrationPromise", null);
|
|
795
|
+
_define_property(this, "lastFramePtsUs", null);
|
|
796
|
+
_define_property(this, "frameFreshnessError", null);
|
|
797
|
+
_define_property(this, "lastFrameFreshnessWarningAt", 0);
|
|
798
|
+
_define_property(this, "disposePromise", null);
|
|
824
799
|
this.adb = adb;
|
|
825
800
|
const requestedBitRate = options.videoBitRate ?? DEFAULT_VIDEO_BIT_RATE;
|
|
826
801
|
const clampedBitRate = Math.min(requestedBitRate, MAX_VIDEO_BIT_RATE);
|
|
@@ -1004,6 +979,10 @@ ${stdout ? truncateAdbShellStream(stdout, 'stdout') : EMPTY_ADB_SHELL_STDOUT}`;
|
|
|
1004
979
|
const bitRateDescription = Number.isFinite(videoBitRate) ? ` Current videoBitRate: ${videoBitRate} bps (${videoBitRate / 1000000} Mbps).` : '';
|
|
1005
980
|
return `No usable scrcpy frame crossed the active freshness target within ${timeoutMs}ms. This can happen when a static screen emits no new encoded frame, or when the video stream or transport is interrupted. This timeout does not by itself identify bandwidth or the configured video bitrate as the cause.${bitRateDescription}`;
|
|
1006
981
|
}
|
|
982
|
+
const DEFAULT_ADB_SERVER_ENDPOINT = {
|
|
983
|
+
host: '127.0.0.1',
|
|
984
|
+
port: 5037
|
|
985
|
+
};
|
|
1007
986
|
class ScrcpyDeviceAdapter {
|
|
1008
987
|
isEnabled() {
|
|
1009
988
|
if (!this.isConfigured()) return false;
|
|
@@ -1068,18 +1047,13 @@ ${stdout ? truncateAdbShellStream(stdout, 'stdout') : EMPTY_ADB_SHELL_STDOUT}`;
|
|
|
1068
1047
|
const { Adb, AdbServerClient } = await import("@yume-chan/adb");
|
|
1069
1048
|
const { AdbServerNodeTcpConnector } = await import("@yume-chan/adb-server-node-tcp");
|
|
1070
1049
|
const { ScrcpyScreenshotManager: ScrcpyManager } = await Promise.resolve().then(__webpack_require__.bind(__webpack_require__, "./src/scrcpy-manager.ts"));
|
|
1071
|
-
const
|
|
1072
|
-
const adbClient = new AdbServerClient(new AdbServerNodeTcpConnector(
|
|
1073
|
-
host: adbBackend.adbHost ?? '127.0.0.1',
|
|
1074
|
-
port: adbBackend.adbPort ?? 5037
|
|
1075
|
-
}));
|
|
1050
|
+
const adbServerEndpoint = await this.resolveAdbServerEndpoint();
|
|
1051
|
+
const adbClient = new AdbServerClient(new AdbServerNodeTcpConnector(adbServerEndpoint));
|
|
1076
1052
|
adb = new Adb(await adbClient.createTransport({
|
|
1077
1053
|
serial: this.deviceId
|
|
1078
1054
|
}));
|
|
1079
1055
|
const config = this.resolveConfig();
|
|
1080
|
-
manager = new ScrcpyManager(adb,
|
|
1081
|
-
await adbBackend.push(localPath, remotePath);
|
|
1082
|
-
}, {
|
|
1056
|
+
manager = new ScrcpyManager(adb, {
|
|
1083
1057
|
maxSize: config.maxSize,
|
|
1084
1058
|
videoBitRate: config.videoBitRate,
|
|
1085
1059
|
idleTimeoutMs: config.idleTimeoutMs
|
|
@@ -1273,13 +1247,10 @@ ${stdout ? truncateAdbShellStream(stdout, 'stdout') : EMPTY_ADB_SHELL_STDOUT}`;
|
|
|
1273
1247
|
this.resolvedConfig = null;
|
|
1274
1248
|
this.clearFailure();
|
|
1275
1249
|
}
|
|
1276
|
-
constructor(deviceId, scrcpyConfig,
|
|
1277
|
-
adbExecTimeout: 60000,
|
|
1278
|
-
deviceId
|
|
1279
|
-
})){
|
|
1250
|
+
constructor(deviceId, scrcpyConfig, resolveAdbServerEndpoint = ()=>DEFAULT_ADB_SERVER_ENDPOINT){
|
|
1280
1251
|
_define_property(this, "deviceId", void 0);
|
|
1281
1252
|
_define_property(this, "scrcpyConfig", void 0);
|
|
1282
|
-
_define_property(this, "
|
|
1253
|
+
_define_property(this, "resolveAdbServerEndpoint", void 0);
|
|
1283
1254
|
_define_property(this, "manager", void 0);
|
|
1284
1255
|
_define_property(this, "managerPromise", void 0);
|
|
1285
1256
|
_define_property(this, "resolvedConfig", void 0);
|
|
@@ -1292,7 +1263,7 @@ ${stdout ? truncateAdbShellStream(stdout, 'stdout') : EMPTY_ADB_SHELL_STDOUT}`;
|
|
|
1292
1263
|
_define_property(this, "keyframeUnsubscribers", void 0);
|
|
1293
1264
|
this.deviceId = deviceId;
|
|
1294
1265
|
this.scrcpyConfig = scrcpyConfig;
|
|
1295
|
-
this.
|
|
1266
|
+
this.resolveAdbServerEndpoint = resolveAdbServerEndpoint;
|
|
1296
1267
|
this.manager = null;
|
|
1297
1268
|
this.managerPromise = null;
|
|
1298
1269
|
this.resolvedConfig = null;
|
|
@@ -1792,7 +1763,13 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1792
1763
|
return adapter.getStatus();
|
|
1793
1764
|
}
|
|
1794
1765
|
getScrcpyAdapter() {
|
|
1795
|
-
if (!this.scrcpyAdapter) this.scrcpyAdapter = new ScrcpyDeviceAdapter(this.deviceId, this.options?.scrcpyConfig, ()=>
|
|
1766
|
+
if (!this.scrcpyAdapter) this.scrcpyAdapter = new ScrcpyDeviceAdapter(this.deviceId, this.options?.scrcpyConfig, async ()=>{
|
|
1767
|
+
const adb = await this.getAdb();
|
|
1768
|
+
return {
|
|
1769
|
+
host: adb.adbHost ?? '127.0.0.1',
|
|
1770
|
+
port: adb.adbPort ?? 5037
|
|
1771
|
+
};
|
|
1772
|
+
});
|
|
1796
1773
|
return this.scrcpyAdapter;
|
|
1797
1774
|
}
|
|
1798
1775
|
async openScrcpyFrameSource() {
|
package/dist/types/index.d.ts
CHANGED
|
@@ -23,6 +23,11 @@ import { UITreeSnapshot } from '@midscene/core';
|
|
|
23
23
|
|
|
24
24
|
declare type ActionArgs<T extends DeviceAction> = [ActionParam<T>] extends [undefined] ? [] : [ActionParam<T>];
|
|
25
25
|
|
|
26
|
+
declare interface AdbServerEndpoint {
|
|
27
|
+
host: string;
|
|
28
|
+
port: number;
|
|
29
|
+
}
|
|
30
|
+
|
|
26
31
|
export declare function agentFromAdbDevice(deviceId?: string, opts?: AndroidAgentOpt & AndroidDeviceOpt): Promise<AndroidAgent>;
|
|
27
32
|
|
|
28
33
|
export declare class AndroidAgent extends Agent<AndroidDevice> {
|
|
@@ -388,6 +393,8 @@ declare interface RawKeyframe {
|
|
|
388
393
|
capturedAt: number;
|
|
389
394
|
}
|
|
390
395
|
|
|
396
|
+
declare type ResolveAdbServerEndpoint = () => AdbServerEndpoint | Promise<AdbServerEndpoint>;
|
|
397
|
+
|
|
391
398
|
declare interface ResolvedScrcpyConfig {
|
|
392
399
|
enabled: boolean;
|
|
393
400
|
maxSize: number;
|
|
@@ -395,8 +402,6 @@ declare interface ResolvedScrcpyConfig {
|
|
|
395
402
|
idleTimeoutMs: number;
|
|
396
403
|
}
|
|
397
404
|
|
|
398
|
-
export declare type ResolveScrcpyAdbBackend = () => ScrcpyAdbBackend | Promise<ScrcpyAdbBackend>;
|
|
399
|
-
|
|
400
405
|
declare type RunAdbShellOpt = {
|
|
401
406
|
/**
|
|
402
407
|
* ADB shell command execution timeout in milliseconds.
|
|
@@ -404,13 +409,6 @@ declare type RunAdbShellOpt = {
|
|
|
404
409
|
timeout?: number;
|
|
405
410
|
};
|
|
406
411
|
|
|
407
|
-
/** ADB capabilities scrcpy needs from the canonical Appium transport. */
|
|
408
|
-
export declare interface ScrcpyAdbBackend {
|
|
409
|
-
adbHost?: string;
|
|
410
|
-
adbPort?: number;
|
|
411
|
-
push(localPath: string, remotePath: string): Promise<unknown>;
|
|
412
|
-
}
|
|
413
|
-
|
|
414
412
|
declare interface ScrcpyConfig {
|
|
415
413
|
enabled?: boolean;
|
|
416
414
|
maxSize?: number;
|
|
@@ -425,7 +423,7 @@ declare interface ScrcpyConfig {
|
|
|
425
423
|
export declare class ScrcpyDeviceAdapter {
|
|
426
424
|
private deviceId;
|
|
427
425
|
private scrcpyConfig;
|
|
428
|
-
private
|
|
426
|
+
private resolveAdbServerEndpoint;
|
|
429
427
|
private manager;
|
|
430
428
|
private managerPromise;
|
|
431
429
|
private resolvedConfig;
|
|
@@ -436,7 +434,7 @@ export declare class ScrcpyDeviceAdapter {
|
|
|
436
434
|
private pendingActionBarrierAtHostUs;
|
|
437
435
|
private keyframeListeners;
|
|
438
436
|
private keyframeUnsubscribers;
|
|
439
|
-
constructor(deviceId: string, scrcpyConfig: ScrcpyConfig | undefined,
|
|
437
|
+
constructor(deviceId: string, scrcpyConfig: ScrcpyConfig | undefined, resolveAdbServerEndpoint?: ResolveAdbServerEndpoint);
|
|
440
438
|
isEnabled(): boolean;
|
|
441
439
|
getStatus(): ScrcpyStatus;
|
|
442
440
|
private isConfigured;
|
|
@@ -529,7 +527,6 @@ declare interface ScrcpyFreshnessBarrierOptions {
|
|
|
529
527
|
}
|
|
530
528
|
|
|
531
529
|
declare class ScrcpyScreenshotManager {
|
|
532
|
-
private readonly pushServer;
|
|
533
530
|
private adb;
|
|
534
531
|
private scrcpyClient;
|
|
535
532
|
private videoStream;
|
|
@@ -559,7 +556,7 @@ declare class ScrcpyScreenshotManager {
|
|
|
559
556
|
private frameFreshnessError;
|
|
560
557
|
private lastFrameFreshnessWarningAt;
|
|
561
558
|
private disposePromise;
|
|
562
|
-
constructor(adb: Adb,
|
|
559
|
+
constructor(adb: Adb, options?: ScrcpyScreenshotOptions);
|
|
563
560
|
/**
|
|
564
561
|
* Validate environment prerequisites (ffmpeg, scrcpy-server, etc.)
|
|
565
562
|
* Must be called once after construction, before any screenshot operations.
|
|
@@ -722,9 +719,6 @@ declare interface ScrcpyScreenshotOptions {
|
|
|
722
719
|
idleTimeoutMs?: number;
|
|
723
720
|
}
|
|
724
721
|
|
|
725
|
-
/** Transfers the local scrcpy server binary to its device path. */
|
|
726
|
-
declare type ScrcpyServerPusher = (localPath: string, remotePath: string) => Promise<void>;
|
|
727
|
-
|
|
728
722
|
export declare interface ScrcpyStatus {
|
|
729
723
|
enabled: boolean;
|
|
730
724
|
connected: boolean;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@midscene/android",
|
|
3
|
-
"version": "1.12.1
|
|
3
|
+
"version": "1.12.1",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/web-infra-dev/midscene.git",
|
|
@@ -41,8 +41,8 @@
|
|
|
41
41
|
"@yume-chan/stream-extra": "2.6.1",
|
|
42
42
|
"appium-adb": "12.12.1",
|
|
43
43
|
"sharp": "^0.34.3",
|
|
44
|
-
"@midscene/shared": "1.12.1
|
|
45
|
-
"@midscene/core": "1.12.1
|
|
44
|
+
"@midscene/shared": "1.12.1",
|
|
45
|
+
"@midscene/core": "1.12.1"
|
|
46
46
|
},
|
|
47
47
|
"optionalDependencies": {
|
|
48
48
|
"@ffmpeg-installer/ffmpeg": "^1.1.0"
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"typescript": "^5.8.3",
|
|
57
57
|
"undici": "^6.0.0",
|
|
58
58
|
"zod": "^3.25.1",
|
|
59
|
-
"@midscene/playground": "1.12.1
|
|
59
|
+
"@midscene/playground": "1.12.1"
|
|
60
60
|
},
|
|
61
61
|
"license": "MIT",
|
|
62
62
|
"scripts": {
|