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