@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.
- package/CHANGELOG.json +15 -0
- package/CHANGELOG.md +9 -1
- package/README.md +105 -181
- package/esm/codec/h264.d.ts +1 -21
- package/esm/codec/h264.d.ts.map +1 -1
- package/esm/codec/h264.js +13 -234
- package/esm/codec/h264.js.map +1 -1
- package/esm/codec/h265.d.ts +454 -0
- package/esm/codec/h265.d.ts.map +1 -1
- package/esm/codec/h265.js +1060 -0
- package/esm/codec/h265.js.map +1 -1
- package/esm/codec/index.d.ts +1 -0
- package/esm/codec/index.d.ts.map +1 -1
- package/esm/codec/index.js +1 -0
- package/esm/codec/index.js.map +1 -1
- package/esm/codec/nalu.d.ts +44 -0
- package/esm/codec/nalu.d.ts.map +1 -0
- package/esm/codec/nalu.js +310 -0
- package/esm/codec/nalu.js.map +1 -0
- package/esm/control/back-or-screen-on.d.ts +1 -1
- package/esm/control/back-or-screen-on.d.ts.map +1 -1
- package/esm/control/index.d.ts +2 -0
- package/esm/control/index.d.ts.map +1 -1
- package/esm/control/index.js +2 -0
- package/esm/control/index.js.map +1 -1
- package/esm/control/inject-keycode.d.ts +1 -2
- package/esm/control/inject-keycode.d.ts.map +1 -1
- package/esm/control/inject-keycode.js +1 -2
- package/esm/control/inject-keycode.js.map +1 -1
- package/esm/control/inject-text.d.ts +1 -2
- package/esm/control/inject-text.d.ts.map +1 -1
- package/esm/control/inject-text.js +1 -2
- package/esm/control/inject-text.js.map +1 -1
- package/esm/control/inject-touch.d.ts +15 -20
- package/esm/control/inject-touch.d.ts.map +1 -1
- package/esm/control/inject-touch.js +14 -41
- package/esm/control/inject-touch.js.map +1 -1
- package/esm/control/rotate-device.d.ts +2 -4
- package/esm/control/rotate-device.d.ts.map +1 -1
- package/esm/control/rotate-device.js +2 -3
- package/esm/control/rotate-device.js.map +1 -1
- package/esm/control/serializer.d.ts +13 -23
- package/esm/control/serializer.d.ts.map +1 -1
- package/esm/control/serializer.js +23 -52
- package/esm/control/serializer.js.map +1 -1
- package/esm/control/set-screen-power-mode.d.ts +1 -2
- package/esm/control/set-screen-power-mode.d.ts.map +1 -1
- package/esm/control/set-screen-power-mode.js +1 -2
- package/esm/control/set-screen-power-mode.js.map +1 -1
- package/esm/control/type.d.ts +14 -0
- package/esm/control/type.d.ts.map +1 -1
- package/esm/control/type.js +22 -0
- package/esm/control/type.js.map +1 -1
- package/esm/control/writer.d.ts +28 -0
- package/esm/control/writer.d.ts.map +1 -0
- package/esm/control/writer.js +53 -0
- package/esm/control/writer.js.map +1 -0
- package/esm/device-message/stream.d.ts.map +1 -1
- package/esm/device-message/stream.js +23 -8
- package/esm/device-message/stream.js.map +1 -1
- package/esm/index.d.ts +1 -2
- package/esm/index.d.ts.map +1 -1
- package/esm/index.js +1 -2
- package/esm/index.js.map +1 -1
- package/esm/options/1_16/codec-options.d.ts +2 -3
- package/esm/options/1_16/codec-options.d.ts.map +1 -1
- package/esm/options/1_16/codec-options.js.map +1 -1
- package/esm/options/1_16/index.d.ts +3 -1
- package/esm/options/1_16/index.d.ts.map +1 -1
- package/esm/options/1_16/index.js +3 -1
- package/esm/options/1_16/index.js.map +1 -1
- package/esm/options/1_16/options.d.ts +42 -96
- package/esm/options/1_16/options.d.ts.map +1 -1
- package/esm/options/1_16/options.js +106 -143
- package/esm/options/1_16/options.js.map +1 -1
- package/esm/options/1_16/scroll.d.ts +1 -2
- package/esm/options/1_16/scroll.d.ts.map +1 -1
- package/esm/options/1_16/scroll.js +1 -2
- package/esm/options/1_16/scroll.js.map +1 -1
- package/esm/options/1_17.d.ts +1 -0
- package/esm/options/1_17.d.ts.map +1 -1
- package/esm/options/1_17.js +7 -1
- package/esm/options/1_17.js.map +1 -1
- package/esm/options/1_18.d.ts +49 -11
- package/esm/options/1_18.d.ts.map +1 -1
- package/esm/options/1_18.js +65 -32
- package/esm/options/1_18.js.map +1 -1
- package/esm/options/1_21.d.ts +26 -7
- package/esm/options/1_21.d.ts.map +1 -1
- package/esm/options/1_21.js +35 -20
- package/esm/options/1_21.js.map +1 -1
- package/esm/options/1_22/index.d.ts +1 -0
- package/esm/options/1_22/index.d.ts.map +1 -1
- package/esm/options/1_22/index.js +1 -0
- package/esm/options/1_22/index.js.map +1 -1
- package/esm/options/1_22/options.d.ts +32 -26
- package/esm/options/1_22/options.d.ts.map +1 -1
- package/esm/options/1_22/options.js +27 -16
- package/esm/options/1_22/options.js.map +1 -1
- package/esm/options/1_22/scroll.d.ts +1 -1
- package/esm/options/1_22/scroll.js +1 -1
- package/esm/options/1_23.d.ts +32 -8
- package/esm/options/1_23.d.ts.map +1 -1
- package/esm/options/1_23.js +24 -14
- package/esm/options/1_23.js.map +1 -1
- package/esm/options/1_24.d.ts +29 -4
- package/esm/options/1_24.d.ts.map +1 -1
- package/esm/options/1_24.js +17 -7
- package/esm/options/1_24.js.map +1 -1
- package/esm/options/1_25/options.d.ts +6 -2
- package/esm/options/1_25/options.d.ts.map +1 -1
- package/esm/options/1_25/options.js +16 -2
- package/esm/options/1_25/options.js.map +1 -1
- package/esm/options/1_25/scroll.d.ts.map +1 -1
- package/esm/options/1_25/scroll.js +2 -1
- package/esm/options/1_25/scroll.js.map +1 -1
- package/esm/options/2_0.d.ts +12 -8
- package/esm/options/2_0.d.ts.map +1 -1
- package/esm/options/2_0.js +80 -11
- package/esm/options/2_0.js.map +1 -1
- package/esm/options/codec.d.ts +4 -4
- package/esm/options/codec.d.ts.map +1 -1
- package/esm/options/codec.js +3 -3
- package/esm/options/codec.js.map +1 -1
- package/esm/options/index.d.ts +4 -0
- package/esm/options/index.d.ts.map +1 -1
- package/esm/options/index.js +4 -0
- package/esm/options/index.js.map +1 -1
- package/esm/options/types.d.ts +73 -33
- package/esm/options/types.d.ts.map +1 -1
- package/esm/options/types.js +52 -0
- package/esm/options/types.js.map +1 -1
- package/package.json +7 -14
- package/src/codec/av1.ts +33 -0
- package/src/codec/h264.ts +317 -0
- package/src/codec/h265.ts +1375 -0
- package/src/codec/index.ts +4 -0
- package/src/codec/nalu.ts +373 -0
- package/src/control/back-or-screen-on.ts +1 -1
- package/{esm/control/simple.js → src/control/basic.ts} +3 -3
- package/src/control/index.ts +2 -0
- package/src/control/inject-keycode.ts +1 -3
- package/src/control/inject-text.ts +1 -3
- package/src/control/inject-touch.ts +16 -55
- package/src/control/rotate-device.ts +2 -7
- package/src/control/serializer.ts +42 -101
- package/src/control/set-screen-power-mode.ts +1 -3
- package/src/control/type.ts +32 -0
- package/src/control/writer.ts +87 -0
- package/src/device-message/stream.ts +32 -12
- package/src/index.ts +1 -2
- package/src/options/1_16/codec-options.ts +2 -3
- package/src/options/1_16/float-to-uint16.ts +33 -0
- package/src/options/1_16/index.ts +3 -1
- package/src/options/1_16/init.ts +80 -0
- package/src/options/1_16/message.ts +55 -0
- package/src/options/1_16/options.ts +146 -255
- package/src/options/1_16/scroll.ts +1 -2
- package/src/options/1_17.ts +66 -0
- package/src/options/1_18.ts +101 -37
- package/src/options/1_21.ts +47 -25
- package/src/options/1_22/index.ts +1 -0
- package/src/options/1_22/init.ts +19 -0
- package/src/options/1_22/options.ts +38 -45
- package/src/options/1_22/scroll.ts +1 -1
- package/src/options/1_23.ts +33 -21
- package/src/options/1_24.ts +23 -11
- package/src/options/1_25/options.ts +22 -4
- package/src/options/1_25/scroll.ts +2 -1
- package/src/options/2_0.ts +342 -0
- package/src/options/codec.ts +98 -0
- package/src/options/index.ts +4 -0
- package/src/options/latest.ts +14 -0
- package/src/options/types.ts +152 -42
- package/tsconfig.build.json +9 -1
- package/tsconfig.build.tsbuildinfo +1 -1
- package/esm/adb/client.d.ts +0 -41
- package/esm/adb/client.d.ts.map +0 -1
- package/esm/adb/client.js +0 -224
- package/esm/adb/client.js.map +0 -1
- package/esm/adb/connection.d.ts +0 -49
- package/esm/adb/connection.d.ts.map +0 -1
- package/esm/adb/connection.js +0 -122
- package/esm/adb/connection.js.map +0 -1
- package/esm/adb/index.d.ts +0 -4
- package/esm/adb/index.d.ts.map +0 -1
- package/esm/adb/index.js +0 -4
- package/esm/adb/index.js.map +0 -1
- package/esm/adb/options/1_16.d.ts +0 -8
- package/esm/adb/options/1_16.d.ts.map +0 -1
- package/esm/adb/options/1_16.js +0 -20
- package/esm/adb/options/1_16.js.map +0 -1
- package/esm/adb/options/1_22.d.ts +0 -8
- package/esm/adb/options/1_22.d.ts.map +0 -1
- package/esm/adb/options/1_22.js +0 -17
- package/esm/adb/options/1_22.js.map +0 -1
- package/esm/adb/options/1_26.d.ts +0 -9
- package/esm/adb/options/1_26.d.ts.map +0 -1
- package/esm/adb/options/1_26.js +0 -11
- package/esm/adb/options/1_26.js.map +0 -1
- package/esm/adb/options/2_0.d.ts +0 -8
- package/esm/adb/options/2_0.d.ts.map +0 -1
- package/esm/adb/options/2_0.js +0 -13
- package/esm/adb/options/2_0.js.map +0 -1
- package/esm/adb/options/index.d.ts +0 -4
- package/esm/adb/options/index.d.ts.map +0 -1
- package/esm/adb/options/index.js +0 -4
- package/esm/adb/options/index.js.map +0 -1
- package/esm/adb/options/types.d.ts +0 -24
- package/esm/adb/options/types.d.ts.map +0 -1
- package/esm/adb/options/types.js +0 -37
- package/esm/adb/options/types.js.map +0 -1
- package/esm/codec.d.ts +0 -34
- package/esm/codec.d.ts.map +0 -1
- package/esm/codec.js +0 -37
- package/esm/codec.js.map +0 -1
- package/esm/control/simple.d.ts +0 -5
- package/esm/control/simple.d.ts.map +0 -1
- package/esm/control/simple.js.map +0 -1
- package/esm/decoder.d.ts +0 -2
- package/esm/decoder.d.ts.map +0 -1
- package/esm/decoder.js +0 -2
- package/esm/decoder.js.map +0 -1
- package/esm/options/1.17.d.ts +0 -3
- package/esm/options/1.17.d.ts.map +0 -1
- package/esm/options/1.17.js +0 -2
- package/esm/options/1.17.js.map +0 -1
- package/esm/options/1_16/h264-configuration.d.ts +0 -49
- package/esm/options/1_16/h264-configuration.d.ts.map +0 -1
- package/esm/options/1_16/h264-configuration.js +0 -414
- package/esm/options/1_16/h264-configuration.js.map +0 -1
- package/esm/options/1_16/sps.d.ts +0 -22
- package/esm/options/1_16/sps.d.ts.map +0 -1
- package/esm/options/1_16/sps.js +0 -263
- package/esm/options/1_16/sps.js.map +0 -1
- package/esm/options/1_26.d.ts +0 -57
- package/esm/options/1_26.d.ts.map +0 -1
- package/esm/options/1_26.js +0 -67
- package/esm/options/1_26.js.map +0 -1
- package/esm/options/2.d.ts +0 -57
- package/esm/options/2.d.ts.map +0 -1
- package/esm/options/2.js +0 -67
- package/esm/options/2.js.map +0 -1
- package/src/adb/client.ts +0 -329
- package/src/adb/connection.ts +0 -209
- package/src/adb/index.ts +0 -3
- package/src/adb/options/1_16.ts +0 -32
- package/src/adb/options/1_22.ts +0 -26
- package/src/adb/options/index.ts +0 -3
- package/src/adb/options/types.ts +0 -75
- package/src/codec.ts +0 -35
- package/src/options/1_16/h264-configuration.ts +0 -485
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
import type { ReadableStream } from "@yume-chan/stream-extra";
|
|
2
|
+
import {
|
|
3
|
+
BufferedReadableStream,
|
|
4
|
+
PushReadableStream,
|
|
5
|
+
} from "@yume-chan/stream-extra";
|
|
6
|
+
import type { ValueOrPromise } from "@yume-chan/struct";
|
|
7
|
+
import Struct, { NumberFieldType, placeholder } from "@yume-chan/struct";
|
|
8
|
+
|
|
9
|
+
import type {
|
|
10
|
+
AndroidMotionEventAction,
|
|
11
|
+
ScrcpyInjectTouchControlMessage,
|
|
12
|
+
} from "../control/index.js";
|
|
13
|
+
|
|
14
|
+
import {
|
|
15
|
+
CodecOptions,
|
|
16
|
+
ScrcpyFloatToUint16FieldDefinition,
|
|
17
|
+
ScrcpyOptions1_16,
|
|
18
|
+
} from "./1_16/index.js";
|
|
19
|
+
import { ScrcpyOptions1_21 } from "./1_21.js";
|
|
20
|
+
import type { ScrcpyOptionsInit1_24 } from "./1_24.js";
|
|
21
|
+
import { ScrcpyOptions1_24 } from "./1_24.js";
|
|
22
|
+
import { ScrcpyOptions1_25 } from "./1_25/index.js";
|
|
23
|
+
import type { ScrcpyAudioStreamMetadata, ScrcpyVideoStream } from "./codec.js";
|
|
24
|
+
import { ScrcpyAudioCodec, ScrcpyVideoCodecId } from "./codec.js";
|
|
25
|
+
import type {
|
|
26
|
+
ScrcpyDisplay,
|
|
27
|
+
ScrcpyEncoder,
|
|
28
|
+
ScrcpyOptionValue,
|
|
29
|
+
} from "./types.js";
|
|
30
|
+
import { ScrcpyOptionsBase } from "./types.js";
|
|
31
|
+
|
|
32
|
+
export const ScrcpyInjectTouchControlMessage2_0 = new Struct()
|
|
33
|
+
.uint8("type")
|
|
34
|
+
.uint8("action", placeholder<AndroidMotionEventAction>())
|
|
35
|
+
.uint64("pointerId")
|
|
36
|
+
.uint32("pointerX")
|
|
37
|
+
.uint32("pointerY")
|
|
38
|
+
.uint16("screenWidth")
|
|
39
|
+
.uint16("screenHeight")
|
|
40
|
+
.field("pressure", ScrcpyFloatToUint16FieldDefinition)
|
|
41
|
+
.uint32("actionButton")
|
|
42
|
+
.uint32("buttons");
|
|
43
|
+
|
|
44
|
+
export type ScrcpyInjectTouchControlMessage2_0 =
|
|
45
|
+
(typeof ScrcpyInjectTouchControlMessage2_0)["TInit"];
|
|
46
|
+
|
|
47
|
+
export class ScrcpyInstanceId implements ScrcpyOptionValue {
|
|
48
|
+
public static readonly NONE = new ScrcpyInstanceId(-1);
|
|
49
|
+
|
|
50
|
+
public static random(): ScrcpyInstanceId {
|
|
51
|
+
// A random 31-bit unsigned integer
|
|
52
|
+
return new ScrcpyInstanceId((Math.random() * 0x80000000) | 0);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
public value: number;
|
|
56
|
+
|
|
57
|
+
public constructor(value: number) {
|
|
58
|
+
this.value = value;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
public toOptionValue(): string | undefined {
|
|
62
|
+
if (this.value < 0) {
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
return this.value.toString(16);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface ScrcpyOptionsInit2_0
|
|
70
|
+
extends Omit<
|
|
71
|
+
ScrcpyOptionsInit1_24,
|
|
72
|
+
"bitRate" | "codecOptions" | "encoderName"
|
|
73
|
+
> {
|
|
74
|
+
scid?: ScrcpyInstanceId;
|
|
75
|
+
|
|
76
|
+
videoCodec?: "h264" | "h265" | "av1";
|
|
77
|
+
videoBitRate?: number;
|
|
78
|
+
videoCodecOptions?: CodecOptions;
|
|
79
|
+
videoEncoder?: string;
|
|
80
|
+
|
|
81
|
+
audio?: boolean;
|
|
82
|
+
audioCodec?: "opus" | "aac" | "raw";
|
|
83
|
+
audioBitRate?: number;
|
|
84
|
+
audioCodecOptions?: CodecOptions;
|
|
85
|
+
audioEncoder?: string;
|
|
86
|
+
|
|
87
|
+
listEncoders?: boolean;
|
|
88
|
+
listDisplays?: boolean;
|
|
89
|
+
sendCodecMeta?: boolean;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function omit<T extends object, K extends keyof T>(
|
|
93
|
+
obj: T,
|
|
94
|
+
keys: K[]
|
|
95
|
+
): Omit<T, K> {
|
|
96
|
+
const result: Record<PropertyKey, unknown> = {};
|
|
97
|
+
for (const key in obj) {
|
|
98
|
+
if (!keys.includes(key as keyof T as K)) {
|
|
99
|
+
result[key] = obj[key];
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return result as Omit<T, K>;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export class ScrcpyOptions2_0 extends ScrcpyOptionsBase<
|
|
106
|
+
ScrcpyOptionsInit2_0,
|
|
107
|
+
ScrcpyOptions1_25
|
|
108
|
+
> {
|
|
109
|
+
public static readonly DEFAULTS = {
|
|
110
|
+
...omit(ScrcpyOptions1_24.DEFAULTS, [
|
|
111
|
+
"bitRate",
|
|
112
|
+
"codecOptions",
|
|
113
|
+
"encoderName",
|
|
114
|
+
]),
|
|
115
|
+
scid: ScrcpyInstanceId.NONE,
|
|
116
|
+
|
|
117
|
+
videoCodec: "h264",
|
|
118
|
+
videoBitRate: 8000000,
|
|
119
|
+
videoCodecOptions: new CodecOptions(),
|
|
120
|
+
videoEncoder: "",
|
|
121
|
+
|
|
122
|
+
audio: true,
|
|
123
|
+
audioCodec: "opus",
|
|
124
|
+
audioBitRate: 128000,
|
|
125
|
+
audioCodecOptions: new CodecOptions(),
|
|
126
|
+
audioEncoder: "",
|
|
127
|
+
|
|
128
|
+
listEncoders: false,
|
|
129
|
+
listDisplays: false,
|
|
130
|
+
sendCodecMeta: true,
|
|
131
|
+
} as const satisfies Required<ScrcpyOptionsInit2_0>;
|
|
132
|
+
|
|
133
|
+
public override get defaults(): Required<ScrcpyOptionsInit2_0> {
|
|
134
|
+
return ScrcpyOptions2_0.DEFAULTS;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
public constructor(init: ScrcpyOptionsInit2_0) {
|
|
138
|
+
super(new ScrcpyOptions1_25(init), {
|
|
139
|
+
...ScrcpyOptions2_0.DEFAULTS,
|
|
140
|
+
...init,
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
public override serialize(): string[] {
|
|
145
|
+
return ScrcpyOptions1_21.serialize(this.value, this.defaults);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
public override setListEncoders(): void {
|
|
149
|
+
this.value.listEncoders = true;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
public override setListDisplays(): void {
|
|
153
|
+
this.value.listDisplays = true;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
public override parseEncoder(line: string): ScrcpyEncoder | undefined {
|
|
157
|
+
let match = line.match(
|
|
158
|
+
/\s+--video-codec=(.*)\s+--video-encoder='(.*)'/
|
|
159
|
+
);
|
|
160
|
+
if (match) {
|
|
161
|
+
return {
|
|
162
|
+
type: "video",
|
|
163
|
+
codec: match[1]!,
|
|
164
|
+
name: match[2]!,
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
match = line.match(/\s+--audio-codec=(.*)\s+--audio-encoder='(.*)'/);
|
|
169
|
+
if (match) {
|
|
170
|
+
return {
|
|
171
|
+
type: "audio",
|
|
172
|
+
codec: match[1]!,
|
|
173
|
+
name: match[2]!,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return undefined;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
public override parseDisplay(line: string): ScrcpyDisplay | undefined {
|
|
181
|
+
const match = line.match(/\s+--display=(\d+)\s+\((.*?)\)/);
|
|
182
|
+
if (match) {
|
|
183
|
+
const display: ScrcpyDisplay = {
|
|
184
|
+
id: Number.parseInt(match[1]!, 10),
|
|
185
|
+
};
|
|
186
|
+
if (match[2] !== "size unknown") {
|
|
187
|
+
display.resolution = match[2]!;
|
|
188
|
+
}
|
|
189
|
+
return display;
|
|
190
|
+
}
|
|
191
|
+
return undefined;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
public override parseVideoStreamMetadata(
|
|
195
|
+
stream: ReadableStream<Uint8Array>
|
|
196
|
+
): ValueOrPromise<ScrcpyVideoStream> {
|
|
197
|
+
const { sendDeviceMeta, sendCodecMeta } = this.value;
|
|
198
|
+
if (!sendDeviceMeta && !sendCodecMeta) {
|
|
199
|
+
let codec: ScrcpyVideoCodecId;
|
|
200
|
+
switch (this.value.videoCodec) {
|
|
201
|
+
case "h264":
|
|
202
|
+
codec = ScrcpyVideoCodecId.H264;
|
|
203
|
+
break;
|
|
204
|
+
case "h265":
|
|
205
|
+
codec = ScrcpyVideoCodecId.H265;
|
|
206
|
+
break;
|
|
207
|
+
case "av1":
|
|
208
|
+
codec = ScrcpyVideoCodecId.AV1;
|
|
209
|
+
break;
|
|
210
|
+
}
|
|
211
|
+
return { stream, metadata: { codec } };
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
return (async () => {
|
|
215
|
+
const buffered = new BufferedReadableStream(stream);
|
|
216
|
+
|
|
217
|
+
// `sendDeviceMeta` now only contains device name,
|
|
218
|
+
// can't use `super.parseVideoStreamMetadata` here
|
|
219
|
+
let deviceName: string | undefined;
|
|
220
|
+
if (sendDeviceMeta) {
|
|
221
|
+
deviceName = await ScrcpyOptions1_16.parseCString(buffered, 64);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
let codec: ScrcpyVideoCodecId;
|
|
225
|
+
let width: number | undefined;
|
|
226
|
+
let height: number | undefined;
|
|
227
|
+
if (sendCodecMeta) {
|
|
228
|
+
codec = await ScrcpyOptions1_16.parseUint32BE(buffered);
|
|
229
|
+
width = await ScrcpyOptions1_16.parseUint32BE(buffered);
|
|
230
|
+
height = await ScrcpyOptions1_16.parseUint32BE(buffered);
|
|
231
|
+
} else {
|
|
232
|
+
switch (this.value.videoCodec) {
|
|
233
|
+
case "h264":
|
|
234
|
+
codec = ScrcpyVideoCodecId.H264;
|
|
235
|
+
break;
|
|
236
|
+
case "h265":
|
|
237
|
+
codec = ScrcpyVideoCodecId.H265;
|
|
238
|
+
break;
|
|
239
|
+
case "av1":
|
|
240
|
+
codec = ScrcpyVideoCodecId.AV1;
|
|
241
|
+
break;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
return {
|
|
246
|
+
stream: buffered.release(),
|
|
247
|
+
metadata: { deviceName, codec, width, height },
|
|
248
|
+
};
|
|
249
|
+
})();
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
public override parseAudioStreamMetadata(
|
|
253
|
+
stream: ReadableStream<Uint8Array>
|
|
254
|
+
): 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) {
|
|
280
|
+
case ScrcpyAudioCodec.OPUS.metadataValue:
|
|
281
|
+
codec = ScrcpyAudioCodec.OPUS;
|
|
282
|
+
break;
|
|
283
|
+
case ScrcpyAudioCodec.AAC.metadataValue:
|
|
284
|
+
codec = ScrcpyAudioCodec.AAC;
|
|
285
|
+
break;
|
|
286
|
+
case ScrcpyAudioCodec.RAW.metadataValue:
|
|
287
|
+
codec = ScrcpyAudioCodec.RAW;
|
|
288
|
+
break;
|
|
289
|
+
default:
|
|
290
|
+
throw new Error(
|
|
291
|
+
`Unknown audio codec metadata value: ${codecMetadataValue}`
|
|
292
|
+
);
|
|
293
|
+
}
|
|
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
|
+
})();
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
public override serializeInjectTouchControlMessage(
|
|
338
|
+
message: ScrcpyInjectTouchControlMessage
|
|
339
|
+
): Uint8Array {
|
|
340
|
+
return ScrcpyInjectTouchControlMessage2_0.serialize(message);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import type { ReadableStream } from "@yume-chan/stream-extra";
|
|
2
|
+
|
|
3
|
+
import type { ScrcpyOptionValue } from "./types.js";
|
|
4
|
+
|
|
5
|
+
export enum ScrcpyVideoCodecId {
|
|
6
|
+
H264 = 0x68_32_36_34,
|
|
7
|
+
H265 = 0x68_32_36_35,
|
|
8
|
+
AV1 = 0x00_61_76_31,
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface ScrcpyVideoStreamMetadata {
|
|
12
|
+
deviceName?: string | undefined;
|
|
13
|
+
width?: number | undefined;
|
|
14
|
+
height?: number | undefined;
|
|
15
|
+
codec: ScrcpyVideoCodecId;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface ScrcpyVideoStream {
|
|
19
|
+
readonly stream: ReadableStream<Uint8Array>;
|
|
20
|
+
readonly metadata: ScrcpyVideoStreamMetadata;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export class ScrcpyAudioCodec implements ScrcpyOptionValue {
|
|
24
|
+
public static readonly OPUS = new ScrcpyAudioCodec(
|
|
25
|
+
"opus",
|
|
26
|
+
0x6f_70_75_73,
|
|
27
|
+
"audio/opus",
|
|
28
|
+
"opus"
|
|
29
|
+
);
|
|
30
|
+
public static readonly AAC = new ScrcpyAudioCodec(
|
|
31
|
+
"aac",
|
|
32
|
+
0x00_61_61_63,
|
|
33
|
+
"audio/aac",
|
|
34
|
+
"mp4a.66"
|
|
35
|
+
);
|
|
36
|
+
public static readonly RAW = new ScrcpyAudioCodec(
|
|
37
|
+
"raw",
|
|
38
|
+
0x00_72_61_77,
|
|
39
|
+
"audio/raw",
|
|
40
|
+
"1"
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
public readonly optionValue: string;
|
|
44
|
+
public readonly metadataValue: number;
|
|
45
|
+
public readonly mimeType: string;
|
|
46
|
+
public readonly webCodecId: string;
|
|
47
|
+
|
|
48
|
+
public constructor(
|
|
49
|
+
optionValue: string,
|
|
50
|
+
metadataValue: number,
|
|
51
|
+
mimeType: string,
|
|
52
|
+
webCodecId: string
|
|
53
|
+
) {
|
|
54
|
+
this.optionValue = optionValue;
|
|
55
|
+
this.metadataValue = metadataValue;
|
|
56
|
+
this.mimeType = mimeType;
|
|
57
|
+
this.webCodecId = webCodecId;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
public toOptionValue(): string {
|
|
61
|
+
return this.optionValue;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface ScrcpyAudioStreamDisabledMetadata {
|
|
66
|
+
readonly type: "disabled";
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface ScrcpyAudioStreamErroredMetadata {
|
|
70
|
+
readonly type: "errored";
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export interface ScrcpyAudioStreamSuccessMetadata {
|
|
74
|
+
readonly type: "success";
|
|
75
|
+
readonly codec: ScrcpyAudioCodec;
|
|
76
|
+
readonly stream: ReadableStream<Uint8Array>;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export type ScrcpyAudioStreamMetadata =
|
|
80
|
+
| ScrcpyAudioStreamDisabledMetadata
|
|
81
|
+
| ScrcpyAudioStreamErroredMetadata
|
|
82
|
+
| ScrcpyAudioStreamSuccessMetadata;
|
|
83
|
+
|
|
84
|
+
export interface ScrcpyMediaStreamConfigurationPacket {
|
|
85
|
+
type: "configuration";
|
|
86
|
+
data: Uint8Array;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export interface ScrcpyMediaStreamDataPacket {
|
|
90
|
+
type: "data";
|
|
91
|
+
keyframe?: boolean;
|
|
92
|
+
pts?: bigint;
|
|
93
|
+
data: Uint8Array;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export type ScrcpyMediaStreamPacket =
|
|
97
|
+
| ScrcpyMediaStreamConfigurationPacket
|
|
98
|
+
| ScrcpyMediaStreamDataPacket;
|
package/src/options/index.ts
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
export * from "./1_16/index.js";
|
|
2
|
+
export * from "./1_17.js";
|
|
2
3
|
export * from "./1_18.js";
|
|
3
4
|
export * from "./1_21.js";
|
|
4
5
|
export * from "./1_22/index.js";
|
|
5
6
|
export * from "./1_23.js";
|
|
6
7
|
export * from "./1_24.js";
|
|
7
8
|
export * from "./1_25/index.js";
|
|
9
|
+
export * from "./2_0.js";
|
|
10
|
+
export * from "./codec.js";
|
|
11
|
+
export * from "./latest.js";
|
|
8
12
|
export * from "./types.js";
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ScrcpyLogLevel1_18, ScrcpyVideoOrientation1_18 } from "./1_18.js";
|
|
2
|
+
import type { ScrcpyOptionsInit2_0 } from "./2_0.js";
|
|
3
|
+
import { ScrcpyOptions2_0 } from "./2_0.js";
|
|
4
|
+
|
|
5
|
+
export const ScrcpyLogLevel = ScrcpyLogLevel1_18;
|
|
6
|
+
export type ScrcpyLogLevel = ScrcpyLogLevel1_18;
|
|
7
|
+
|
|
8
|
+
export const ScrcpyVideoOrientation = ScrcpyVideoOrientation1_18;
|
|
9
|
+
export type ScrcpyVideoOrientation = ScrcpyVideoOrientation1_18;
|
|
10
|
+
|
|
11
|
+
export type ScrcpyOptionsInitLatest = ScrcpyOptionsInit2_0;
|
|
12
|
+
export class ScrcpyOptionsLatest extends ScrcpyOptions2_0 {}
|
|
13
|
+
|
|
14
|
+
export const ScrcpyLatestVersion = "2.0";
|
package/src/options/types.ts
CHANGED
|
@@ -1,12 +1,19 @@
|
|
|
1
|
-
import type { TransformStream } from "@yume-chan/stream-extra";
|
|
1
|
+
import type { ReadableStream, TransformStream } from "@yume-chan/stream-extra";
|
|
2
|
+
import type { ValueOrPromise } from "@yume-chan/struct";
|
|
2
3
|
|
|
3
4
|
import type {
|
|
4
5
|
ScrcpyBackOrScreenOnControlMessage,
|
|
5
6
|
ScrcpyControlMessageType,
|
|
7
|
+
ScrcpyInjectTouchControlMessage,
|
|
6
8
|
ScrcpySetClipboardControlMessage,
|
|
7
9
|
} from "../control/index.js";
|
|
8
10
|
|
|
9
11
|
import type { ScrcpyScrollController } from "./1_16/scroll.js";
|
|
12
|
+
import type {
|
|
13
|
+
ScrcpyAudioStreamMetadata,
|
|
14
|
+
ScrcpyMediaStreamPacket,
|
|
15
|
+
ScrcpyVideoStream,
|
|
16
|
+
} from "./codec.js";
|
|
10
17
|
|
|
11
18
|
export const DEFAULT_SERVER_PATH = "/data/local/tmp/scrcpy-server.jar";
|
|
12
19
|
|
|
@@ -38,65 +45,168 @@ export function toScrcpyOptionValue<T>(value: unknown, empty: T): string | T {
|
|
|
38
45
|
return String(value);
|
|
39
46
|
}
|
|
40
47
|
|
|
41
|
-
export interface
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
48
|
+
export interface ScrcpyEncoder {
|
|
49
|
+
type: "video" | "audio";
|
|
50
|
+
codec?: string;
|
|
51
|
+
name: string;
|
|
52
|
+
}
|
|
45
53
|
|
|
46
|
-
|
|
47
|
-
|
|
54
|
+
export interface ScrcpyDisplay {
|
|
55
|
+
id: number;
|
|
56
|
+
resolution?: string;
|
|
57
|
+
}
|
|
48
58
|
|
|
49
|
-
|
|
50
|
-
|
|
59
|
+
export interface ScrcpyOptions<T extends object> {
|
|
60
|
+
readonly defaults: Required<T>;
|
|
61
|
+
|
|
62
|
+
readonly controlMessageTypes: readonly ScrcpyControlMessageType[];
|
|
63
|
+
|
|
64
|
+
readonly value: Required<T>;
|
|
65
|
+
|
|
66
|
+
serialize(): string[];
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Set the essential options to let Scrcpy server print out available encoders.
|
|
70
|
+
*/
|
|
71
|
+
setListEncoders(): void;
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Set the essential options to let Scrcpy server print out available displays.
|
|
75
|
+
*/
|
|
76
|
+
setListDisplays(): void;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Parse encoder information from Scrcpy server output
|
|
80
|
+
* @param line One line of Scrcpy server output
|
|
81
|
+
*/
|
|
82
|
+
parseEncoder(line: string): ScrcpyEncoder | undefined;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Parse display information from Scrcpy server output
|
|
86
|
+
* @param line One line of Scrcpy server output
|
|
87
|
+
*/
|
|
88
|
+
parseDisplay(line: string): ScrcpyDisplay | undefined;
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Parse the device metadata from video stream according to the current version and options.
|
|
92
|
+
* @param stream The video stream.
|
|
93
|
+
* @returns
|
|
94
|
+
* A tuple of the video stream and the metadata.
|
|
95
|
+
*
|
|
96
|
+
* The returned video stream may be different from the input stream, and should be used for further processing.
|
|
97
|
+
*/
|
|
98
|
+
parseVideoStreamMetadata(
|
|
99
|
+
stream: ReadableStream<Uint8Array>
|
|
100
|
+
): ValueOrPromise<ScrcpyVideoStream>;
|
|
101
|
+
|
|
102
|
+
parseAudioStreamMetadata(
|
|
103
|
+
stream: ReadableStream<Uint8Array>
|
|
104
|
+
): ValueOrPromise<ScrcpyAudioStreamMetadata>;
|
|
105
|
+
|
|
106
|
+
createMediaStreamTransformer(): TransformStream<
|
|
107
|
+
Uint8Array,
|
|
108
|
+
ScrcpyMediaStreamPacket
|
|
109
|
+
>;
|
|
51
110
|
|
|
52
|
-
|
|
53
|
-
|
|
111
|
+
serializeInjectTouchControlMessage(
|
|
112
|
+
message: ScrcpyInjectTouchControlMessage
|
|
113
|
+
): Uint8Array;
|
|
54
114
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
115
|
+
serializeBackOrScreenOnControlMessage(
|
|
116
|
+
message: ScrcpyBackOrScreenOnControlMessage
|
|
117
|
+
): Uint8Array | undefined;
|
|
58
118
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
pictureParameterSet: Uint8Array;
|
|
63
|
-
data: H264Configuration;
|
|
64
|
-
}
|
|
119
|
+
serializeSetClipboardControlMessage(
|
|
120
|
+
message: ScrcpySetClipboardControlMessage
|
|
121
|
+
): Uint8Array;
|
|
65
122
|
|
|
66
|
-
|
|
67
|
-
type: "frame";
|
|
68
|
-
keyframe?: boolean;
|
|
69
|
-
pts?: bigint;
|
|
70
|
-
data: Uint8Array;
|
|
123
|
+
createScrollController(): ScrcpyScrollController;
|
|
71
124
|
}
|
|
72
125
|
|
|
73
|
-
export
|
|
74
|
-
|
|
75
|
-
|
|
126
|
+
export abstract class ScrcpyOptionsBase<
|
|
127
|
+
T extends object,
|
|
128
|
+
B extends ScrcpyOptions<object>
|
|
129
|
+
> implements ScrcpyOptions<T>
|
|
130
|
+
{
|
|
131
|
+
protected _base: B;
|
|
76
132
|
|
|
77
|
-
|
|
78
|
-
value: Partial<T>;
|
|
133
|
+
public abstract get defaults(): Required<T>;
|
|
79
134
|
|
|
80
|
-
|
|
135
|
+
public get controlMessageTypes(): readonly ScrcpyControlMessageType[] {
|
|
136
|
+
return this._base.controlMessageTypes;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
public readonly value: Required<T>;
|
|
81
140
|
|
|
82
|
-
|
|
141
|
+
public constructor(base: B, value: Required<T>) {
|
|
142
|
+
this._base = base;
|
|
143
|
+
this.value = value;
|
|
144
|
+
}
|
|
83
145
|
|
|
84
|
-
|
|
146
|
+
public abstract serialize(): string[];
|
|
147
|
+
|
|
148
|
+
public setListEncoders(): void {
|
|
149
|
+
this._base.setListEncoders();
|
|
150
|
+
}
|
|
85
151
|
|
|
86
|
-
|
|
152
|
+
public setListDisplays(): void {
|
|
153
|
+
this._base.setListDisplays();
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
public parseEncoder(line: string): ScrcpyEncoder | undefined {
|
|
157
|
+
return this._base.parseEncoder(line);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
public parseDisplay(line: string): ScrcpyDisplay | undefined {
|
|
161
|
+
return this._base.parseDisplay(line);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Parse the device metadata from video stream according to the current version and options.
|
|
166
|
+
* @param stream The video stream.
|
|
167
|
+
* @returns
|
|
168
|
+
* A tuple of the video stream and the metadata.
|
|
169
|
+
*
|
|
170
|
+
* The returned video stream may be different from the input stream, and should be used for further processing.
|
|
171
|
+
*/
|
|
172
|
+
public parseVideoStreamMetadata(
|
|
173
|
+
stream: ReadableStream<Uint8Array>
|
|
174
|
+
): ValueOrPromise<ScrcpyVideoStream> {
|
|
175
|
+
return this._base.parseVideoStreamMetadata(stream);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
public parseAudioStreamMetadata(
|
|
179
|
+
stream: ReadableStream<Uint8Array>
|
|
180
|
+
): ValueOrPromise<ScrcpyAudioStreamMetadata> {
|
|
181
|
+
return this._base.parseAudioStreamMetadata(stream);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
public createMediaStreamTransformer(): TransformStream<
|
|
87
185
|
Uint8Array,
|
|
88
|
-
|
|
89
|
-
|
|
186
|
+
ScrcpyMediaStreamPacket
|
|
187
|
+
> {
|
|
188
|
+
return this._base.createMediaStreamTransformer();
|
|
189
|
+
}
|
|
90
190
|
|
|
91
|
-
|
|
191
|
+
public serializeInjectTouchControlMessage(
|
|
192
|
+
message: ScrcpyInjectTouchControlMessage
|
|
193
|
+
): Uint8Array {
|
|
194
|
+
return this._base.serializeInjectTouchControlMessage(message);
|
|
195
|
+
}
|
|
92
196
|
|
|
93
|
-
serializeBackOrScreenOnControlMessage(
|
|
197
|
+
public serializeBackOrScreenOnControlMessage(
|
|
94
198
|
message: ScrcpyBackOrScreenOnControlMessage
|
|
95
|
-
): Uint8Array | undefined
|
|
199
|
+
): Uint8Array | undefined {
|
|
200
|
+
return this._base.serializeBackOrScreenOnControlMessage(message);
|
|
201
|
+
}
|
|
96
202
|
|
|
97
|
-
serializeSetClipboardControlMessage(
|
|
203
|
+
public serializeSetClipboardControlMessage(
|
|
98
204
|
message: ScrcpySetClipboardControlMessage
|
|
99
|
-
): Uint8Array
|
|
205
|
+
): Uint8Array {
|
|
206
|
+
return this._base.serializeSetClipboardControlMessage(message);
|
|
207
|
+
}
|
|
100
208
|
|
|
101
|
-
|
|
209
|
+
public createScrollController(): ScrcpyScrollController {
|
|
210
|
+
return this._base.createScrollController();
|
|
211
|
+
}
|
|
102
212
|
}
|