@yume-chan/scrcpy 0.0.22 → 0.0.24

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 (173) hide show
  1. package/CHANGELOG.json +33 -0
  2. package/CHANGELOG.md +18 -1
  3. package/LICENSE +1 -1
  4. package/esm/codec/av1.d.ts +364 -0
  5. package/esm/codec/av1.d.ts.map +1 -1
  6. package/esm/codec/av1.js +591 -0
  7. package/esm/codec/av1.js.map +1 -1
  8. package/esm/codec/nalu.d.ts +0 -9
  9. package/esm/codec/nalu.d.ts.map +1 -1
  10. package/esm/codec/nalu.js +56 -129
  11. package/esm/codec/nalu.js.map +1 -1
  12. package/esm/control/{basic.d.ts → empty.d.ts} +2 -2
  13. package/esm/control/empty.d.ts.map +1 -0
  14. package/esm/control/empty.js +3 -0
  15. package/esm/control/empty.js.map +1 -0
  16. package/esm/control/index.d.ts +1 -1
  17. package/esm/control/index.js +1 -1
  18. package/esm/control/rotate-device.js +2 -2
  19. package/esm/control/serializer.d.ts +2 -0
  20. package/esm/control/serializer.d.ts.map +1 -1
  21. package/esm/control/serializer.js +10 -4
  22. package/esm/control/serializer.js.map +1 -1
  23. package/esm/control/type.js +1 -1
  24. package/esm/control/type.js.map +1 -1
  25. package/esm/control/writer.d.ts +4 -1
  26. package/esm/control/writer.d.ts.map +1 -1
  27. package/esm/control/writer.js +12 -2
  28. package/esm/control/writer.js.map +1 -1
  29. package/esm/index.d.ts +0 -1
  30. package/esm/index.d.ts.map +1 -1
  31. package/esm/index.js +0 -1
  32. package/esm/index.js.map +1 -1
  33. package/esm/options/1_16/float.d.ts +6 -0
  34. package/esm/options/1_16/float.d.ts.map +1 -0
  35. package/esm/options/1_16/{float-to-uint16.js → float.js} +7 -6
  36. package/esm/options/1_16/float.js.map +1 -0
  37. package/esm/options/1_16/index.d.ts +1 -1
  38. package/esm/options/1_16/index.d.ts.map +1 -1
  39. package/esm/options/1_16/index.js +1 -1
  40. package/esm/options/1_16/index.js.map +1 -1
  41. package/esm/options/1_16/message.d.ts +4 -0
  42. package/esm/options/1_16/message.d.ts.map +1 -1
  43. package/esm/options/1_16/message.js +7 -4
  44. package/esm/options/1_16/message.js.map +1 -1
  45. package/esm/options/1_16/options.d.ts +14 -5
  46. package/esm/options/1_16/options.d.ts.map +1 -1
  47. package/esm/options/1_16/options.js +45 -18
  48. package/esm/options/1_16/options.js.map +1 -1
  49. package/esm/options/1_17.d.ts +3 -4
  50. package/esm/options/1_17.d.ts.map +1 -1
  51. package/esm/options/1_17.js +4 -7
  52. package/esm/options/1_17.js.map +1 -1
  53. package/esm/options/1_18.d.ts +3 -4
  54. package/esm/options/1_18.d.ts.map +1 -1
  55. package/esm/options/1_18.js +5 -25
  56. package/esm/options/1_18.js.map +1 -1
  57. package/esm/options/1_21.d.ts +10 -5
  58. package/esm/options/1_21.d.ts.map +1 -1
  59. package/esm/options/1_21.js +30 -7
  60. package/esm/options/1_21.js.map +1 -1
  61. package/esm/options/1_22/options.d.ts +3 -4
  62. package/esm/options/1_22/options.d.ts.map +1 -1
  63. package/esm/options/1_22/options.js +4 -7
  64. package/esm/options/1_22/options.js.map +1 -1
  65. package/esm/options/1_23.d.ts +3 -4
  66. package/esm/options/1_23.d.ts.map +1 -1
  67. package/esm/options/1_23.js +4 -7
  68. package/esm/options/1_23.js.map +1 -1
  69. package/esm/options/1_24.d.ts +3 -4
  70. package/esm/options/1_24.d.ts.map +1 -1
  71. package/esm/options/1_24.js +3 -6
  72. package/esm/options/1_24.js.map +1 -1
  73. package/esm/options/1_25/options.d.ts +2 -3
  74. package/esm/options/1_25/options.d.ts.map +1 -1
  75. package/esm/options/1_25/options.js +3 -6
  76. package/esm/options/1_25/options.js.map +1 -1
  77. package/esm/options/1_25/scroll.d.ts +3 -2
  78. package/esm/options/1_25/scroll.d.ts.map +1 -1
  79. package/esm/options/1_25/scroll.js +8 -7
  80. package/esm/options/1_25/scroll.js.map +1 -1
  81. package/esm/options/2_0.d.ts +11 -9
  82. package/esm/options/2_0.d.ts.map +1 -1
  83. package/esm/options/2_0.js +71 -77
  84. package/esm/options/2_0.js.map +1 -1
  85. package/esm/options/2_1.d.ts +5 -6
  86. package/esm/options/2_1.d.ts.map +1 -1
  87. package/esm/options/2_1.js +3 -6
  88. package/esm/options/2_1.js.map +1 -1
  89. package/esm/options/2_2.d.ts +5 -6
  90. package/esm/options/2_2.d.ts.map +1 -1
  91. package/esm/options/2_2.js +4 -7
  92. package/esm/options/2_2.js.map +1 -1
  93. package/esm/options/2_3.d.ts +59 -0
  94. package/esm/options/2_3.d.ts.map +1 -0
  95. package/esm/options/2_3.js +47 -0
  96. package/esm/options/2_3.js.map +1 -0
  97. package/esm/options/codec.d.ts +1 -0
  98. package/esm/options/codec.d.ts.map +1 -1
  99. package/esm/options/codec.js +1 -0
  100. package/esm/options/codec.js.map +1 -1
  101. package/esm/options/index.d.ts +1 -0
  102. package/esm/options/index.d.ts.map +1 -1
  103. package/esm/options/index.js +1 -0
  104. package/esm/options/index.js.map +1 -1
  105. package/esm/options/latest.d.ts +4 -4
  106. package/esm/options/latest.js +2 -2
  107. package/esm/options/types.d.ts +30 -32
  108. package/esm/options/types.d.ts.map +1 -1
  109. package/esm/options/types.js +77 -26
  110. package/esm/options/types.js.map +1 -1
  111. package/package.json +12 -12
  112. package/src/codec/av1.ts +670 -0
  113. package/src/codec/nalu.ts +67 -154
  114. package/src/control/empty.ts +3 -0
  115. package/src/control/index.ts +1 -1
  116. package/src/control/rotate-device.ts +2 -2
  117. package/src/control/serializer.ts +12 -4
  118. package/src/control/type.ts +1 -1
  119. package/src/control/writer.ts +16 -6
  120. package/src/index.ts +0 -1
  121. package/src/options/1_16/{float-to-uint16.ts → float.ts} +8 -6
  122. package/src/options/1_16/index.ts +1 -1
  123. package/src/options/1_16/message.ts +8 -4
  124. package/src/options/1_16/options.ts +70 -31
  125. package/src/options/1_17.ts +4 -10
  126. package/src/options/1_18.ts +4 -37
  127. package/src/options/1_21.ts +40 -11
  128. package/src/options/1_22/options.ts +4 -10
  129. package/src/options/1_23.ts +4 -10
  130. package/src/options/1_24.ts +3 -9
  131. package/src/options/1_25/options.ts +3 -9
  132. package/src/options/1_25/scroll.ts +10 -11
  133. package/src/options/2_0.ts +92 -95
  134. package/src/options/2_1.ts +3 -9
  135. package/src/options/2_2.ts +4 -10
  136. package/src/options/2_3.ts +70 -0
  137. package/src/options/codec.ts +6 -0
  138. package/src/options/index.ts +1 -0
  139. package/src/options/latest.ts +4 -4
  140. package/src/options/types.ts +89 -98
  141. package/tsconfig.build.tsbuildinfo +1 -1
  142. package/esm/control/basic.d.ts.map +0 -1
  143. package/esm/control/basic.js +0 -3
  144. package/esm/control/basic.js.map +0 -1
  145. package/esm/device-message/ack-clipboard.d.ts +0 -9
  146. package/esm/device-message/ack-clipboard.d.ts.map +0 -1
  147. package/esm/device-message/ack-clipboard.js +0 -6
  148. package/esm/device-message/ack-clipboard.js.map +0 -1
  149. package/esm/device-message/clipboard.d.ts +0 -10
  150. package/esm/device-message/clipboard.d.ts.map +0 -1
  151. package/esm/device-message/clipboard.js +0 -7
  152. package/esm/device-message/clipboard.js.map +0 -1
  153. package/esm/device-message/index.d.ts +0 -5
  154. package/esm/device-message/index.d.ts.map +0 -1
  155. package/esm/device-message/index.js +0 -5
  156. package/esm/device-message/index.js.map +0 -1
  157. package/esm/device-message/stream.d.ts +0 -8
  158. package/esm/device-message/stream.d.ts.map +0 -1
  159. package/esm/device-message/stream.js +0 -35
  160. package/esm/device-message/stream.js.map +0 -1
  161. package/esm/device-message/type.d.ts +0 -5
  162. package/esm/device-message/type.d.ts.map +0 -1
  163. package/esm/device-message/type.js +0 -7
  164. package/esm/device-message/type.js.map +0 -1
  165. package/esm/options/1_16/float-to-uint16.d.ts +0 -5
  166. package/esm/options/1_16/float-to-uint16.d.ts.map +0 -1
  167. package/esm/options/1_16/float-to-uint16.js.map +0 -1
  168. package/src/control/basic.ts +0 -3
  169. package/src/device-message/ack-clipboard.ts +0 -10
  170. package/src/device-message/clipboard.ts +0 -11
  171. package/src/device-message/index.ts +0 -4
  172. package/src/device-message/stream.ts +0 -49
  173. package/src/device-message/type.ts +0 -5
@@ -1,10 +1,11 @@
1
+ import { getUint32BigEndian } from "@yume-chan/no-data-view";
1
2
  import type { ReadableStream } from "@yume-chan/stream-extra";
2
3
  import {
3
4
  BufferedReadableStream,
4
5
  PushReadableStream,
5
6
  } from "@yume-chan/stream-extra";
6
7
  import type { ValueOrPromise } from "@yume-chan/struct";
7
- import Struct, { NumberFieldType, placeholder } from "@yume-chan/struct";
8
+ import Struct, { placeholder } from "@yume-chan/struct";
8
9
 
9
10
  import type {
10
11
  AndroidMotionEventAction,
@@ -13,8 +14,8 @@ import type {
13
14
 
14
15
  import {
15
16
  CodecOptions,
16
- ScrcpyFloatToUint16FieldDefinition,
17
17
  ScrcpyOptions1_16,
18
+ ScrcpyUnsignedFloatFieldDefinition,
18
19
  } from "./1_16/index.js";
19
20
  import { ScrcpyOptions1_21 } from "./1_21.js";
20
21
  import type { ScrcpyOptionsInit1_24 } from "./1_24.js";
@@ -27,7 +28,7 @@ import type {
27
28
  ScrcpyEncoder,
28
29
  ScrcpyOptionValue,
29
30
  } from "./types.js";
30
- import { ScrcpyOptionsBase } from "./types.js";
31
+ import { ScrcpyOptions } from "./types.js";
31
32
 
32
33
  export const ScrcpyInjectTouchControlMessage2_0 = new Struct()
33
34
  .uint8("type")
@@ -37,7 +38,7 @@ export const ScrcpyInjectTouchControlMessage2_0 = new Struct()
37
38
  .uint32("pointerY")
38
39
  .uint16("screenWidth")
39
40
  .uint16("screenHeight")
40
- .field("pressure", ScrcpyFloatToUint16FieldDefinition)
41
+ .field("pressure", ScrcpyUnsignedFloatFieldDefinition)
41
42
  .uint32("actionButton")
42
43
  .uint32("buttons");
43
44
 
@@ -76,20 +77,20 @@ export interface ScrcpyOptionsInit2_0
76
77
  videoCodec?: "h264" | "h265" | "av1";
77
78
  videoBitRate?: number;
78
79
  videoCodecOptions?: CodecOptions;
79
- videoEncoder?: string;
80
+ videoEncoder?: string | undefined;
80
81
 
81
82
  audio?: boolean;
82
- audioCodec?: "opus" | "aac" | "raw";
83
+ audioCodec?: "raw" | "opus" | "aac";
83
84
  audioBitRate?: number;
84
85
  audioCodecOptions?: CodecOptions;
85
- audioEncoder?: string;
86
+ audioEncoder?: string | undefined;
86
87
 
87
88
  listEncoders?: boolean;
88
89
  listDisplays?: boolean;
89
90
  sendCodecMeta?: boolean;
90
91
  }
91
92
 
92
- function omit<T extends object, K extends keyof T>(
93
+ export function omit<T extends object, K extends keyof T>(
93
94
  obj: T,
94
95
  keys: K[],
95
96
  ): Omit<T, K> {
@@ -102,10 +103,59 @@ function omit<T extends object, K extends keyof T>(
102
103
  return result as Omit<T, K>;
103
104
  }
104
105
 
105
- export class ScrcpyOptions2_0 extends ScrcpyOptionsBase<
106
- ScrcpyOptionsInit2_0,
107
- ScrcpyOptions1_25
108
- > {
106
+ export class ScrcpyOptions2_0 extends ScrcpyOptions<ScrcpyOptionsInit2_0> {
107
+ static async parseAudioMetadata(
108
+ stream: ReadableStream<Uint8Array>,
109
+ sendCodecMeta: boolean,
110
+ mapMetadata: (value: number) => ScrcpyAudioCodec,
111
+ getOptionCodec: () => ScrcpyAudioCodec,
112
+ ): Promise<ScrcpyAudioStreamMetadata> {
113
+ const buffered = new BufferedReadableStream(stream);
114
+
115
+ const buffer = await buffered.readExactly(4);
116
+ // Treat it as a 32-bit number for simpler comparisons
117
+ const codecMetadataValue = getUint32BigEndian(buffer, 0);
118
+ // Server will send `0x00_00_00_00` and `0x00_00_00_01` even if `sendCodecMeta` is false
119
+ switch (codecMetadataValue) {
120
+ case 0x00_00_00_00:
121
+ return {
122
+ type: "disabled",
123
+ };
124
+ case 0x00_00_00_01:
125
+ return {
126
+ type: "errored",
127
+ };
128
+ }
129
+
130
+ if (sendCodecMeta) {
131
+ return {
132
+ type: "success",
133
+ codec: mapMetadata(codecMetadataValue),
134
+ stream: buffered.release(),
135
+ };
136
+ }
137
+
138
+ return {
139
+ type: "success",
140
+ // Infer codec from `audioCodec` option
141
+ codec: getOptionCodec(),
142
+ stream: new PushReadableStream<Uint8Array>(async (controller) => {
143
+ // Put the first 4 bytes back
144
+ await controller.enqueue(buffer);
145
+
146
+ const stream = buffered.release();
147
+ const reader = stream.getReader();
148
+ while (true) {
149
+ const { done, value } = await reader.read();
150
+ if (done) {
151
+ break;
152
+ }
153
+ await controller.enqueue(value);
154
+ }
155
+ }),
156
+ };
157
+ }
158
+
109
159
  static readonly DEFAULTS = {
110
160
  ...omit(ScrcpyOptions1_24.DEFAULTS, [
111
161
  "bitRate",
@@ -117,13 +167,13 @@ export class ScrcpyOptions2_0 extends ScrcpyOptionsBase<
117
167
  videoCodec: "h264",
118
168
  videoBitRate: 8000000,
119
169
  videoCodecOptions: new CodecOptions(),
120
- videoEncoder: "",
170
+ videoEncoder: undefined,
121
171
 
122
172
  audio: true,
123
173
  audioCodec: "opus",
124
174
  audioBitRate: 128000,
125
175
  audioCodecOptions: new CodecOptions(),
126
- audioEncoder: "",
176
+ audioEncoder: undefined,
127
177
 
128
178
  listEncoders: false,
129
179
  listDisplays: false,
@@ -135,10 +185,7 @@ export class ScrcpyOptions2_0 extends ScrcpyOptionsBase<
135
185
  }
136
186
 
137
187
  constructor(init: ScrcpyOptionsInit2_0) {
138
- super(new ScrcpyOptions1_25(init), {
139
- ...ScrcpyOptions2_0.DEFAULTS,
140
- ...init,
141
- });
188
+ super(ScrcpyOptions1_25, init, ScrcpyOptions2_0.DEFAULTS);
142
189
  }
143
190
 
144
191
  override serialize(): string[] {
@@ -155,7 +202,7 @@ export class ScrcpyOptions2_0 extends ScrcpyOptionsBase<
155
202
 
156
203
  override parseEncoder(line: string): ScrcpyEncoder | undefined {
157
204
  let match = line.match(
158
- /\s+--video-codec=(.*)\s+--video-encoder='(.*)'/,
205
+ /^\s+--video-codec=(\S+)\s+--video-encoder='([^']+)'$/,
159
206
  );
160
207
  if (match) {
161
208
  return {
@@ -165,7 +212,9 @@ export class ScrcpyOptions2_0 extends ScrcpyOptionsBase<
165
212
  };
166
213
  }
167
214
 
168
- match = line.match(/\s+--audio-codec=(.*)\s+--audio-encoder='(.*)'/);
215
+ match = line.match(
216
+ /^\s+--audio-codec=(\S+)\s+--audio-encoder='([^']+)'$/,
217
+ );
169
218
  if (match) {
170
219
  return {
171
220
  type: "audio",
@@ -178,7 +227,7 @@ export class ScrcpyOptions2_0 extends ScrcpyOptionsBase<
178
227
  }
179
228
 
180
229
  override parseDisplay(line: string): ScrcpyDisplay | undefined {
181
- const match = line.match(/\s+--display=(\d+)\s+\((.*?)\)/);
230
+ const match = line.match(/^\s+--display=(\d+)\s+\(([^)]+)\)$/);
182
231
  if (match) {
183
232
  const display: ScrcpyDisplay = {
184
233
  id: Number.parseInt(match[1]!, 10),
@@ -252,86 +301,34 @@ export class ScrcpyOptions2_0 extends ScrcpyOptionsBase<
252
301
  override parseAudioStreamMetadata(
253
302
  stream: ReadableStream<Uint8Array>,
254
303
  ): ValueOrPromise<ScrcpyAudioStreamMetadata> {
255
- return (async (): Promise<ScrcpyAudioStreamMetadata> => {
256
- const buffered = new BufferedReadableStream(stream);
257
- const buffer = await buffered.readExactly(
258
- NumberFieldType.Uint32.size,
259
- );
260
-
261
- const codecMetadataValue = NumberFieldType.Uint32.deserialize(
262
- buffer,
263
- false,
264
- );
265
- // Server will send `0x00_00_00_00` and `0x00_00_00_01` even if `sendCodecMeta` is false
266
- switch (codecMetadataValue) {
267
- case 0x00_00_00_00:
268
- return {
269
- type: "disabled",
270
- };
271
- case 0x00_00_00_01:
272
- return {
273
- type: "errored",
274
- };
275
- }
276
-
277
- if (this.value.sendCodecMeta) {
278
- let codec: ScrcpyAudioCodec;
279
- switch (codecMetadataValue) {
304
+ return ScrcpyOptions2_0.parseAudioMetadata(
305
+ stream,
306
+ this.value.sendCodecMeta,
307
+ (value) => {
308
+ switch (value) {
309
+ case ScrcpyAudioCodec.RAW.metadataValue:
310
+ return ScrcpyAudioCodec.RAW;
280
311
  case ScrcpyAudioCodec.OPUS.metadataValue:
281
- codec = ScrcpyAudioCodec.OPUS;
282
- break;
312
+ return ScrcpyAudioCodec.OPUS;
283
313
  case ScrcpyAudioCodec.AAC.metadataValue:
284
- codec = ScrcpyAudioCodec.AAC;
285
- break;
286
- case ScrcpyAudioCodec.RAW.metadataValue:
287
- codec = ScrcpyAudioCodec.RAW;
288
- break;
314
+ return ScrcpyAudioCodec.AAC;
289
315
  default:
290
316
  throw new Error(
291
- `Unknown audio codec metadata value: ${codecMetadataValue}`,
317
+ `Unknown audio codec metadata value: ${value}`,
292
318
  );
293
319
  }
294
- return {
295
- type: "success",
296
- codec,
297
- stream: buffered.release(),
298
- };
299
- }
300
-
301
- // Infer codec from `audioCodec` option
302
- let codec: ScrcpyAudioCodec;
303
- switch (this.value.audioCodec) {
304
- case "opus":
305
- codec = ScrcpyAudioCodec.OPUS;
306
- break;
307
- case "aac":
308
- codec = ScrcpyAudioCodec.AAC;
309
- break;
310
- case "raw":
311
- codec = ScrcpyAudioCodec.RAW;
312
- break;
313
- }
314
- return {
315
- type: "success",
316
- codec,
317
- stream: new PushReadableStream<Uint8Array>(
318
- async (controller) => {
319
- // Put the first 4 bytes back
320
- await controller.enqueue(buffer);
321
-
322
- const stream = buffered.release();
323
- const reader = stream.getReader();
324
- while (true) {
325
- const { done, value } = await reader.read();
326
- if (done) {
327
- break;
328
- }
329
- await controller.enqueue(value);
330
- }
331
- },
332
- ),
333
- };
334
- })();
320
+ },
321
+ () => {
322
+ switch (this.value.audioCodec) {
323
+ case "raw":
324
+ return ScrcpyAudioCodec.RAW;
325
+ case "opus":
326
+ return ScrcpyAudioCodec.OPUS;
327
+ case "aac":
328
+ return ScrcpyAudioCodec.AAC;
329
+ }
330
+ },
331
+ );
335
332
  }
336
333
 
337
334
  override serializeInjectTouchControlMessage(
@@ -1,17 +1,14 @@
1
1
  import { ScrcpyOptions1_21 } from "./1_21.js";
2
2
  import type { ScrcpyOptionsInit2_0 } from "./2_0.js";
3
3
  import { ScrcpyOptions2_0 } from "./2_0.js";
4
- import { ScrcpyOptionsBase } from "./types.js";
4
+ import { ScrcpyOptions } from "./types.js";
5
5
 
6
6
  export interface ScrcpyOptionsInit2_1 extends ScrcpyOptionsInit2_0 {
7
7
  video?: boolean;
8
8
  audioSource?: "output" | "mic";
9
9
  }
10
10
 
11
- export class ScrcpyOptions2_1 extends ScrcpyOptionsBase<
12
- ScrcpyOptionsInit2_1,
13
- ScrcpyOptions2_0
14
- > {
11
+ export class ScrcpyOptions2_1 extends ScrcpyOptions<ScrcpyOptionsInit2_1> {
15
12
  static readonly DEFAULTS = {
16
13
  ...ScrcpyOptions2_0.DEFAULTS,
17
14
  video: true,
@@ -23,10 +20,7 @@ export class ScrcpyOptions2_1 extends ScrcpyOptionsBase<
23
20
  }
24
21
 
25
22
  constructor(init: ScrcpyOptionsInit2_1) {
26
- super(new ScrcpyOptions2_0(init), {
27
- ...ScrcpyOptions2_1.DEFAULTS,
28
- ...init,
29
- });
23
+ super(ScrcpyOptions2_0, init, ScrcpyOptions2_1.DEFAULTS);
30
24
  }
31
25
 
32
26
  override serialize(): string[] {
@@ -2,7 +2,7 @@ import { ScrcpyOptions1_21 } from "./1_21.js";
2
2
  import type { ScrcpyOptionsInit2_1 } from "./2_1.js";
3
3
  import { ScrcpyOptions2_1 } from "./2_1.js";
4
4
  import type { ScrcpyDisplay } from "./types.js";
5
- import { ScrcpyOptionsBase } from "./types.js";
5
+ import { ScrcpyOptions } from "./types.js";
6
6
 
7
7
  export interface ScrcpyOptionsInit2_2
8
8
  extends Omit<ScrcpyOptionsInit2_1, "display"> {
@@ -19,10 +19,7 @@ export interface ScrcpyOptionsInit2_2
19
19
  listCameraSizes?: boolean;
20
20
  }
21
21
 
22
- export class ScrcpyOptions2_2 extends ScrcpyOptionsBase<
23
- ScrcpyOptionsInit2_2,
24
- ScrcpyOptions2_1
25
- > {
22
+ export class ScrcpyOptions2_2 extends ScrcpyOptions<ScrcpyOptionsInit2_2> {
26
23
  static readonly DEFAULTS = {
27
24
  ...ScrcpyOptions2_1.DEFAULTS,
28
25
  videoSource: "display",
@@ -42,14 +39,11 @@ export class ScrcpyOptions2_2 extends ScrcpyOptionsBase<
42
39
  }
43
40
 
44
41
  constructor(init: ScrcpyOptionsInit2_2) {
45
- super(new ScrcpyOptions2_1(init), {
46
- ...ScrcpyOptions2_2.DEFAULTS,
47
- ...init,
48
- });
42
+ super(ScrcpyOptions2_1, init, ScrcpyOptions2_2.DEFAULTS);
49
43
  }
50
44
 
51
45
  override parseDisplay(line: string): ScrcpyDisplay | undefined {
52
- const match = line.match(/\s+--display-id=(\d+)\s+\((.*?)\)/);
46
+ const match = line.match(/^\s+--display-id=(\d+)\s+\(([^)]+)\)$/);
53
47
  if (match) {
54
48
  const display: ScrcpyDisplay = {
55
49
  id: Number.parseInt(match[1]!, 10),
@@ -0,0 +1,70 @@
1
+ import type { ReadableStream } from "@yume-chan/stream-extra";
2
+ import type { ValueOrPromise } from "@yume-chan/struct";
3
+
4
+ import { ScrcpyOptions1_21 } from "./1_21.js";
5
+ import { ScrcpyOptions2_0 } from "./2_0.js";
6
+ import type { ScrcpyOptionsInit2_2 } from "./2_2.js";
7
+ import { ScrcpyOptions2_2 } from "./2_2.js";
8
+ import type { ScrcpyAudioStreamMetadata } from "./codec.js";
9
+ import { ScrcpyAudioCodec } from "./codec.js";
10
+ import { ScrcpyOptions } from "./types.js";
11
+
12
+ export interface ScrcpyOptionsInit2_3
13
+ extends Omit<ScrcpyOptionsInit2_2, "audioCodec"> {
14
+ audioCodec?: "raw" | "opus" | "aac" | "flac";
15
+ }
16
+
17
+ export class ScrcpyOptions2_3 extends ScrcpyOptions<ScrcpyOptionsInit2_3> {
18
+ static readonly DEFAULTS = {
19
+ ...ScrcpyOptions2_2.DEFAULTS,
20
+ } as const satisfies Required<ScrcpyOptionsInit2_3>;
21
+
22
+ override get defaults(): Required<ScrcpyOptionsInit2_3> {
23
+ return ScrcpyOptions2_3.DEFAULTS;
24
+ }
25
+
26
+ constructor(init: ScrcpyOptionsInit2_3) {
27
+ super(ScrcpyOptions2_2, init, ScrcpyOptions2_3.DEFAULTS);
28
+ }
29
+
30
+ override serialize(): string[] {
31
+ return ScrcpyOptions1_21.serialize(this.value, this.defaults);
32
+ }
33
+
34
+ override parseAudioStreamMetadata(
35
+ stream: ReadableStream<Uint8Array>,
36
+ ): ValueOrPromise<ScrcpyAudioStreamMetadata> {
37
+ return ScrcpyOptions2_0.parseAudioMetadata(
38
+ stream,
39
+ this.value.sendCodecMeta,
40
+ (value) => {
41
+ switch (value) {
42
+ case ScrcpyAudioCodec.RAW.metadataValue:
43
+ return ScrcpyAudioCodec.RAW;
44
+ case ScrcpyAudioCodec.OPUS.metadataValue:
45
+ return ScrcpyAudioCodec.OPUS;
46
+ case ScrcpyAudioCodec.AAC.metadataValue:
47
+ return ScrcpyAudioCodec.AAC;
48
+ case ScrcpyAudioCodec.FLAC.metadataValue:
49
+ return ScrcpyAudioCodec.FLAC;
50
+ default:
51
+ throw new Error(
52
+ `Unknown audio codec metadata value: ${value}`,
53
+ );
54
+ }
55
+ },
56
+ () => {
57
+ switch (this.value.audioCodec) {
58
+ case "raw":
59
+ return ScrcpyAudioCodec.RAW;
60
+ case "opus":
61
+ return ScrcpyAudioCodec.OPUS;
62
+ case "aac":
63
+ return ScrcpyAudioCodec.AAC;
64
+ case "flac":
65
+ return ScrcpyAudioCodec.FLAC;
66
+ }
67
+ },
68
+ );
69
+ }
70
+ }
@@ -33,6 +33,12 @@ export class ScrcpyAudioCodec implements ScrcpyOptionValue {
33
33
  "audio/aac",
34
34
  "mp4a.66",
35
35
  );
36
+ static readonly FLAC = new ScrcpyAudioCodec(
37
+ "flac",
38
+ 0x66_6c_61_63,
39
+ "audio/flac",
40
+ "flac",
41
+ );
36
42
  static readonly RAW = new ScrcpyAudioCodec(
37
43
  "raw",
38
44
  0x00_72_61_77,
@@ -9,6 +9,7 @@ export * from "./1_25/index.js";
9
9
  export * from "./2_0.js";
10
10
  export * from "./2_1.js";
11
11
  export * from "./2_2.js";
12
+ export * from "./2_3.js";
12
13
  export * from "./codec.js";
13
14
  export * from "./latest.js";
14
15
  export * from "./types.js";
@@ -1,6 +1,6 @@
1
1
  import { ScrcpyLogLevel1_18, ScrcpyVideoOrientation1_18 } from "./1_18.js";
2
- import type { ScrcpyOptionsInit2_2 } from "./2_2.js";
3
- import { ScrcpyOptions2_2 } from "./2_2.js";
2
+ import type { ScrcpyOptionsInit2_3 } from "./2_3.js";
3
+ import { ScrcpyOptions2_3 } from "./2_3.js";
4
4
 
5
5
  export const ScrcpyLogLevel = ScrcpyLogLevel1_18;
6
6
  export type ScrcpyLogLevel = ScrcpyLogLevel1_18;
@@ -8,5 +8,5 @@ export type ScrcpyLogLevel = ScrcpyLogLevel1_18;
8
8
  export const ScrcpyVideoOrientation = ScrcpyVideoOrientation1_18;
9
9
  export type ScrcpyVideoOrientation = ScrcpyVideoOrientation1_18;
10
10
 
11
- export type ScrcpyOptionsInitLatest = ScrcpyOptionsInit2_2;
12
- export class ScrcpyOptionsLatest extends ScrcpyOptions2_2 {}
11
+ export type ScrcpyOptionsInitLatest = ScrcpyOptionsInit2_3;
12
+ export class ScrcpyOptionsLatest extends ScrcpyOptions2_3 {}