@midscene/android 1.12.2-beta-20260828072235.0 → 1.12.2

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