@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,13 +1,5 @@
1
- import type {
2
- Consumable,
3
- WritableStream,
4
- WritableStreamDefaultWriter,
5
- } from "@yume-chan/stream-extra";
6
- import { ConsumableWritableStream } from "@yume-chan/stream-extra";
7
-
8
1
  import type {
9
2
  ScrcpyOptions,
10
- ScrcpyOptionsInit1_16,
11
3
  ScrcpyScrollController,
12
4
  } from "../options/index.js";
13
5
 
@@ -15,84 +7,52 @@ import type { AndroidKeyEventAction } from "./inject-keycode.js";
15
7
  import { ScrcpyInjectKeyCodeControlMessage } from "./inject-keycode.js";
16
8
  import type { ScrcpyInjectScrollControlMessage } from "./inject-scroll.js";
17
9
  import { ScrcpyInjectTextControlMessage } from "./inject-text.js";
18
- import { ScrcpyInjectTouchControlMessage } from "./inject-touch.js";
10
+ import type { ScrcpyInjectTouchControlMessage } from "./inject-touch.js";
19
11
  import { ScrcpyRotateDeviceControlMessage } from "./rotate-device.js";
20
12
  import type { AndroidScreenPowerMode } from "./set-screen-power-mode.js";
21
13
  import { ScrcpySetScreenPowerModeControlMessage } from "./set-screen-power-mode.js";
22
- import { ScrcpyControlMessageType } from "./type.js";
14
+ import {
15
+ ScrcpyControlMessageType,
16
+ ScrcpyControlMessageTypeValue,
17
+ } from "./type.js";
23
18
 
24
19
  export class ScrcpyControlMessageSerializer {
25
- private options: ScrcpyOptions<ScrcpyOptionsInit1_16>;
26
- /** Control message type values for current version of server */
27
- private types: ScrcpyControlMessageType[];
28
- private writer: WritableStreamDefaultWriter<Consumable<Uint8Array>>;
29
- private scrollController: ScrcpyScrollController;
30
-
31
- public constructor(
32
- stream: WritableStream<Consumable<Uint8Array>>,
33
- options: ScrcpyOptions<ScrcpyOptionsInit1_16>
34
- ) {
35
- this.writer = stream.getWriter();
36
-
37
- this.options = options;
38
- this.types = options.getControlMessageTypes();
39
- this.scrollController = options.getScrollController();
40
- }
41
-
42
- public getActualMessageType(type: ScrcpyControlMessageType): number {
43
- const value = this.types.indexOf(type);
44
- if (value === -1) {
45
- throw new Error("Not supported");
46
- }
47
- return value;
48
- }
49
-
50
- public addMessageType<T extends { type: ScrcpyControlMessageType }>(
51
- message: Omit<T, "type">,
52
- type: T["type"]
53
- ): T {
54
- (message as T).type = this.getActualMessageType(type);
55
- return message as T;
56
- }
57
-
58
- private async write(data: Uint8Array) {
59
- await ConsumableWritableStream.write(this.writer, data);
20
+ private _options: ScrcpyOptions<object>;
21
+ private _typeValues: ScrcpyControlMessageTypeValue;
22
+ private _scrollController: ScrcpyScrollController;
23
+
24
+ public constructor(options: ScrcpyOptions<object>) {
25
+ this._options = options;
26
+ this._typeValues = new ScrcpyControlMessageTypeValue(options);
27
+ this._scrollController = options.createScrollController();
60
28
  }
61
29
 
62
30
  public injectKeyCode(
63
31
  message: Omit<ScrcpyInjectKeyCodeControlMessage, "type">
64
32
  ) {
65
- return this.write(
66
- ScrcpyInjectKeyCodeControlMessage.serialize(
67
- this.addMessageType(
68
- message,
69
- ScrcpyControlMessageType.InjectKeyCode
70
- )
33
+ return ScrcpyInjectKeyCodeControlMessage.serialize(
34
+ this._typeValues.fillMessageType(
35
+ message,
36
+ ScrcpyControlMessageType.InjectKeyCode
71
37
  )
72
38
  );
73
39
  }
74
40
 
75
41
  public injectText(text: string) {
76
- return this.write(
77
- ScrcpyInjectTextControlMessage.serialize({
78
- text,
79
- type: this.getActualMessageType(
80
- ScrcpyControlMessageType.InjectText
81
- ),
82
- })
83
- );
42
+ return ScrcpyInjectTextControlMessage.serialize({
43
+ text,
44
+ type: this._typeValues.get(ScrcpyControlMessageType.InjectText),
45
+ });
84
46
  }
85
47
 
86
48
  /**
87
49
  * `pressure` is a float value between 0 and 1.
88
50
  */
89
51
  public injectTouch(message: Omit<ScrcpyInjectTouchControlMessage, "type">) {
90
- return this.write(
91
- ScrcpyInjectTouchControlMessage.serialize(
92
- this.addMessageType(
93
- message,
94
- ScrcpyControlMessageType.InjectTouch
95
- )
52
+ return this._options.serializeInjectTouchControlMessage(
53
+ this._typeValues.fillMessageType(
54
+ message,
55
+ ScrcpyControlMessageType.InjectTouch
96
56
  )
97
57
  );
98
58
  }
@@ -103,52 +63,33 @@ export class ScrcpyControlMessageSerializer {
103
63
  public injectScroll(
104
64
  message: Omit<ScrcpyInjectScrollControlMessage, "type">
105
65
  ) {
106
- const data = this.scrollController.serializeScrollMessage(
107
- this.addMessageType(message, ScrcpyControlMessageType.InjectScroll)
66
+ return this._scrollController.serializeScrollMessage(
67
+ this._typeValues.fillMessageType(
68
+ message,
69
+ ScrcpyControlMessageType.InjectScroll
70
+ )
108
71
  );
109
-
110
- if (!data) {
111
- return;
112
- }
113
-
114
- return this.write(data);
115
72
  }
116
73
 
117
- public async backOrScreenOn(action: AndroidKeyEventAction) {
118
- const buffer = this.options.serializeBackOrScreenOnControlMessage({
74
+ public backOrScreenOn(action: AndroidKeyEventAction) {
75
+ return this._options.serializeBackOrScreenOnControlMessage({
119
76
  action,
120
- type: this.getActualMessageType(
121
- ScrcpyControlMessageType.BackOrScreenOn
122
- ),
77
+ type: this._typeValues.get(ScrcpyControlMessageType.BackOrScreenOn),
123
78
  });
124
-
125
- if (buffer) {
126
- return await this.write(buffer);
127
- }
128
79
  }
129
80
 
130
81
  public setScreenPowerMode(mode: AndroidScreenPowerMode) {
131
- return this.write(
132
- ScrcpySetScreenPowerModeControlMessage.serialize({
133
- mode,
134
- type: this.getActualMessageType(
135
- ScrcpyControlMessageType.SetScreenPowerMode
136
- ),
137
- })
138
- );
82
+ return ScrcpySetScreenPowerModeControlMessage.serialize({
83
+ mode,
84
+ type: this._typeValues.get(
85
+ ScrcpyControlMessageType.SetScreenPowerMode
86
+ ),
87
+ });
139
88
  }
140
89
 
141
90
  public rotateDevice() {
142
- return this.write(
143
- ScrcpyRotateDeviceControlMessage.serialize({
144
- type: this.getActualMessageType(
145
- ScrcpyControlMessageType.RotateDevice
146
- ),
147
- })
148
- );
149
- }
150
-
151
- public close() {
152
- return this.writer.close();
91
+ return ScrcpyRotateDeviceControlMessage.serialize({
92
+ type: this._typeValues.get(ScrcpyControlMessageType.RotateDevice),
93
+ });
153
94
  }
154
95
  }
@@ -1,7 +1,5 @@
1
1
  import Struct, { placeholder } from "@yume-chan/struct";
2
2
 
3
- import { ScrcpyControlMessageType } from "./type.js";
4
-
5
3
  // https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/java/android/view/SurfaceControl.java;l=659;drc=20303e05bf73796124ab70a279cf849b61b97905
6
4
  export enum AndroidScreenPowerMode {
7
5
  Off = 0,
@@ -9,7 +7,7 @@ export enum AndroidScreenPowerMode {
9
7
  }
10
8
 
11
9
  export const ScrcpySetScreenPowerModeControlMessage = new Struct()
12
- .uint8("type", ScrcpyControlMessageType.SetScreenPowerMode as const)
10
+ .uint8("type")
13
11
  .uint8("mode", placeholder<AndroidScreenPowerMode>());
14
12
 
15
13
  export type ScrcpySetScreenPowerModeControlMessage =
@@ -1,5 +1,8 @@
1
1
  // https://github.com/Genymobile/scrcpy/blob/fa5b2a29e983a46b49531def9cf3d80c40c3de37/app/src/control_msg.h#L23
2
2
  // For their message bodies, see https://github.com/Genymobile/scrcpy/blob/5c62f3419d252d10cd8c9cbb7c918b358b81f2d0/app/src/control_msg.c#L92
3
+
4
+ import type { ScrcpyOptions } from "../options/index.js";
5
+
3
6
  // Their IDs change between versions, so always use `options.getControlMessageTypes()`
4
7
  export enum ScrcpyControlMessageType {
5
8
  InjectKeyCode,
@@ -15,3 +18,32 @@ export enum ScrcpyControlMessageType {
15
18
  SetScreenPowerMode,
16
19
  RotateDevice,
17
20
  }
21
+
22
+ /**
23
+ * Scrcpy control message types have different values between versions.
24
+ *
25
+ * This class provides a way to get the actual value for a given type.
26
+ */
27
+ export class ScrcpyControlMessageTypeValue {
28
+ private types: readonly ScrcpyControlMessageType[];
29
+
30
+ public constructor(options: ScrcpyOptions<object>) {
31
+ this.types = options.controlMessageTypes;
32
+ }
33
+
34
+ public get(type: ScrcpyControlMessageType): number {
35
+ const value = this.types.indexOf(type);
36
+ if (value === -1) {
37
+ throw new Error("Not supported");
38
+ }
39
+ return value;
40
+ }
41
+
42
+ public fillMessageType<T extends { type: ScrcpyControlMessageType }>(
43
+ message: Omit<T, "type">,
44
+ type: T["type"]
45
+ ): T {
46
+ (message as T).type = this.get(type);
47
+ return message as T;
48
+ }
49
+ }
@@ -0,0 +1,87 @@
1
+ import type {
2
+ Consumable,
3
+ WritableStreamDefaultWriter,
4
+ } from "@yume-chan/stream-extra";
5
+ import { ConsumableWritableStream } from "@yume-chan/stream-extra";
6
+
7
+ import type { ScrcpyOptions } from "../options/index.js";
8
+
9
+ import type {
10
+ AndroidKeyEventAction,
11
+ ScrcpyInjectKeyCodeControlMessage,
12
+ } from "./inject-keycode.js";
13
+ import type { ScrcpyInjectScrollControlMessage } from "./inject-scroll.js";
14
+ import type { ScrcpyInjectTouchControlMessage } from "./inject-touch.js";
15
+ import { ScrcpyControlMessageSerializer } from "./serializer.js";
16
+ import type { AndroidScreenPowerMode } from "./set-screen-power-mode.js";
17
+
18
+ export class ScrcpyControlMessageWriter {
19
+ private _writer: WritableStreamDefaultWriter<Consumable<Uint8Array>>;
20
+ private _serializer: ScrcpyControlMessageSerializer;
21
+
22
+ public constructor(
23
+ writer: WritableStreamDefaultWriter<Consumable<Uint8Array>>,
24
+ options: ScrcpyOptions<object>
25
+ ) {
26
+ this._writer = writer;
27
+ this._serializer = new ScrcpyControlMessageSerializer(options);
28
+ }
29
+
30
+ private async write(message: Uint8Array) {
31
+ await ConsumableWritableStream.write(this._writer, message);
32
+ }
33
+
34
+ public async injectKeyCode(
35
+ message: Omit<ScrcpyInjectKeyCodeControlMessage, "type">
36
+ ) {
37
+ await this.write(this._serializer.injectKeyCode(message));
38
+ }
39
+
40
+ public async injectText(text: string) {
41
+ await this.write(this._serializer.injectText(text));
42
+ }
43
+
44
+ /**
45
+ * `pressure` is a float value between 0 and 1.
46
+ */
47
+ public async injectTouch(
48
+ message: Omit<ScrcpyInjectTouchControlMessage, "type">
49
+ ) {
50
+ await this.write(this._serializer.injectTouch(message));
51
+ }
52
+
53
+ /**
54
+ * `scrollX` and `scrollY` are float values between 0 and 1.
55
+ */
56
+ public async injectScroll(
57
+ message: Omit<ScrcpyInjectScrollControlMessage, "type">
58
+ ) {
59
+ const data = this._serializer.injectScroll(message);
60
+ if (data) {
61
+ await this.write(data);
62
+ }
63
+ }
64
+
65
+ public async backOrScreenOn(action: AndroidKeyEventAction) {
66
+ const data = this._serializer.backOrScreenOn(action);
67
+ if (data) {
68
+ await this.write(data);
69
+ }
70
+ }
71
+
72
+ public async setScreenPowerMode(mode: AndroidScreenPowerMode) {
73
+ await this.write(this._serializer.setScreenPowerMode(mode));
74
+ }
75
+
76
+ public async rotateDevice() {
77
+ await this.write(this._serializer.rotateDevice());
78
+ }
79
+
80
+ public releaseLock() {
81
+ this._writer.releaseLock();
82
+ }
83
+
84
+ public async close() {
85
+ await this._writer.close();
86
+ }
87
+ }
@@ -1,4 +1,9 @@
1
1
  import { BufferedTransformStream } from "@yume-chan/stream-extra";
2
+ import {
3
+ ExactReadableEndedError,
4
+ StructEmptyError,
5
+ StructNotEnoughDataError,
6
+ } from "@yume-chan/struct";
2
7
 
3
8
  import { ScrcpyAckClipboardDeviceMessage } from "./ack-clipboard.js";
4
9
  import { ScrcpyClipboardDeviceMessage } from "./clipboard.js";
@@ -11,18 +16,33 @@ export type ScrcpyDeviceMessage =
11
16
  export class ScrcpyDeviceMessageDeserializeStream extends BufferedTransformStream<ScrcpyDeviceMessage> {
12
17
  constructor() {
13
18
  super(async (stream) => {
14
- const type = await stream.read(1);
15
- switch (type[0]) {
16
- case ScrcpyDeviceMessageType.Clipboard:
17
- return await ScrcpyClipboardDeviceMessage.deserialize(
18
- stream
19
- );
20
- case ScrcpyDeviceMessageType.AckClipboard:
21
- return await ScrcpyAckClipboardDeviceMessage.deserialize(
22
- stream
23
- );
24
- default:
25
- throw new Error("unknown control message type");
19
+ try {
20
+ const type = await stream.readExactly(1);
21
+ switch (type[0]) {
22
+ case ScrcpyDeviceMessageType.Clipboard:
23
+ return await ScrcpyClipboardDeviceMessage.deserialize(
24
+ stream
25
+ );
26
+ case ScrcpyDeviceMessageType.AckClipboard:
27
+ return await ScrcpyAckClipboardDeviceMessage.deserialize(
28
+ stream
29
+ );
30
+ default:
31
+ throw new Error("Unsupported control message type");
32
+ }
33
+ } catch (e) {
34
+ // Can't read the `type` byte
35
+ if (e instanceof ExactReadableEndedError) {
36
+ throw new StructEmptyError();
37
+ }
38
+
39
+ // Can't read struct body,
40
+ // treat as not enough data because `type` byte is already read
41
+ if (e instanceof StructEmptyError) {
42
+ throw new StructNotEnoughDataError();
43
+ }
44
+
45
+ throw e;
26
46
  }
27
47
  });
28
48
  }
package/src/index.ts CHANGED
@@ -1,5 +1,4 @@
1
- export * from "./adb/index.js";
2
- export * from "./codec.js";
1
+ export * from "./codec/index.js";
3
2
  export * from "./control/index.js";
4
3
  export * from "./device-message/index.js";
5
4
  export * from "./options/index.js";
@@ -1,4 +1,3 @@
1
- import type { AndroidCodecLevel, AndroidCodecProfile } from "../../codec.js";
2
1
  import type { ScrcpyOptionValue } from "../types.js";
3
2
 
4
3
  /**
@@ -6,8 +5,8 @@ import type { ScrcpyOptionValue } from "../types.js";
6
5
  * please file an issue on GitHub.
7
6
  */
8
7
  export interface CodecOptionsInit {
9
- profile: AndroidCodecProfile;
10
- level: AndroidCodecLevel;
8
+ profile: number;
9
+ level: number;
11
10
 
12
11
  iFrameInterval: number;
13
12
  maxBframes: number;
@@ -0,0 +1,33 @@
1
+ import { NumberFieldDefinition, NumberFieldType } from "@yume-chan/struct";
2
+
3
+ export function clamp(value: number, min: number, max: number): number {
4
+ if (value < min) {
5
+ return min;
6
+ }
7
+
8
+ if (value > max) {
9
+ return max;
10
+ }
11
+
12
+ return value;
13
+ }
14
+
15
+ export const ScrcpyFloatToUint16NumberType: NumberFieldType = {
16
+ size: 2,
17
+ signed: false,
18
+ deserialize(array, littleEndian) {
19
+ const value = NumberFieldType.Uint16.deserialize(array, littleEndian);
20
+ // https://github.com/Genymobile/scrcpy/blob/1f138aef41de651668043b32c4effc2d4adbfc44/server/src/main/java/com/genymobile/scrcpy/Binary.java#L22
21
+ return value === 0xffff ? 1 : value / 0x10000;
22
+ },
23
+ serialize(dataView, offset, value, littleEndian) {
24
+ // https://github.com/Genymobile/scrcpy/blob/1f138aef41de651668043b32c4effc2d4adbfc44/app/src/util/binary.h#L51
25
+ value = clamp(value, -1, 1);
26
+ value = value === 1 ? 0xffff : value * 0x10000;
27
+ NumberFieldType.Uint16.serialize(dataView, offset, value, littleEndian);
28
+ },
29
+ };
30
+
31
+ export const ScrcpyFloatToUint16FieldDefinition = new NumberFieldDefinition(
32
+ ScrcpyFloatToUint16NumberType
33
+ );
@@ -1,4 +1,6 @@
1
1
  export * from "./codec-options.js";
2
- export * from "./h264-configuration.js";
2
+ export * from "./float-to-uint16.js";
3
+ export * from "./init.js";
4
+ export * from "./message.js";
3
5
  export * from "./options.js";
4
6
  export * from "./scroll.js";
@@ -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"];