@yume-chan/scrcpy 0.0.12 → 0.0.15
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 +39 -0
- package/CHANGELOG.md +23 -1
- package/README.md +1 -0
- package/bin/scrcpy-server +0 -0
- package/bin/version.d.ts +1 -1
- package/bin/version.js +1 -1
- package/esm/client.d.ts +14 -2
- package/esm/client.d.ts.map +1 -1
- package/esm/client.js +277 -145
- package/esm/client.js.map +1 -1
- package/esm/connection.d.ts +4 -4
- package/esm/connection.d.ts.map +1 -1
- package/esm/connection.js +74 -71
- package/esm/connection.js.map +1 -1
- package/esm/decoder/tinyh264/index.js +48 -48
- package/esm/decoder/tinyh264/index.js.map +1 -1
- package/esm/decoder/tinyh264/wrapper.js +3 -2
- package/esm/decoder/tinyh264/wrapper.js.map +1 -1
- package/esm/decoder/web-codecs/index.d.ts.map +1 -1
- package/esm/decoder/web-codecs/index.js +28 -22
- package/esm/decoder/web-codecs/index.js.map +1 -1
- package/esm/message.d.ts +12 -8
- package/esm/message.d.ts.map +1 -1
- package/esm/message.js +13 -8
- package/esm/message.js.map +1 -1
- package/esm/options/1_16/index.d.ts +8 -7
- package/esm/options/1_16/index.d.ts.map +1 -1
- package/esm/options/1_16/index.js +88 -82
- package/esm/options/1_16/index.js.map +1 -1
- package/esm/options/1_16/sps.js +3 -2
- package/esm/options/1_16/sps.js.map +1 -1
- package/esm/options/1_18.d.ts +3 -2
- package/esm/options/1_18.d.ts.map +1 -1
- package/esm/options/1_18.js +24 -1
- package/esm/options/1_18.js.map +1 -1
- package/esm/options/1_21.js +4 -1
- package/esm/options/1_21.js.map +1 -1
- package/esm/options/1_22.d.ts +3 -3
- package/esm/options/1_22.d.ts.map +1 -1
- package/esm/options/1_22.js +9 -6
- package/esm/options/1_22.js.map +1 -1
- package/esm/options/1_23.d.ts +12 -0
- package/esm/options/1_23.d.ts.map +1 -0
- package/esm/options/1_23.js +34 -0
- package/esm/options/1_23.js.map +1 -0
- package/esm/options/1_24.d.ts +9 -0
- package/esm/options/1_24.d.ts.map +1 -0
- package/esm/options/1_24.js +13 -0
- package/esm/options/1_24.js.map +1 -0
- package/esm/options/common.d.ts +6 -2
- package/esm/options/common.d.ts.map +1 -1
- package/esm/options/common.js.map +1 -1
- package/esm/options/index.d.ts +2 -0
- package/esm/options/index.d.ts.map +1 -1
- package/esm/options/index.js +2 -0
- package/esm/options/index.js.map +1 -1
- package/esm/push-server.d.ts +2 -2
- package/esm/push-server.d.ts.map +1 -1
- package/esm/push-server.js +6 -13
- package/esm/push-server.js.map +1 -1
- package/esm/utils.d.ts +0 -2
- package/esm/utils.d.ts.map +1 -1
- package/esm/utils.js +0 -8
- package/esm/utils.js.map +1 -1
- package/package.json +6 -6
- package/src/client.ts +185 -25
- package/src/connection.ts +40 -15
- package/src/decoder/web-codecs/index.ts +2 -1
- package/src/message.ts +10 -3
- package/src/options/1_16/index.ts +51 -43
- package/src/options/1_18.ts +21 -1
- package/src/options/1_22.ts +6 -8
- package/src/options/1_23.ts +44 -0
- package/src/options/1_24.ts +18 -0
- package/src/options/common.ts +7 -2
- package/src/options/index.ts +2 -0
- package/src/push-server.ts +6 -8
- package/src/utils.ts +0 -11
package/src/connection.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Adb,
|
|
1
|
+
import type { Adb, AdbSocket } from "@yume-chan/adb";
|
|
2
2
|
import type { Disposable } from "@yume-chan/event";
|
|
3
3
|
import type { ValueOrPromise } from "@yume-chan/struct";
|
|
4
4
|
import { delay } from "./utils.js";
|
|
@@ -29,7 +29,7 @@ export abstract class ScrcpyClientConnection implements Disposable {
|
|
|
29
29
|
|
|
30
30
|
public initialize(): ValueOrPromise<void> { }
|
|
31
31
|
|
|
32
|
-
public abstract getStreams(): ValueOrPromise<[videoSteam:
|
|
32
|
+
public abstract getStreams(): ValueOrPromise<[videoSteam: AdbSocket, controlStream: AdbSocket | undefined]>;
|
|
33
33
|
|
|
34
34
|
public dispose(): void { }
|
|
35
35
|
}
|
|
@@ -50,26 +50,39 @@ export class ScrcpyClientForwardConnection extends ScrcpyClientConnection {
|
|
|
50
50
|
throw new Error(`Can't connect to server after 100 retries`);
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
private async connectVideoStream(): Promise<
|
|
54
|
-
const
|
|
55
|
-
const stream = new AdbBufferedStream(socket);
|
|
53
|
+
private async connectVideoStream(): Promise<AdbSocket> {
|
|
54
|
+
const stream = await this.connectAndRetry();
|
|
56
55
|
if (this.options.sendDummyByte) {
|
|
56
|
+
const reader = stream.readable.getReader();
|
|
57
|
+
const { done, value } = await reader.read();
|
|
57
58
|
// server will write a `0` to signal connection success
|
|
58
|
-
|
|
59
|
+
if (done || value.byteLength !== 1 || value[0] !== 0) {
|
|
60
|
+
throw new Error('Unexpected response from server');
|
|
61
|
+
}
|
|
62
|
+
reader.releaseLock();
|
|
59
63
|
}
|
|
60
64
|
return stream;
|
|
61
65
|
}
|
|
62
66
|
|
|
63
|
-
public async getStreams(): Promise<[videoSteam:
|
|
67
|
+
public async getStreams(): Promise<[videoSteam: AdbSocket, controlStream: AdbSocket | undefined]> {
|
|
64
68
|
const videoStream = await this.connectVideoStream();
|
|
69
|
+
|
|
65
70
|
let controlStream: AdbSocket | undefined;
|
|
66
71
|
if (this.options.control) {
|
|
67
72
|
controlStream = await this.connectAndRetry();
|
|
68
73
|
}
|
|
74
|
+
|
|
75
|
+
// Server only writes device meta after control socket is connected (if enabled)
|
|
69
76
|
if (this.options.sendDeviceMeta) {
|
|
77
|
+
const reader = videoStream.readable.getReader();
|
|
78
|
+
const { done, value } = await reader.read();
|
|
70
79
|
// 64 bytes device name + 2 bytes video width + 2 bytes video height
|
|
71
|
-
|
|
80
|
+
if (done || value.byteLength !== 64 + 2 + 2) {
|
|
81
|
+
throw new Error('Unexpected response from server');
|
|
82
|
+
}
|
|
83
|
+
reader.releaseLock();
|
|
72
84
|
}
|
|
85
|
+
|
|
73
86
|
return [videoStream, controlStream];
|
|
74
87
|
}
|
|
75
88
|
}
|
|
@@ -90,27 +103,39 @@ export class ScrcpyClientReverseConnection extends ScrcpyClientConnection {
|
|
|
90
103
|
const queue = new TransformStream<AdbSocket>();
|
|
91
104
|
this.streams = queue.readable.getReader();
|
|
92
105
|
const writer = queue.writable.getWriter();
|
|
93
|
-
this.address = await this.device.reverse.add(
|
|
94
|
-
|
|
95
|
-
|
|
106
|
+
this.address = await this.device.reverse.add(
|
|
107
|
+
'localabstract:scrcpy',
|
|
108
|
+
'tcp:27183',
|
|
109
|
+
socket => {
|
|
110
|
+
writer.write(socket);
|
|
111
|
+
return true;
|
|
96
112
|
},
|
|
97
|
-
|
|
113
|
+
);
|
|
98
114
|
}
|
|
99
115
|
|
|
100
116
|
private async accept(): Promise<AdbSocket> {
|
|
101
117
|
return (await this.streams.read()).value!;
|
|
102
118
|
}
|
|
103
119
|
|
|
104
|
-
public async getStreams(): Promise<[videoSteam:
|
|
105
|
-
const videoStream =
|
|
120
|
+
public async getStreams(): Promise<[videoSteam: AdbSocket, controlStream: AdbSocket | undefined]> {
|
|
121
|
+
const videoStream = await this.accept();
|
|
122
|
+
|
|
106
123
|
let controlStream: AdbSocket | undefined;
|
|
107
124
|
if (this.options.control) {
|
|
108
125
|
controlStream = await this.accept();
|
|
109
126
|
}
|
|
127
|
+
|
|
128
|
+
// Server only writes device meta after control socket is connected (if enabled)
|
|
110
129
|
if (this.options.sendDeviceMeta) {
|
|
130
|
+
const reader = videoStream.readable.getReader();
|
|
131
|
+
const { done, value } = await reader.read();
|
|
111
132
|
// 64 bytes device name + 2 bytes video width + 2 bytes video height
|
|
112
|
-
|
|
133
|
+
if (done || value.byteLength !== 64 + 2 + 2) {
|
|
134
|
+
throw new Error('Unexpected response from server');
|
|
135
|
+
}
|
|
136
|
+
reader.releaseLock();
|
|
113
137
|
}
|
|
138
|
+
|
|
114
139
|
return [videoStream, controlStream];
|
|
115
140
|
}
|
|
116
141
|
|
|
@@ -55,7 +55,8 @@ export class WebCodecsDecoder implements H264Decoder {
|
|
|
55
55
|
break;
|
|
56
56
|
case 'frame':
|
|
57
57
|
this.decoder.decode(new EncodedVideoChunk({
|
|
58
|
-
|
|
58
|
+
// Treat `undefined` as `key`, otherwise won't decode.
|
|
59
|
+
type: packet.keyframe === false ? 'delta' : 'key',
|
|
59
60
|
timestamp: 0,
|
|
60
61
|
data: packet.data,
|
|
61
62
|
}));
|
package/src/message.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import Struct, { placeholder } from '@yume-chan/struct';
|
|
2
2
|
|
|
3
|
+
// https://github.com/Genymobile/scrcpy/blob/fa5b2a29e983a46b49531def9cf3d80c40c3de37/app/src/control_msg.h#L23
|
|
4
|
+
// For their message bodies, see https://github.com/Genymobile/scrcpy/blob/5c62f3419d252d10cd8c9cbb7c918b358b81f2d0/app/src/control_msg.c#L92
|
|
3
5
|
export enum ScrcpyControlMessageType {
|
|
4
6
|
InjectKeycode,
|
|
5
7
|
InjectText,
|
|
@@ -7,6 +9,7 @@ export enum ScrcpyControlMessageType {
|
|
|
7
9
|
InjectScroll,
|
|
8
10
|
BackOrScreenOn,
|
|
9
11
|
ExpandNotificationPanel,
|
|
12
|
+
ExpandSettingPanel,
|
|
10
13
|
CollapseNotificationPanel,
|
|
11
14
|
GetClipboard,
|
|
12
15
|
SetClipboard,
|
|
@@ -31,9 +34,13 @@ export enum AndroidMotionEventAction {
|
|
|
31
34
|
ButtonRelease,
|
|
32
35
|
}
|
|
33
36
|
|
|
37
|
+
export const ScrcpySimpleControlMessage =
|
|
38
|
+
new Struct()
|
|
39
|
+
.uint8('type');
|
|
40
|
+
|
|
34
41
|
export const ScrcpyInjectTouchControlMessage =
|
|
35
42
|
new Struct()
|
|
36
|
-
.
|
|
43
|
+
.fields(ScrcpySimpleControlMessage)
|
|
37
44
|
.uint8('action', placeholder<AndroidMotionEventAction>())
|
|
38
45
|
.uint64('pointerId')
|
|
39
46
|
.uint32('pointerX')
|
|
@@ -47,7 +54,7 @@ export type ScrcpyInjectTouchControlMessage = typeof ScrcpyInjectTouchControlMes
|
|
|
47
54
|
|
|
48
55
|
export const ScrcpyInjectTextControlMessage =
|
|
49
56
|
new Struct()
|
|
50
|
-
.
|
|
57
|
+
.fields(ScrcpySimpleControlMessage)
|
|
51
58
|
.uint32('length')
|
|
52
59
|
.string('text', { lengthField: 'length' });
|
|
53
60
|
|
|
@@ -95,7 +102,7 @@ export enum AndroidKeyCode {
|
|
|
95
102
|
|
|
96
103
|
export const ScrcpyInjectKeyCodeControlMessage =
|
|
97
104
|
new Struct()
|
|
98
|
-
.
|
|
105
|
+
.fields(ScrcpySimpleControlMessage)
|
|
99
106
|
.uint8('action', placeholder<AndroidKeyEventAction>())
|
|
100
107
|
.uint32('keyCode')
|
|
101
108
|
.uint32('repeat')
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import Struct
|
|
1
|
+
import { StructDeserializeStream, TransformStream, type Adb } from "@yume-chan/adb";
|
|
2
|
+
import Struct from "@yume-chan/struct";
|
|
3
3
|
import type { AndroidCodecLevel, AndroidCodecProfile } from "../../codec.js";
|
|
4
4
|
import { ScrcpyClientConnection, ScrcpyClientForwardConnection, ScrcpyClientReverseConnection, type ScrcpyClientConnectionOptions } from "../../connection.js";
|
|
5
|
-
import { AndroidKeyEventAction, ScrcpyControlMessageType } from "../../message.js";
|
|
5
|
+
import { AndroidKeyEventAction, ScrcpyControlMessageType, ScrcpySimpleControlMessage } from "../../message.js";
|
|
6
6
|
import type { ScrcpyBackOrScreenOnEvent1_18 } from "../1_18.js";
|
|
7
7
|
import type { ScrcpyInjectScrollControlMessage1_22 } from "../1_22.js";
|
|
8
8
|
import { toScrcpyOptionValue, type ScrcpyOptions, type ScrcpyOptionValue, type VideoStreamPacket } from "../common.js";
|
|
@@ -16,7 +16,7 @@ export enum ScrcpyLogLevel {
|
|
|
16
16
|
Error = 'error',
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
export enum
|
|
19
|
+
export enum ScrcpyVideoOrientation {
|
|
20
20
|
Initial = -2,
|
|
21
21
|
Unlocked = -1,
|
|
22
22
|
Portrait = 0,
|
|
@@ -75,7 +75,7 @@ export interface ScrcpyOptionsInit1_16 {
|
|
|
75
75
|
* It will not keep the device screen in specific orientation,
|
|
76
76
|
* only the captured video will in this orientation.
|
|
77
77
|
*/
|
|
78
|
-
lockVideoOrientation:
|
|
78
|
+
lockVideoOrientation: ScrcpyVideoOrientation;
|
|
79
79
|
|
|
80
80
|
tunnelForward: boolean;
|
|
81
81
|
|
|
@@ -112,19 +112,18 @@ export interface ScrcpyOptionsInit1_16 {
|
|
|
112
112
|
|
|
113
113
|
export const VideoPacket =
|
|
114
114
|
new Struct()
|
|
115
|
-
.
|
|
115
|
+
.uint64('pts')
|
|
116
116
|
.uint32('size')
|
|
117
117
|
.uint8Array('data', { lengthField: 'size' });
|
|
118
118
|
|
|
119
|
-
export const
|
|
119
|
+
export const NO_PTS = BigInt(1) << BigInt(63);
|
|
120
120
|
|
|
121
121
|
export const ScrcpyBackOrScreenOnEvent1_16 =
|
|
122
|
-
|
|
123
|
-
.uint8('type', placeholder<ScrcpyControlMessageType.BackOrScreenOn>());
|
|
122
|
+
ScrcpySimpleControlMessage;
|
|
124
123
|
|
|
125
124
|
export const ScrcpyInjectScrollControlMessage1_16 =
|
|
126
125
|
new Struct()
|
|
127
|
-
.
|
|
126
|
+
.fields(ScrcpySimpleControlMessage)
|
|
128
127
|
.uint32('pointerX')
|
|
129
128
|
.uint32('pointerY')
|
|
130
129
|
.uint16('screenWidth')
|
|
@@ -142,8 +141,8 @@ export class ScrcpyOptions1_16<T extends ScrcpyOptionsInit1_16 = ScrcpyOptionsIn
|
|
|
142
141
|
}
|
|
143
142
|
|
|
144
143
|
if (new.target === ScrcpyOptions1_16 &&
|
|
145
|
-
value.lockVideoOrientation ===
|
|
146
|
-
value.lockVideoOrientation =
|
|
144
|
+
value.lockVideoOrientation === ScrcpyVideoOrientation.Initial) {
|
|
145
|
+
value.lockVideoOrientation = ScrcpyVideoOrientation.Unlocked;
|
|
147
146
|
}
|
|
148
147
|
|
|
149
148
|
this.value = value as Partial<T>;
|
|
@@ -174,7 +173,7 @@ export class ScrcpyOptions1_16<T extends ScrcpyOptionsInit1_16 = ScrcpyOptionsIn
|
|
|
174
173
|
maxSize: 0,
|
|
175
174
|
bitRate: 8_000_000,
|
|
176
175
|
maxFps: 0,
|
|
177
|
-
lockVideoOrientation:
|
|
176
|
+
lockVideoOrientation: ScrcpyVideoOrientation.Unlocked,
|
|
178
177
|
tunnelForward: false,
|
|
179
178
|
crop: '-',
|
|
180
179
|
sendFrameMeta: true,
|
|
@@ -211,29 +210,28 @@ export class ScrcpyOptions1_16<T extends ScrcpyOptionsInit1_16 = ScrcpyOptionsIn
|
|
|
211
210
|
return /\s+scrcpy --encoder-name '(.*?)'/;
|
|
212
211
|
}
|
|
213
212
|
|
|
214
|
-
public
|
|
213
|
+
public createVideoStreamTransformer(): TransformStream<Uint8Array, VideoStreamPacket> {
|
|
215
214
|
// Optimized path for video frames only
|
|
216
215
|
if (this.value.sendFrameMeta === false) {
|
|
217
|
-
return
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
},
|
|
226
|
-
}));
|
|
216
|
+
return new TransformStream({
|
|
217
|
+
transform(chunk, controller) {
|
|
218
|
+
controller.enqueue({
|
|
219
|
+
type: 'frame',
|
|
220
|
+
data: chunk,
|
|
221
|
+
});
|
|
222
|
+
},
|
|
223
|
+
});
|
|
227
224
|
}
|
|
228
225
|
|
|
229
226
|
let header: Uint8Array | undefined;
|
|
230
227
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
228
|
+
let deserializeStream = new StructDeserializeStream(VideoPacket);
|
|
229
|
+
return {
|
|
230
|
+
writable: deserializeStream.writable,
|
|
231
|
+
readable: deserializeStream.readable.pipeThrough(new TransformStream({
|
|
232
|
+
transform(packet, controller) {
|
|
233
|
+
if (packet.pts === NO_PTS) {
|
|
234
|
+
const sequenceParameterSet = parse_sequence_parameter_set(packet.data.slice().buffer);
|
|
237
235
|
|
|
238
236
|
const {
|
|
239
237
|
profile_idc: profileIndex,
|
|
@@ -258,7 +256,7 @@ export class ScrcpyOptions1_16<T extends ScrcpyOptionsInit1_16 = ScrcpyOptionsIn
|
|
|
258
256
|
const croppedWidth = encodedWidth - cropLeft - cropRight;
|
|
259
257
|
const croppedHeight = encodedHeight - cropTop - cropBottom;
|
|
260
258
|
|
|
261
|
-
header = data;
|
|
259
|
+
header = packet.data;
|
|
262
260
|
controller.enqueue({
|
|
263
261
|
type: 'configuration',
|
|
264
262
|
data: {
|
|
@@ -280,28 +278,38 @@ export class ScrcpyOptions1_16<T extends ScrcpyOptionsInit1_16 = ScrcpyOptionsIn
|
|
|
280
278
|
|
|
281
279
|
let frameData: Uint8Array;
|
|
282
280
|
if (header) {
|
|
283
|
-
frameData = new Uint8Array(header.byteLength + data.byteLength);
|
|
281
|
+
frameData = new Uint8Array(header.byteLength + packet.data.byteLength);
|
|
284
282
|
frameData.set(header);
|
|
285
|
-
frameData.set(data
|
|
283
|
+
frameData.set(packet.data, header.byteLength);
|
|
286
284
|
header = undefined;
|
|
287
285
|
} else {
|
|
288
|
-
frameData = data;
|
|
286
|
+
frameData = packet.data;
|
|
289
287
|
}
|
|
290
288
|
|
|
291
289
|
controller.enqueue({
|
|
292
290
|
type: 'frame',
|
|
291
|
+
pts: packet.pts,
|
|
293
292
|
data: frameData,
|
|
294
293
|
});
|
|
295
|
-
} catch (e) {
|
|
296
|
-
if (e instanceof BufferedStreamEndedError) {
|
|
297
|
-
controller.close();
|
|
298
|
-
return;
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
throw e;
|
|
302
294
|
}
|
|
303
|
-
}
|
|
304
|
-
}
|
|
295
|
+
}))
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
public getControlMessageTypes(): ScrcpyControlMessageType[] {
|
|
300
|
+
return [
|
|
301
|
+
/* 0 */ ScrcpyControlMessageType.InjectKeycode,
|
|
302
|
+
/* 1 */ ScrcpyControlMessageType.InjectText,
|
|
303
|
+
/* 2 */ ScrcpyControlMessageType.InjectTouch,
|
|
304
|
+
/* 3 */ ScrcpyControlMessageType.InjectScroll,
|
|
305
|
+
/* 4 */ ScrcpyControlMessageType.BackOrScreenOn,
|
|
306
|
+
/* 5 */ ScrcpyControlMessageType.ExpandNotificationPanel,
|
|
307
|
+
/* 6 */ ScrcpyControlMessageType.CollapseNotificationPanel,
|
|
308
|
+
/* 7 */ ScrcpyControlMessageType.GetClipboard,
|
|
309
|
+
/* 8 */ ScrcpyControlMessageType.SetClipboard,
|
|
310
|
+
/* 9 */ ScrcpyControlMessageType.SetScreenPowerMode,
|
|
311
|
+
/* 10 */ ScrcpyControlMessageType.RotateDevice,
|
|
312
|
+
];
|
|
305
313
|
}
|
|
306
314
|
|
|
307
315
|
public serializeBackOrScreenOnControlMessage(
|
package/src/options/1_18.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import Struct, { placeholder } from "@yume-chan/struct";
|
|
2
|
-
import
|
|
2
|
+
import { AndroidKeyEventAction, ScrcpyControlMessageType } from "../message.js";
|
|
3
3
|
import { ScrcpyBackOrScreenOnEvent1_16, ScrcpyOptions1_16, type ScrcpyOptionsInit1_16 } from "./1_16/index.js";
|
|
4
4
|
|
|
5
5
|
export interface ScrcpyOptionsInit1_18 extends ScrcpyOptionsInit1_16 {
|
|
@@ -33,6 +33,26 @@ export class ScrcpyOptions1_18<T extends ScrcpyOptionsInit1_18 = ScrcpyOptionsIn
|
|
|
33
33
|
return /\s+scrcpy --encoder '(.*?)'/;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
public override getControlMessageTypes(): ScrcpyControlMessageType[] {
|
|
37
|
+
/**
|
|
38
|
+
* 0 InjectKeycode
|
|
39
|
+
* 1 InjectText
|
|
40
|
+
* 2 InjectTouch
|
|
41
|
+
* 3 InjectScroll
|
|
42
|
+
* 4 BackOrScreenOn
|
|
43
|
+
* 5 ExpandNotificationPanel
|
|
44
|
+
* 6 ExpandSettingsPanel
|
|
45
|
+
* 7 CollapseNotificationPanel
|
|
46
|
+
* 8 GetClipboard
|
|
47
|
+
* 9 SetClipboard
|
|
48
|
+
* 10 SetScreenPowerMode
|
|
49
|
+
* 11 RotateDevice
|
|
50
|
+
*/
|
|
51
|
+
const types = super.getControlMessageTypes();
|
|
52
|
+
types.splice(6, 0, ScrcpyControlMessageType.ExpandSettingPanel);
|
|
53
|
+
return types;
|
|
54
|
+
}
|
|
55
|
+
|
|
36
56
|
public override serializeBackOrScreenOnControlMessage(
|
|
37
57
|
message: ScrcpyBackOrScreenOnEvent1_18,
|
|
38
58
|
) {
|
package/src/options/1_22.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Adb } from "@yume-chan/adb";
|
|
2
2
|
import Struct from "@yume-chan/struct";
|
|
3
|
-
import { ScrcpyClientForwardConnection, ScrcpyClientReverseConnection, type ScrcpyClientConnection
|
|
3
|
+
import { ScrcpyClientForwardConnection, ScrcpyClientReverseConnection, type ScrcpyClientConnection } from "../connection.js";
|
|
4
4
|
import { ScrcpyInjectScrollControlMessage1_16 } from "./1_16/index.js";
|
|
5
5
|
import { ScrcpyOptions1_21, type ScrcpyOptionsInit1_21 } from "./1_21.js";
|
|
6
6
|
|
|
@@ -8,14 +8,14 @@ export interface ScrcpyOptionsInit1_22 extends ScrcpyOptionsInit1_21 {
|
|
|
8
8
|
downsizeOnError: boolean;
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
|
-
* Send device name and size
|
|
11
|
+
* Send device name and size at start of video stream.
|
|
12
12
|
*
|
|
13
13
|
* @default true
|
|
14
14
|
*/
|
|
15
15
|
sendDeviceMeta: boolean;
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
|
-
*
|
|
18
|
+
* Send a `0` byte on start of video stream to detect connection issues
|
|
19
19
|
*
|
|
20
20
|
* @default true
|
|
21
21
|
*/
|
|
@@ -59,11 +59,9 @@ export class ScrcpyOptions1_22<T extends ScrcpyOptionsInit1_22 = ScrcpyOptionsIn
|
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
public override createConnection(device: Adb): ScrcpyClientConnection {
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
sendDummyByte: this.value.sendDummyByte ?? defaultValue.sendDummyByte,
|
|
66
|
-
sendDeviceMeta: this.value.sendDeviceMeta ?? defaultValue.sendDeviceMeta,
|
|
62
|
+
const options = {
|
|
63
|
+
...this.getDefaultValue(),
|
|
64
|
+
...this.value,
|
|
67
65
|
};
|
|
68
66
|
if (this.value.tunnelForward) {
|
|
69
67
|
return new ScrcpyClientForwardConnection(device, options);
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { TransformStream } from "@yume-chan/adb";
|
|
2
|
+
import { ScrcpyOptions1_22, type ScrcpyOptionsInit1_22 } from './1_22.js';
|
|
3
|
+
import type { VideoStreamPacket } from "./common.js";
|
|
4
|
+
|
|
5
|
+
export interface ScrcpyOptionsInit1_23 extends ScrcpyOptionsInit1_22 {
|
|
6
|
+
cleanup: boolean;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const KEYFRAME_PTS = BigInt(1) << BigInt(62);
|
|
10
|
+
|
|
11
|
+
export class ScrcpyOptions1_23<T extends ScrcpyOptionsInit1_23 = ScrcpyOptionsInit1_23> extends ScrcpyOptions1_22<T> {
|
|
12
|
+
public constructor(init: Partial<ScrcpyOptionsInit1_23>) {
|
|
13
|
+
super(init);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
protected override getDefaultValue(): T {
|
|
17
|
+
return {
|
|
18
|
+
...super.getDefaultValue(),
|
|
19
|
+
cleanup: true,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
public override createVideoStreamTransformer(): TransformStream<Uint8Array, VideoStreamPacket> {
|
|
24
|
+
const superStream = super.createVideoStreamTransformer();
|
|
25
|
+
return {
|
|
26
|
+
writable: superStream.writable,
|
|
27
|
+
readable: superStream.readable.pipeThrough(new TransformStream({
|
|
28
|
+
transform(packet, controller): void {
|
|
29
|
+
if (packet.type !== 'frame') {
|
|
30
|
+
controller.enqueue(packet);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (packet.pts !== undefined && packet.pts & KEYFRAME_PTS) {
|
|
35
|
+
packet.keyframe = true;
|
|
36
|
+
packet.pts &= ~KEYFRAME_PTS;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
controller.enqueue(packet);
|
|
40
|
+
}
|
|
41
|
+
}))
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ScrcpyOptions1_23, type ScrcpyOptionsInit1_23 } from './1_23.js';
|
|
2
|
+
|
|
3
|
+
export interface ScrcpyOptionsInit1_24 extends ScrcpyOptionsInit1_23 {
|
|
4
|
+
powerOn: boolean;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export class ScrcpyOptions1_24<T extends ScrcpyOptionsInit1_24 = ScrcpyOptionsInit1_24> extends ScrcpyOptions1_23<T> {
|
|
8
|
+
public constructor(init: Partial<ScrcpyOptionsInit1_24>) {
|
|
9
|
+
super(init);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
protected override getDefaultValue(): T {
|
|
13
|
+
return {
|
|
14
|
+
...super.getDefaultValue(),
|
|
15
|
+
powerOn: true,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
}
|
package/src/options/common.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import type { Adb,
|
|
1
|
+
import type { Adb, TransformStream } from "@yume-chan/adb";
|
|
2
2
|
import type { ScrcpyClientConnection } from "../connection.js";
|
|
3
3
|
import type { H264Configuration } from "../decoder/index.js";
|
|
4
|
+
import type { ScrcpyControlMessageType } from "../message.js";
|
|
4
5
|
import type { ScrcpyBackOrScreenOnEvent1_18 } from "./1_18.js";
|
|
5
6
|
import type { ScrcpyInjectScrollControlMessage1_22 } from "./1_22.js";
|
|
6
7
|
|
|
@@ -35,6 +36,8 @@ export interface VideoStreamConfigurationPacket {
|
|
|
35
36
|
|
|
36
37
|
export interface VideoStreamFramePacket {
|
|
37
38
|
type: 'frame';
|
|
39
|
+
keyframe?: boolean | undefined;
|
|
40
|
+
pts?: bigint | undefined;
|
|
38
41
|
data: Uint8Array;
|
|
39
42
|
}
|
|
40
43
|
|
|
@@ -49,7 +52,9 @@ export interface ScrcpyOptions<T> {
|
|
|
49
52
|
|
|
50
53
|
createConnection(adb: Adb): ScrcpyClientConnection;
|
|
51
54
|
|
|
52
|
-
|
|
55
|
+
createVideoStreamTransformer(): TransformStream<Uint8Array, VideoStreamPacket>;
|
|
56
|
+
|
|
57
|
+
getControlMessageTypes(): ScrcpyControlMessageType[];
|
|
53
58
|
|
|
54
59
|
serializeBackOrScreenOnControlMessage(
|
|
55
60
|
message: ScrcpyBackOrScreenOnEvent1_18,
|
package/src/options/index.ts
CHANGED
package/src/push-server.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { WrapWritableStream, type Adb, type AdbSync } from "@yume-chan/adb";
|
|
2
2
|
import { DEFAULT_SERVER_PATH } from "./options/index.js";
|
|
3
3
|
|
|
4
4
|
export interface PushServerOptions {
|
|
@@ -11,15 +11,13 @@ export function pushServer(
|
|
|
11
11
|
) {
|
|
12
12
|
const { path = DEFAULT_SERVER_PATH } = options;
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
let sync!: AdbSync;
|
|
15
|
+
return new WrapWritableStream<Uint8Array>({
|
|
15
16
|
async start() {
|
|
16
|
-
|
|
17
|
-
return
|
|
18
|
-
writable: sync.write(path),
|
|
19
|
-
state: sync,
|
|
20
|
-
};
|
|
17
|
+
sync = await device.sync();
|
|
18
|
+
return sync.write(path);
|
|
21
19
|
},
|
|
22
|
-
async close(
|
|
20
|
+
async close() {
|
|
23
21
|
await sync.dispose();
|
|
24
22
|
},
|
|
25
23
|
});
|
package/src/utils.ts
CHANGED
|
@@ -3,14 +3,3 @@ export function delay(time: number): Promise<void> {
|
|
|
3
3
|
(globalThis as any).setTimeout(resolve, time);
|
|
4
4
|
});
|
|
5
5
|
}
|
|
6
|
-
|
|
7
|
-
const Utf8Encoder = new TextEncoder();
|
|
8
|
-
const Utf8Decoder = new TextDecoder();
|
|
9
|
-
|
|
10
|
-
export function encodeUtf8(input: string): ArrayBuffer {
|
|
11
|
-
return Utf8Encoder.encode(input).buffer;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export function decodeUtf8(buffer: ArrayBuffer): string {
|
|
15
|
-
return Utf8Decoder.decode(buffer);
|
|
16
|
-
}
|