@yume-chan/scrcpy 0.0.18 → 0.0.20

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.
Files changed (288) hide show
  1. package/CHANGELOG.json +33 -0
  2. package/CHANGELOG.md +18 -1
  3. package/README.md +157 -183
  4. package/bin/scrcpy-server +0 -0
  5. package/bin/version.d.ts +1 -1
  6. package/bin/version.js +1 -1
  7. package/esm/codec/av1.d.ts +33 -0
  8. package/esm/codec/av1.d.ts.map +1 -0
  9. package/esm/codec/av1.js +35 -0
  10. package/esm/codec/av1.js.map +1 -0
  11. package/esm/codec/h264.d.ts +78 -0
  12. package/esm/codec/h264.d.ts.map +1 -0
  13. package/esm/codec/h264.js +256 -0
  14. package/esm/codec/h264.js.map +1 -0
  15. package/esm/codec/h265.d.ts +490 -0
  16. package/esm/codec/h265.d.ts.map +1 -0
  17. package/esm/codec/h265.js +1098 -0
  18. package/esm/codec/h265.js.map +1 -0
  19. package/esm/codec/index.d.ts +5 -0
  20. package/esm/codec/index.d.ts.map +1 -0
  21. package/esm/codec/index.js +5 -0
  22. package/esm/codec/index.js.map +1 -0
  23. package/esm/codec/nalu.d.ts +44 -0
  24. package/esm/codec/nalu.d.ts.map +1 -0
  25. package/esm/codec/nalu.js +310 -0
  26. package/esm/codec/nalu.js.map +1 -0
  27. package/esm/control/back-or-screen-on.d.ts +2 -2
  28. package/esm/control/back-or-screen-on.d.ts.map +1 -1
  29. package/esm/control/back-or-screen-on.js +1 -1
  30. package/esm/control/basic.d.ts +5 -0
  31. package/esm/control/basic.d.ts.map +1 -0
  32. package/esm/control/basic.js +3 -0
  33. package/esm/control/basic.js.map +1 -0
  34. package/esm/control/hover-helper.d.ts +17 -17
  35. package/esm/control/hover-helper.d.ts.map +1 -1
  36. package/esm/control/hover-helper.js +43 -43
  37. package/esm/control/hover-helper.js.map +1 -1
  38. package/esm/control/index.d.ts +13 -11
  39. package/esm/control/index.d.ts.map +1 -1
  40. package/esm/control/index.js +13 -11
  41. package/esm/control/index.js.map +1 -1
  42. package/esm/control/inject-keycode.d.ts +193 -60
  43. package/esm/control/inject-keycode.d.ts.map +1 -1
  44. package/esm/control/inject-keycode.js +198 -61
  45. package/esm/control/inject-keycode.js.map +1 -1
  46. package/esm/control/inject-scroll.d.ts +2 -2
  47. package/esm/control/inject-scroll.d.ts.map +1 -1
  48. package/esm/control/inject-scroll.js +1 -1
  49. package/esm/control/inject-text.d.ts +7 -8
  50. package/esm/control/inject-text.d.ts.map +1 -1
  51. package/esm/control/inject-text.js +5 -6
  52. package/esm/control/inject-text.js.map +1 -1
  53. package/esm/control/inject-touch.d.ts +32 -37
  54. package/esm/control/inject-touch.d.ts.map +1 -1
  55. package/esm/control/inject-touch.js +35 -62
  56. package/esm/control/inject-touch.js.map +1 -1
  57. package/esm/control/rotate-device.d.ts +4 -6
  58. package/esm/control/rotate-device.d.ts.map +1 -1
  59. package/esm/control/rotate-device.js +2 -4
  60. package/esm/control/rotate-device.js.map +1 -1
  61. package/esm/control/serializer.d.ts +25 -33
  62. package/esm/control/serializer.d.ts.map +1 -1
  63. package/esm/control/serializer.js +53 -78
  64. package/esm/control/serializer.js.map +1 -1
  65. package/esm/control/set-clipboard.d.ts +2 -2
  66. package/esm/control/set-clipboard.d.ts.map +1 -1
  67. package/esm/control/set-clipboard.js +1 -1
  68. package/esm/control/set-screen-power-mode.d.ts +10 -11
  69. package/esm/control/set-screen-power-mode.d.ts.map +1 -1
  70. package/esm/control/set-screen-power-mode.js +10 -11
  71. package/esm/control/set-screen-power-mode.js.map +1 -1
  72. package/esm/control/type.d.ts +28 -14
  73. package/esm/control/type.d.ts.map +1 -1
  74. package/esm/control/type.js +40 -18
  75. package/esm/control/type.js.map +1 -1
  76. package/esm/control/writer.d.ts +28 -0
  77. package/esm/control/writer.d.ts.map +1 -0
  78. package/esm/control/writer.js +53 -0
  79. package/esm/control/writer.js.map +1 -0
  80. package/esm/device-message/ack-clipboard.d.ts +8 -8
  81. package/esm/device-message/ack-clipboard.d.ts.map +1 -1
  82. package/esm/device-message/ack-clipboard.js +5 -5
  83. package/esm/device-message/clipboard.d.ts +9 -9
  84. package/esm/device-message/clipboard.d.ts.map +1 -1
  85. package/esm/device-message/clipboard.js +6 -6
  86. package/esm/device-message/index.d.ts +4 -4
  87. package/esm/device-message/index.js +4 -4
  88. package/esm/device-message/stream.d.ts +7 -7
  89. package/esm/device-message/stream.d.ts.map +1 -1
  90. package/esm/device-message/stream.js +34 -19
  91. package/esm/device-message/stream.js.map +1 -1
  92. package/esm/device-message/type.d.ts +4 -4
  93. package/esm/device-message/type.js +6 -6
  94. package/esm/index.d.ts +4 -5
  95. package/esm/index.d.ts.map +1 -1
  96. package/esm/index.js +4 -5
  97. package/esm/index.js.map +1 -1
  98. package/esm/options/1_16/codec-options.d.ts +19 -19
  99. package/esm/options/1_16/codec-options.d.ts.map +1 -1
  100. package/esm/options/1_16/codec-options.js +25 -25
  101. package/esm/options/1_16/codec-options.js.map +1 -1
  102. package/esm/options/1_16/float-to-uint16.d.ts +5 -0
  103. package/esm/options/1_16/float-to-uint16.d.ts.map +1 -0
  104. package/esm/options/1_16/float-to-uint16.js +27 -0
  105. package/esm/options/1_16/float-to-uint16.js.map +1 -0
  106. package/esm/options/1_16/index.d.ts +6 -4
  107. package/esm/options/1_16/index.d.ts.map +1 -1
  108. package/esm/options/1_16/index.js +6 -4
  109. package/esm/options/1_16/index.js.map +1 -1
  110. package/esm/options/1_16/init.d.ts +66 -0
  111. package/esm/options/1_16/init.d.ts.map +1 -0
  112. package/esm/options/1_16/init.js +16 -0
  113. package/esm/options/1_16/init.js.map +1 -0
  114. package/esm/options/1_16/message.d.ts +32 -0
  115. package/esm/options/1_16/message.d.ts.map +1 -0
  116. package/esm/options/1_16/message.js +37 -0
  117. package/esm/options/1_16/message.js.map +1 -0
  118. package/esm/options/1_16/options.d.ts +48 -93
  119. package/esm/options/1_16/options.d.ts.map +1 -1
  120. package/esm/options/1_16/options.js +152 -189
  121. package/esm/options/1_16/options.js.map +1 -1
  122. package/esm/options/1_16/scroll.d.ts +26 -26
  123. package/esm/options/1_16/scroll.d.ts.map +1 -1
  124. package/esm/options/1_16/scroll.js +54 -55
  125. package/esm/options/1_16/scroll.js.map +1 -1
  126. package/esm/options/1_17.d.ts +33 -0
  127. package/esm/options/1_17.d.ts.map +1 -0
  128. package/esm/options/1_17.js +42 -0
  129. package/esm/options/1_17.js.map +1 -0
  130. package/esm/options/1_18.d.ts +59 -19
  131. package/esm/options/1_18.d.ts.map +1 -1
  132. package/esm/options/1_18.js +78 -45
  133. package/esm/options/1_18.js.map +1 -1
  134. package/esm/options/1_21.d.ts +41 -20
  135. package/esm/options/1_21.d.ts.map +1 -1
  136. package/esm/options/1_21.js +51 -36
  137. package/esm/options/1_21.js.map +1 -1
  138. package/esm/options/1_22/index.d.ts +3 -2
  139. package/esm/options/1_22/index.d.ts.map +1 -1
  140. package/esm/options/1_22/index.js +3 -2
  141. package/esm/options/1_22/index.js.map +1 -1
  142. package/esm/options/1_22/init.d.ts +17 -0
  143. package/esm/options/1_22/init.d.ts.map +1 -0
  144. package/esm/options/1_22/init.js +2 -0
  145. package/esm/options/1_22/init.js.map +1 -0
  146. package/esm/options/1_22/options.d.ts +35 -28
  147. package/esm/options/1_22/options.d.ts.map +1 -1
  148. package/esm/options/1_22/options.js +36 -25
  149. package/esm/options/1_22/options.js.map +1 -1
  150. package/esm/options/1_22/scroll.d.ts +16 -16
  151. package/esm/options/1_22/scroll.d.ts.map +1 -1
  152. package/esm/options/1_22/scroll.js +14 -14
  153. package/esm/options/1_23.d.ts +36 -11
  154. package/esm/options/1_23.d.ts.map +1 -1
  155. package/esm/options/1_23.js +44 -34
  156. package/esm/options/1_23.js.map +1 -1
  157. package/esm/options/1_24.d.ts +34 -8
  158. package/esm/options/1_24.d.ts.map +1 -1
  159. package/esm/options/1_24.js +22 -12
  160. package/esm/options/1_24.js.map +1 -1
  161. package/esm/options/1_25/index.d.ts +2 -2
  162. package/esm/options/1_25/index.js +2 -2
  163. package/esm/options/1_25/options.d.ts +10 -5
  164. package/esm/options/1_25/options.d.ts.map +1 -1
  165. package/esm/options/1_25/options.js +21 -7
  166. package/esm/options/1_25/options.js.map +1 -1
  167. package/esm/options/1_25/scroll.d.ts +19 -18
  168. package/esm/options/1_25/scroll.d.ts.map +1 -1
  169. package/esm/options/1_25/scroll.js +33 -32
  170. package/esm/options/1_25/scroll.js.map +1 -1
  171. package/esm/options/2_0.d.ts +91 -0
  172. package/esm/options/2_0.d.ts.map +1 -0
  173. package/esm/options/2_0.js +244 -0
  174. package/esm/options/2_0.js.map +1 -0
  175. package/esm/options/codec.d.ts +52 -0
  176. package/esm/options/codec.d.ts.map +1 -0
  177. package/esm/options/codec.js +26 -0
  178. package/esm/options/codec.js.map +1 -0
  179. package/esm/options/index.d.ts +12 -8
  180. package/esm/options/index.d.ts.map +1 -1
  181. package/esm/options/index.js +12 -8
  182. package/esm/options/index.js.map +1 -1
  183. package/esm/options/latest.d.ts +12 -0
  184. package/esm/options/latest.d.ts.map +1 -0
  185. package/esm/options/latest.js +8 -0
  186. package/esm/options/latest.js.map +1 -0
  187. package/esm/options/types.d.ts +86 -46
  188. package/esm/options/types.d.ts.map +1 -1
  189. package/esm/options/types.js +69 -17
  190. package/esm/options/types.js.map +1 -1
  191. package/package.json +10 -16
  192. package/src/codec/av1.ts +33 -0
  193. package/src/codec/h264.ts +317 -0
  194. package/src/codec/h265.ts +1375 -0
  195. package/src/codec/index.ts +4 -0
  196. package/src/codec/nalu.ts +373 -0
  197. package/src/control/back-or-screen-on.ts +1 -1
  198. package/src/control/basic.ts +3 -0
  199. package/src/control/hover-helper.ts +2 -4
  200. package/src/control/index.ts +2 -0
  201. package/src/control/inject-keycode.ts +194 -51
  202. package/src/control/inject-scroll.ts +1 -1
  203. package/src/control/inject-text.ts +6 -9
  204. package/src/control/inject-touch.ts +16 -55
  205. package/src/control/rotate-device.ts +3 -7
  206. package/src/control/serializer.ts +49 -105
  207. package/src/control/set-clipboard.ts +1 -1
  208. package/src/control/set-screen-power-mode.ts +6 -9
  209. package/src/control/type.ts +32 -0
  210. package/src/control/writer.ts +87 -0
  211. package/src/device-message/ack-clipboard.ts +1 -1
  212. package/src/device-message/clipboard.ts +1 -1
  213. package/src/device-message/stream.ts +32 -12
  214. package/src/index.ts +4 -5
  215. package/src/options/1_16/codec-options.ts +5 -8
  216. package/src/options/1_16/float-to-uint16.ts +33 -0
  217. package/src/options/1_16/index.ts +3 -1
  218. package/src/options/1_16/init.ts +80 -0
  219. package/src/options/1_16/message.ts +55 -0
  220. package/src/options/1_16/options.ts +152 -256
  221. package/src/options/1_16/scroll.ts +2 -5
  222. package/src/options/1_17.ts +66 -0
  223. package/src/options/1_18.ts +106 -42
  224. package/src/options/1_21.ts +51 -30
  225. package/src/options/1_22/index.ts +1 -0
  226. package/src/options/1_22/init.ts +19 -0
  227. package/src/options/1_22/options.ts +40 -46
  228. package/src/options/1_22/scroll.ts +2 -2
  229. package/src/options/1_23.ts +33 -23
  230. package/src/options/1_24.ts +25 -11
  231. package/src/options/1_25/options.ts +25 -6
  232. package/src/options/1_25/scroll.ts +5 -7
  233. package/src/options/2_0.ts +342 -0
  234. package/src/options/codec.ts +98 -0
  235. package/src/options/index.ts +7 -3
  236. package/src/options/latest.ts +14 -0
  237. package/src/options/types.ts +158 -48
  238. package/tsconfig.build.json +9 -1
  239. package/tsconfig.build.tsbuildinfo +1 -1
  240. package/esm/adb/client.d.ts +0 -41
  241. package/esm/adb/client.d.ts.map +0 -1
  242. package/esm/adb/client.js +0 -243
  243. package/esm/adb/client.js.map +0 -1
  244. package/esm/adb/connection.d.ts +0 -47
  245. package/esm/adb/connection.d.ts.map +0 -1
  246. package/esm/adb/connection.js +0 -110
  247. package/esm/adb/connection.js.map +0 -1
  248. package/esm/adb/index.d.ts +0 -4
  249. package/esm/adb/index.d.ts.map +0 -1
  250. package/esm/adb/index.js +0 -4
  251. package/esm/adb/index.js.map +0 -1
  252. package/esm/adb/options/1_16.d.ts +0 -8
  253. package/esm/adb/options/1_16.d.ts.map +0 -1
  254. package/esm/adb/options/1_16.js +0 -20
  255. package/esm/adb/options/1_16.js.map +0 -1
  256. package/esm/adb/options/1_22.d.ts +0 -8
  257. package/esm/adb/options/1_22.d.ts.map +0 -1
  258. package/esm/adb/options/1_22.js +0 -17
  259. package/esm/adb/options/1_22.js.map +0 -1
  260. package/esm/adb/options/index.d.ts +0 -4
  261. package/esm/adb/options/index.d.ts.map +0 -1
  262. package/esm/adb/options/index.js +0 -4
  263. package/esm/adb/options/index.js.map +0 -1
  264. package/esm/adb/options/types.d.ts +0 -24
  265. package/esm/adb/options/types.d.ts.map +0 -1
  266. package/esm/adb/options/types.js +0 -37
  267. package/esm/adb/options/types.js.map +0 -1
  268. package/esm/codec.d.ts +0 -34
  269. package/esm/codec.d.ts.map +0 -1
  270. package/esm/codec.js +0 -37
  271. package/esm/codec.js.map +0 -1
  272. package/esm/options/1_16/h264-configuration.d.ts +0 -49
  273. package/esm/options/1_16/h264-configuration.d.ts.map +0 -1
  274. package/esm/options/1_16/h264-configuration.js +0 -414
  275. package/esm/options/1_16/h264-configuration.js.map +0 -1
  276. package/esm/options/1_16/sps.d.ts +0 -22
  277. package/esm/options/1_16/sps.d.ts.map +0 -1
  278. package/esm/options/1_16/sps.js +0 -263
  279. package/esm/options/1_16/sps.js.map +0 -1
  280. package/src/adb/client.ts +0 -345
  281. package/src/adb/connection.ts +0 -192
  282. package/src/adb/index.ts +0 -3
  283. package/src/adb/options/1_16.ts +0 -30
  284. package/src/adb/options/1_22.ts +0 -26
  285. package/src/adb/options/index.ts +0 -3
  286. package/src/adb/options/types.ts +0 -75
  287. package/src/codec.ts +0 -35
  288. package/src/options/1_16/h264-configuration.ts +0 -485
@@ -0,0 +1,80 @@
1
+ import type { CodecOptions } from "./codec-options.js";
2
+
3
+ export enum ScrcpyLogLevel1_16 {
4
+ Debug = "debug",
5
+ Info = "info",
6
+ Warn = "warn",
7
+ Error = "error",
8
+ }
9
+
10
+ export enum ScrcpyVideoOrientation1_16 {
11
+ Unlocked = -1,
12
+ Portrait = 0,
13
+ Landscape = 1,
14
+ PortraitFlipped = 2,
15
+ LandscapeFlipped = 3,
16
+ }
17
+
18
+ export interface ScrcpyOptionsInit1_16 {
19
+ logLevel?: ScrcpyLogLevel1_16;
20
+
21
+ /**
22
+ * The maximum value of both width and height.
23
+ */
24
+ maxSize?: number;
25
+
26
+ bitRate?: number;
27
+
28
+ /**
29
+ * 0 for unlimited.
30
+ *
31
+ * @default 0
32
+ */
33
+ maxFps?: number;
34
+
35
+ /**
36
+ * The orientation of the video stream.
37
+ *
38
+ * It will not keep the device screen in specific orientation,
39
+ * only the captured video will in this orientation.
40
+ */
41
+ lockVideoOrientation?: ScrcpyVideoOrientation1_16;
42
+
43
+ /**
44
+ * Use ADB forward tunnel instead of reverse tunnel.
45
+ *
46
+ * This option is mainly used for working around the bug that on Android <9,
47
+ * ADB daemon can't create reverse tunnels if connected wirelessly (ADB over WiFi).
48
+ *
49
+ * When using `AdbScrcpyClient`, it can detect this situation and enable this option automatically.
50
+ */
51
+ tunnelForward?: boolean;
52
+
53
+ crop?: string | undefined;
54
+
55
+ /**
56
+ * Send PTS so that the client may record properly
57
+ *
58
+ * Note: When `sendFrameMeta: false` is specified,
59
+ * the video stream will not contain `configuration` typed packets,
60
+ * which means it can't be decoded by the companion decoders.
61
+ * It's still possible to record the stream into a file,
62
+ * or to decode it with a more tolerant decoder like FFMpeg.
63
+ *
64
+ * @default true
65
+ */
66
+ sendFrameMeta?: boolean;
67
+
68
+ /**
69
+ * @default true
70
+ */
71
+ control?: boolean;
72
+
73
+ displayId?: number;
74
+
75
+ showTouches?: boolean;
76
+
77
+ stayAwake?: boolean;
78
+
79
+ codecOptions?: CodecOptions;
80
+ }
@@ -0,0 +1,55 @@
1
+ import Struct, { placeholder } from "@yume-chan/struct";
2
+
3
+ import type { AndroidMotionEventAction } from "../../control/index.js";
4
+ import {
5
+ BasicControlMessage,
6
+ ScrcpyControlMessageType,
7
+ } from "../../control/index.js";
8
+
9
+ import { ScrcpyFloatToUint16FieldDefinition } from "./float-to-uint16.js";
10
+
11
+ export const SCRCPY_CONTROL_MESSAGE_TYPES_1_16: readonly ScrcpyControlMessageType[] =
12
+ [
13
+ /* 0 */ ScrcpyControlMessageType.InjectKeyCode,
14
+ /* 1 */ ScrcpyControlMessageType.InjectText,
15
+ /* 2 */ ScrcpyControlMessageType.InjectTouch,
16
+ /* 3 */ ScrcpyControlMessageType.InjectScroll,
17
+ /* 4 */ ScrcpyControlMessageType.BackOrScreenOn,
18
+ /* 5 */ ScrcpyControlMessageType.ExpandNotificationPanel,
19
+ /* 6 */ ScrcpyControlMessageType.CollapseNotificationPanel,
20
+ /* 7 */ ScrcpyControlMessageType.GetClipboard,
21
+ /* 8 */ ScrcpyControlMessageType.SetClipboard,
22
+ /* 9 */ ScrcpyControlMessageType.SetScreenPowerMode,
23
+ /* 10 */ ScrcpyControlMessageType.RotateDevice,
24
+ ];
25
+
26
+ export const ScrcpyMediaStreamRawPacket = new Struct()
27
+ .uint64("pts")
28
+ .uint32("size")
29
+ .uint8Array("data", { lengthField: "size" });
30
+
31
+ export const SCRCPY_MEDIA_PACKET_FLAG_CONFIG = 1n << 63n;
32
+
33
+ export const ScrcpyInjectTouchControlMessage1_16 = new Struct()
34
+ .uint8("type")
35
+ .uint8("action", placeholder<AndroidMotionEventAction>())
36
+ .uint64("pointerId")
37
+ .uint32("pointerX")
38
+ .uint32("pointerY")
39
+ .uint16("screenWidth")
40
+ .uint16("screenHeight")
41
+ .field("pressure", ScrcpyFloatToUint16FieldDefinition)
42
+ .uint32("buttons");
43
+
44
+ export type ScrcpyInjectTouchControlMessage1_16 =
45
+ (typeof ScrcpyInjectTouchControlMessage1_16)["TInit"];
46
+
47
+ export const ScrcpyBackOrScreenOnControlMessage1_16 = BasicControlMessage;
48
+
49
+ export const ScrcpySetClipboardControlMessage1_15 = new Struct()
50
+ .uint8("type")
51
+ .uint32("length")
52
+ .string("content", { lengthField: "length" });
53
+
54
+ export type ScrcpySetClipboardControlMessage1_15 =
55
+ (typeof ScrcpySetClipboardControlMessage1_15)["TInit"];
@@ -1,299 +1,205 @@
1
+ import type { ReadableStream } from "@yume-chan/stream-extra";
1
2
  import {
3
+ BufferedReadableStream,
2
4
  StructDeserializeStream,
3
5
  TransformStream,
4
6
  } from "@yume-chan/stream-extra";
5
- import Struct from "@yume-chan/struct";
7
+ import type { AsyncExactReadable, ValueOrPromise } from "@yume-chan/struct";
8
+ import { NumberFieldType, decodeUtf8 } from "@yume-chan/struct";
6
9
 
7
- import {
8
- AndroidKeyEventAction,
10
+ import type {
11
+ ScrcpyBackOrScreenOnControlMessage,
9
12
  ScrcpyControlMessageType,
10
- type ScrcpyBackOrScreenOnControlMessage,
11
- type ScrcpySetClipboardControlMessage,
13
+ ScrcpyInjectTouchControlMessage,
14
+ ScrcpySetClipboardControlMessage,
12
15
  } from "../../control/index.js";
13
- import {
14
- toScrcpyOptionValue,
15
- type ScrcpyOptions,
16
- type ScrcpyVideoStreamPacket,
17
- } from "../types.js";
16
+ import { AndroidKeyEventAction } from "../../control/index.js";
17
+ import type {
18
+ ScrcpyMediaStreamPacket,
19
+ ScrcpyVideoStream,
20
+ ScrcpyVideoStreamMetadata,
21
+ } from "../codec.js";
22
+ import { ScrcpyVideoCodecId } from "../codec.js";
23
+ import type { ScrcpyDisplay, ScrcpyEncoder, ScrcpyOptions } from "../types.js";
24
+ import { toScrcpyOptionValue } from "../types.js";
18
25
 
19
26
  import { CodecOptions } from "./codec-options.js";
27
+ import type { ScrcpyOptionsInit1_16 } from "./init.js";
28
+ import { ScrcpyLogLevel1_16, ScrcpyVideoOrientation1_16 } from "./init.js";
20
29
  import {
21
- parseH264Configuration,
22
- parseSequenceParameterSet,
23
- removeH264Emulation,
24
- } from "./h264-configuration.js";
25
- import {
26
- ScrcpyScrollController1_16,
27
- type ScrcpyScrollController,
28
- } from "./scroll.js";
29
-
30
- export enum ScrcpyLogLevel {
31
- Verbose = "verbose",
32
- Debug = "debug",
33
- Info = "info",
34
- Warn = "warn",
35
- Error = "error",
36
- }
37
-
38
- export enum ScrcpyVideoOrientation {
39
- Initial = -2,
40
- Unlocked = -1,
41
- Portrait = 0,
42
- Landscape = 1,
43
- PortraitFlipped = 2,
44
- LandscapeFlipped = 3,
45
- }
46
-
47
- export interface ScrcpyOptionsInit1_16 {
48
- logLevel: ScrcpyLogLevel;
49
-
50
- /**
51
- * The maximum value of both width and height.
52
- */
53
- maxSize: number;
54
-
55
- bitRate: number;
56
-
57
- /**
58
- * 0 for unlimited.
59
- *
60
- * @default 0
61
- */
62
- maxFps: number;
63
-
64
- /**
65
- * The orientation of the video stream.
66
- *
67
- * It will not keep the device screen in specific orientation,
68
- * only the captured video will in this orientation.
69
- */
70
- lockVideoOrientation: ScrcpyVideoOrientation;
71
-
72
- tunnelForward: boolean;
73
-
74
- crop: string;
75
-
76
- /**
77
- * Send PTS so that the client may record properly
78
- *
79
- * Note: When `sendFrameMeta: false` is specified,
80
- * `onChangeEncoding` event won't fire and `onVideoData` event doesn't
81
- * merge sps/pps frame and first video frame. Which means you can't use
82
- * the shipped decoders to render the video
83
- * (You can still record the stream into a file).
84
- *
85
- * @default true
86
- */
87
- sendFrameMeta: boolean;
88
-
89
- /**
90
- * @default true
91
- */
92
- control: boolean;
93
-
94
- displayId: number;
95
-
96
- showTouches: boolean;
97
-
98
- stayAwake: boolean;
99
-
100
- codecOptions: CodecOptions;
30
+ SCRCPY_CONTROL_MESSAGE_TYPES_1_16,
31
+ SCRCPY_MEDIA_PACKET_FLAG_CONFIG,
32
+ ScrcpyBackOrScreenOnControlMessage1_16,
33
+ ScrcpyInjectTouchControlMessage1_16,
34
+ ScrcpyMediaStreamRawPacket,
35
+ ScrcpySetClipboardControlMessage1_15,
36
+ } from "./message.js";
37
+ import type { ScrcpyScrollController } from "./scroll.js";
38
+ import { ScrcpyScrollController1_16 } from "./scroll.js";
39
+
40
+ export class ScrcpyOptions1_16 implements ScrcpyOptions<ScrcpyOptionsInit1_16> {
41
+ public static readonly DEFAULTS = {
42
+ logLevel: ScrcpyLogLevel1_16.Debug,
43
+ maxSize: 0,
44
+ bitRate: 8_000_000,
45
+ maxFps: 0,
46
+ lockVideoOrientation: ScrcpyVideoOrientation1_16.Unlocked,
47
+ tunnelForward: false,
48
+ crop: undefined,
49
+ sendFrameMeta: true,
50
+ control: true,
51
+ displayId: 0,
52
+ showTouches: false,
53
+ stayAwake: false,
54
+ codecOptions: new CodecOptions(),
55
+ } as const satisfies Required<ScrcpyOptionsInit1_16>;
56
+
57
+ public static readonly SERIALIZE_ORDER = [
58
+ "logLevel",
59
+ "maxSize",
60
+ "bitRate",
61
+ "maxFps",
62
+ "lockVideoOrientation",
63
+ "tunnelForward",
64
+ "crop",
65
+ "sendFrameMeta",
66
+ "control",
67
+ "displayId",
68
+ "showTouches",
69
+ "stayAwake",
70
+ "codecOptions",
71
+ ] as const satisfies readonly (keyof ScrcpyOptionsInit1_16)[];
72
+
73
+ public static serialize<T>(options: T, order: readonly (keyof T)[]) {
74
+ return order.map((key) => toScrcpyOptionValue(options[key], "-"));
75
+ }
101
76
 
102
- encoderName: string;
103
- }
77
+ public static async parseCString(
78
+ stream: AsyncExactReadable,
79
+ maxLength: number
80
+ ): Promise<string> {
81
+ let result = decodeUtf8(await stream.readExactly(maxLength));
82
+ result = result.substring(0, result.indexOf("\0"));
83
+ return result;
84
+ }
104
85
 
105
- export const VideoPacket = new Struct()
106
- .uint64("pts")
107
- .uint32("size")
108
- .uint8Array("data", { lengthField: "size" });
86
+ public static async parseUint16BE(
87
+ stream: AsyncExactReadable
88
+ ): Promise<number> {
89
+ const buffer = await stream.readExactly(NumberFieldType.Uint16.size);
90
+ return NumberFieldType.Uint16.deserialize(buffer, false);
91
+ }
109
92
 
110
- export const NO_PTS = BigInt(1) << BigInt(63);
93
+ public static async parseUint32BE(
94
+ stream: AsyncExactReadable
95
+ ): Promise<number> {
96
+ const buffer = await stream.readExactly(NumberFieldType.Uint32.size);
97
+ return NumberFieldType.Uint32.deserialize(buffer, false);
98
+ }
111
99
 
112
- export const ScrcpyBackOrScreenOnControlMessage1_16 = new Struct().uint8(
113
- "type",
114
- ScrcpyControlMessageType.BackOrScreenOn as const
115
- );
100
+ public value: Required<ScrcpyOptionsInit1_16>;
116
101
 
117
- export const ScrcpySetClipboardControlMessage1_15 = new Struct()
118
- .uint8("type", ScrcpyControlMessageType.SetClipboard as const)
119
- .uint32("length")
120
- .string("content", { lengthField: "length" });
102
+ public readonly defaults: Required<ScrcpyOptionsInit1_16> =
103
+ ScrcpyOptions1_16.DEFAULTS;
121
104
 
122
- export type ScrcpySetClipboardControlMessage1_15 =
123
- typeof ScrcpySetClipboardControlMessage1_15["TInit"];
105
+ public readonly controlMessageTypes: readonly ScrcpyControlMessageType[] =
106
+ SCRCPY_CONTROL_MESSAGE_TYPES_1_16;
124
107
 
125
- export class ScrcpyOptions1_16<
126
- T extends ScrcpyOptionsInit1_16 = ScrcpyOptionsInit1_16
127
- > implements ScrcpyOptions<T>
128
- {
129
- public value: Partial<T>;
108
+ public constructor(init: ScrcpyOptionsInit1_16) {
109
+ this.value = { ...ScrcpyOptions1_16.DEFAULTS, ...init };
110
+ }
130
111
 
131
- public constructor(value: Partial<ScrcpyOptionsInit1_16>) {
132
- if (
133
- new.target === ScrcpyOptions1_16 &&
134
- value.logLevel === ScrcpyLogLevel.Verbose
135
- ) {
136
- value.logLevel = ScrcpyLogLevel.Debug;
137
- }
112
+ public serialize(): string[] {
113
+ return ScrcpyOptions1_16.serialize(
114
+ this.value,
115
+ ScrcpyOptions1_16.SERIALIZE_ORDER
116
+ );
117
+ }
138
118
 
139
- if (
140
- new.target === ScrcpyOptions1_16 &&
141
- value.lockVideoOrientation === ScrcpyVideoOrientation.Initial
142
- ) {
143
- value.lockVideoOrientation = ScrcpyVideoOrientation.Unlocked;
144
- }
119
+ public setListEncoders(): void {
120
+ throw new Error("Not supported");
121
+ }
145
122
 
146
- this.value = value as Partial<T>;
123
+ public setListDisplays(): void {
124
+ // Set to an invalid value
125
+ // Server will print valid values before crashing
126
+ // (server will crash before opening sockets)
127
+ this.value.displayId = -1;
147
128
  }
148
129
 
149
- protected getArgumentOrder(): (keyof T)[] {
150
- return [
151
- "logLevel",
152
- "maxSize",
153
- "bitRate",
154
- "maxFps",
155
- "lockVideoOrientation",
156
- "tunnelForward",
157
- "crop",
158
- "sendFrameMeta",
159
- "control",
160
- "displayId",
161
- "showTouches",
162
- "stayAwake",
163
- "codecOptions",
164
- "encoderName",
165
- ];
130
+ public parseEncoder(): ScrcpyEncoder | undefined {
131
+ throw new Error("Not supported");
166
132
  }
167
133
 
168
- public getDefaultValue(): T {
169
- return {
170
- logLevel: ScrcpyLogLevel.Debug,
171
- maxSize: 0,
172
- bitRate: 8_000_000,
173
- maxFps: 0,
174
- lockVideoOrientation: ScrcpyVideoOrientation.Unlocked,
175
- tunnelForward: false,
176
- crop: "-",
177
- sendFrameMeta: true,
178
- control: true,
179
- displayId: 0,
180
- showTouches: false,
181
- stayAwake: false,
182
- codecOptions: new CodecOptions({}),
183
- encoderName: "-",
184
- } as T;
134
+ public parseDisplay(line: string): ScrcpyDisplay | undefined {
135
+ const displayIdRegex = /\s+scrcpy --display (\d+)/;
136
+ const match = line.match(displayIdRegex);
137
+ if (match) {
138
+ return {
139
+ id: Number.parseInt(match[1]!, 10),
140
+ };
141
+ }
142
+ return undefined;
185
143
  }
186
144
 
187
- public formatServerArguments(): string[] {
188
- const defaults = this.getDefaultValue();
189
- return this.getArgumentOrder().map((key) =>
190
- toScrcpyOptionValue(this.value[key] || defaults[key], "-")
191
- );
145
+ public parseVideoStreamMetadata(
146
+ stream: ReadableStream<Uint8Array>
147
+ ): ValueOrPromise<ScrcpyVideoStream> {
148
+ return (async () => {
149
+ const buffered = new BufferedReadableStream(stream);
150
+ const metadata: ScrcpyVideoStreamMetadata = {
151
+ codec: ScrcpyVideoCodecId.H264,
152
+ };
153
+ metadata.deviceName = await ScrcpyOptions1_16.parseCString(
154
+ buffered,
155
+ 64
156
+ );
157
+ metadata.width = await ScrcpyOptions1_16.parseUint16BE(buffered);
158
+ metadata.height = await ScrcpyOptions1_16.parseUint16BE(buffered);
159
+ return { stream: buffered.release(), metadata };
160
+ })();
192
161
  }
193
162
 
194
- public getOutputEncoderNameRegex(): RegExp {
195
- return /\s+scrcpy --encoder-name '(.*?)'/;
163
+ public parseAudioStreamMetadata(): never {
164
+ throw new Error("Not supported");
196
165
  }
197
166
 
198
- public createVideoStreamTransformer(): TransformStream<
167
+ public createMediaStreamTransformer(): TransformStream<
199
168
  Uint8Array,
200
- ScrcpyVideoStreamPacket
169
+ ScrcpyMediaStreamPacket
201
170
  > {
202
171
  // Optimized path for video frames only
203
- if (this.value.sendFrameMeta === false) {
172
+ if (!this.value.sendFrameMeta) {
204
173
  return new TransformStream({
205
174
  transform(chunk, controller) {
206
175
  controller.enqueue({
207
- type: "frame",
176
+ type: "data",
208
177
  data: chunk,
209
178
  });
210
179
  },
211
180
  });
212
181
  }
213
182
 
214
- let header: Uint8Array | undefined;
215
-
216
- const deserializeStream = new StructDeserializeStream(VideoPacket);
183
+ const deserializeStream = new StructDeserializeStream(
184
+ ScrcpyMediaStreamRawPacket
185
+ );
217
186
  return {
218
187
  writable: deserializeStream.writable,
219
188
  readable: deserializeStream.readable.pipeThrough(
220
189
  new TransformStream({
221
190
  transform(packet, controller) {
222
- if (packet.pts === NO_PTS) {
223
- const {
224
- sequenceParameterSet,
225
- pictureParameterSet,
226
- } = parseH264Configuration(packet.data);
227
-
228
- const {
229
- profile_idc: profileIndex,
230
- constraint_set: constraintSet,
231
- level_idc: levelIndex,
232
- pic_width_in_mbs_minus1,
233
- pic_height_in_map_units_minus1,
234
- frame_mbs_only_flag,
235
- frame_crop_left_offset,
236
- frame_crop_right_offset,
237
- frame_crop_top_offset,
238
- frame_crop_bottom_offset,
239
- } = parseSequenceParameterSet(
240
- removeH264Emulation(sequenceParameterSet)
241
- );
242
-
243
- const encodedWidth =
244
- (pic_width_in_mbs_minus1 + 1) * 16;
245
- const encodedHeight =
246
- (pic_height_in_map_units_minus1 + 1) *
247
- (2 - frame_mbs_only_flag) *
248
- 16;
249
- const cropLeft = frame_crop_left_offset * 2;
250
- const cropRight = frame_crop_right_offset * 2;
251
- const cropTop = frame_crop_top_offset * 2;
252
- const cropBottom = frame_crop_bottom_offset * 2;
253
-
254
- const croppedWidth =
255
- encodedWidth - cropLeft - cropRight;
256
- const croppedHeight =
257
- encodedHeight - cropTop - cropBottom;
258
-
259
- header = packet.data;
191
+ if (packet.pts === SCRCPY_MEDIA_PACKET_FLAG_CONFIG) {
260
192
  controller.enqueue({
261
193
  type: "configuration",
262
- pictureParameterSet,
263
- sequenceParameterSet,
264
- data: {
265
- profileIndex,
266
- constraintSet,
267
- levelIndex,
268
- encodedWidth,
269
- encodedHeight,
270
- cropLeft,
271
- cropRight,
272
- cropTop,
273
- cropBottom,
274
- croppedWidth,
275
- croppedHeight,
276
- },
194
+ data: packet.data,
277
195
  });
278
196
  return;
279
197
  }
280
198
 
281
- let frameData: Uint8Array;
282
- if (header) {
283
- frameData = new Uint8Array(
284
- header.byteLength + packet.data.byteLength
285
- );
286
- frameData.set(header);
287
- frameData.set(packet.data, header.byteLength);
288
- header = undefined;
289
- } else {
290
- frameData = packet.data;
291
- }
292
-
293
199
  controller.enqueue({
294
- type: "frame",
200
+ type: "data",
295
201
  pts: packet.pts,
296
- data: frameData,
202
+ data: packet.data,
297
203
  });
298
204
  },
299
205
  })
@@ -301,20 +207,10 @@ export class ScrcpyOptions1_16<
301
207
  };
302
208
  }
303
209
 
304
- public getControlMessageTypes(): ScrcpyControlMessageType[] {
305
- return [
306
- /* 0 */ ScrcpyControlMessageType.InjectKeyCode,
307
- /* 1 */ ScrcpyControlMessageType.InjectText,
308
- /* 2 */ ScrcpyControlMessageType.InjectTouch,
309
- /* 3 */ ScrcpyControlMessageType.InjectScroll,
310
- /* 4 */ ScrcpyControlMessageType.BackOrScreenOn,
311
- /* 5 */ ScrcpyControlMessageType.ExpandNotificationPanel,
312
- /* 6 */ ScrcpyControlMessageType.CollapseNotificationPanel,
313
- /* 7 */ ScrcpyControlMessageType.GetClipboard,
314
- /* 8 */ ScrcpyControlMessageType.SetClipboard,
315
- /* 9 */ ScrcpyControlMessageType.SetScreenPowerMode,
316
- /* 10 */ ScrcpyControlMessageType.RotateDevice,
317
- ];
210
+ public serializeInjectTouchControlMessage(
211
+ message: ScrcpyInjectTouchControlMessage
212
+ ): Uint8Array {
213
+ return ScrcpyInjectTouchControlMessage1_16.serialize(message);
318
214
  }
319
215
 
320
216
  public serializeBackOrScreenOnControlMessage(
@@ -333,7 +229,7 @@ export class ScrcpyOptions1_16<
333
229
  return ScrcpySetClipboardControlMessage1_15.serialize(message);
334
230
  }
335
231
 
336
- public getScrollController(): ScrcpyScrollController {
232
+ public createScrollController(): ScrcpyScrollController {
337
233
  return new ScrcpyScrollController1_16();
338
234
  }
339
235
  }
@@ -1,9 +1,6 @@
1
1
  import Struct from "@yume-chan/struct";
2
2
 
3
- import {
4
- ScrcpyControlMessageType,
5
- type ScrcpyInjectScrollControlMessage,
6
- } from "../../control/index.js";
3
+ import type { ScrcpyInjectScrollControlMessage } from "../../control/index.js";
7
4
 
8
5
  export interface ScrcpyScrollController {
9
6
  serializeScrollMessage(
@@ -12,7 +9,7 @@ export interface ScrcpyScrollController {
12
9
  }
13
10
 
14
11
  export const ScrcpyInjectScrollControlMessage1_16 = new Struct()
15
- .uint8("type", ScrcpyControlMessageType.InjectScroll as const)
12
+ .uint8("type")
16
13
  .uint32("pointerX")
17
14
  .uint32("pointerY")
18
15
  .uint16("screenWidth")