@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
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ScrcpyOptions1_23, type ScrcpyOptionsInit1_23 } from './1_23.js';
|
|
2
|
+
export interface ScrcpyOptionsInit1_24 extends ScrcpyOptionsInit1_23 {
|
|
3
|
+
powerOn: boolean;
|
|
4
|
+
}
|
|
5
|
+
export declare class ScrcpyOptions1_24<T extends ScrcpyOptionsInit1_24 = ScrcpyOptionsInit1_24> extends ScrcpyOptions1_23<T> {
|
|
6
|
+
constructor(init: Partial<ScrcpyOptionsInit1_24>);
|
|
7
|
+
protected getDefaultValue(): T;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=1_24.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"1_24.d.ts","sourceRoot":"","sources":["../../src/options/1_24.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,KAAK,qBAAqB,EAAE,MAAM,WAAW,CAAC;AAE1E,MAAM,WAAW,qBAAsB,SAAQ,qBAAqB;IAChE,OAAO,EAAE,OAAO,CAAC;CACpB;AAED,qBAAa,iBAAiB,CAAC,CAAC,SAAS,qBAAqB,GAAG,qBAAqB,CAAE,SAAQ,iBAAiB,CAAC,CAAC,CAAC;gBAC7F,IAAI,EAAE,OAAO,CAAC,qBAAqB,CAAC;cAIpC,eAAe,IAAI,CAAC;CAM1C"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ScrcpyOptions1_23 } from './1_23.js';
|
|
2
|
+
export class ScrcpyOptions1_24 extends ScrcpyOptions1_23 {
|
|
3
|
+
constructor(init) {
|
|
4
|
+
super(init);
|
|
5
|
+
}
|
|
6
|
+
getDefaultValue() {
|
|
7
|
+
return {
|
|
8
|
+
...super.getDefaultValue(),
|
|
9
|
+
powerOn: true,
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=1_24.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"1_24.js","sourceRoot":"","sources":["../../src/options/1_24.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAA8B,MAAM,WAAW,CAAC;AAM1E,MAAM,OAAO,iBAA2E,SAAQ,iBAAoB;IAChH,YAAmB,IAAoC;QACnD,KAAK,CAAC,IAAI,CAAC,CAAC;IAChB,CAAC;IAEkB,eAAe;QAC9B,OAAO;YACH,GAAG,KAAK,CAAC,eAAe,EAAE;YAC1B,OAAO,EAAE,IAAI;SAChB,CAAC;IACN,CAAC;CACJ"}
|
package/esm/options/common.d.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
|
export declare const DEFAULT_SERVER_PATH = "/data/local/tmp/scrcpy-server.jar";
|
|
@@ -15,6 +16,8 @@ export interface VideoStreamConfigurationPacket {
|
|
|
15
16
|
}
|
|
16
17
|
export interface VideoStreamFramePacket {
|
|
17
18
|
type: 'frame';
|
|
19
|
+
keyframe?: boolean | undefined;
|
|
20
|
+
pts?: bigint | undefined;
|
|
18
21
|
data: Uint8Array;
|
|
19
22
|
}
|
|
20
23
|
export declare type VideoStreamPacket = VideoStreamConfigurationPacket | VideoStreamFramePacket;
|
|
@@ -23,7 +26,8 @@ export interface ScrcpyOptions<T> {
|
|
|
23
26
|
formatServerArguments(): string[];
|
|
24
27
|
getOutputEncoderNameRegex(): RegExp;
|
|
25
28
|
createConnection(adb: Adb): ScrcpyClientConnection;
|
|
26
|
-
|
|
29
|
+
createVideoStreamTransformer(): TransformStream<Uint8Array, VideoStreamPacket>;
|
|
30
|
+
getControlMessageTypes(): ScrcpyControlMessageType[];
|
|
27
31
|
serializeBackOrScreenOnControlMessage(message: ScrcpyBackOrScreenOnEvent1_18): Uint8Array | undefined;
|
|
28
32
|
serializeInjectScrollControlMessage(message: ScrcpyInjectScrollControlMessage1_22): Uint8Array;
|
|
29
33
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../../src/options/common.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,
|
|
1
|
+
{"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../../src/options/common.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAC3D,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAC/D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAC;AAC9D,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,WAAW,CAAC;AAC/D,OAAO,KAAK,EAAE,oCAAoC,EAAE,MAAM,WAAW,CAAC;AAEtE,eAAO,MAAM,mBAAmB,sCAAsC,CAAC;AAEvE,MAAM,WAAW,iBAAiB;IAC9B,aAAa,IAAI,MAAM,GAAG,SAAS,CAAC;CACvC;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,GAAG,GAAG,KAAK,IAAI,iBAAiB,CAI1E;AAED,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,GAAG,MAAM,GAAG,CAAC,CAUvE;AAED,MAAM,WAAW,8BAA8B;IAC3C,IAAI,EAAE,eAAe,CAAC;IACtB,IAAI,EAAE,iBAAiB,CAAC;CAC3B;AAED,MAAM,WAAW,sBAAsB;IACnC,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC/B,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB,IAAI,EAAE,UAAU,CAAC;CACpB;AAED,oBAAY,iBAAiB,GAAG,8BAA8B,GAAG,sBAAsB,CAAC;AAExF,MAAM,WAAW,aAAa,CAAC,CAAC;IAC5B,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IAElB,qBAAqB,IAAI,MAAM,EAAE,CAAC;IAElC,yBAAyB,IAAI,MAAM,CAAC;IAEpC,gBAAgB,CAAC,GAAG,EAAE,GAAG,GAAG,sBAAsB,CAAC;IAEnD,4BAA4B,IAAI,eAAe,CAAC,UAAU,EAAE,iBAAiB,CAAC,CAAC;IAE/E,sBAAsB,IAAI,wBAAwB,EAAE,CAAC;IAErD,qCAAqC,CACjC,OAAO,EAAE,6BAA6B,GACvC,UAAU,GAAG,SAAS,CAAC;IAE1B,mCAAmC,CAC/B,OAAO,EAAE,oCAAoC,GAC9C,UAAU,CAAC;CACjB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"common.js","sourceRoot":"","sources":["../../src/options/common.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"common.js","sourceRoot":"","sources":["../../src/options/common.ts"],"names":[],"mappings":"AAOA,MAAM,CAAC,MAAM,mBAAmB,GAAG,mCAAmC,CAAC;AAMvE,MAAM,UAAU,mBAAmB,CAAC,KAAU;IAC1C,OAAO,OAAO,KAAK,KAAK,QAAQ;QAC5B,KAAK,KAAK,IAAI;QACd,OAAO,KAAK,CAAC,aAAa,KAAK,UAAU,CAAC;AAClD,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAI,KAAU,EAAE,KAAQ;IACvD,IAAI,mBAAmB,CAAC,KAAK,CAAC,EAAE;QAC5B,KAAK,GAAG,KAAK,CAAC,aAAa,EAAE,CAAC;KACjC;IAED,IAAI,KAAK,KAAK,SAAS,EAAE;QACrB,OAAO,KAAK,CAAC;KAChB;IAED,OAAO,GAAG,KAAK,EAAE,CAAC;AACtB,CAAC"}
|
package/esm/options/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/options/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/options/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC"}
|
package/esm/options/index.js
CHANGED
package/esm/options/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/options/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/options/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC"}
|
package/esm/push-server.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { WrapWritableStream, type Adb } from "@yume-chan/adb";
|
|
2
2
|
export interface PushServerOptions {
|
|
3
3
|
path?: string;
|
|
4
4
|
}
|
|
5
|
-
export declare function pushServer(device: Adb, options?: PushServerOptions): WrapWritableStream<Uint8Array
|
|
5
|
+
export declare function pushServer(device: Adb, options?: PushServerOptions): WrapWritableStream<Uint8Array>;
|
|
6
6
|
//# sourceMappingURL=push-server.d.ts.map
|
package/esm/push-server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"push-server.d.ts","sourceRoot":"","sources":["../src/push-server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"push-server.d.ts","sourceRoot":"","sources":["../src/push-server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,KAAK,GAAG,EAAgB,MAAM,gBAAgB,CAAC;AAG5E,MAAM,WAAW,iBAAiB;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,UAAU,CACtB,MAAM,EAAE,GAAG,EACX,OAAO,GAAE,iBAAsB,kCAclC"}
|
package/esm/push-server.js
CHANGED
|
@@ -1,22 +1,15 @@
|
|
|
1
|
-
import { __awaiter } from "tslib";
|
|
2
1
|
import { WrapWritableStream } from "@yume-chan/adb";
|
|
3
2
|
import { DEFAULT_SERVER_PATH } from "./options/index.js";
|
|
4
3
|
export function pushServer(device, options = {}) {
|
|
5
4
|
const { path = DEFAULT_SERVER_PATH } = options;
|
|
5
|
+
let sync;
|
|
6
6
|
return new WrapWritableStream({
|
|
7
|
-
start() {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
return {
|
|
11
|
-
writable: sync.write(path),
|
|
12
|
-
state: sync,
|
|
13
|
-
};
|
|
14
|
-
});
|
|
7
|
+
async start() {
|
|
8
|
+
sync = await device.sync();
|
|
9
|
+
return sync.write(path);
|
|
15
10
|
},
|
|
16
|
-
close(
|
|
17
|
-
|
|
18
|
-
yield sync.dispose();
|
|
19
|
-
});
|
|
11
|
+
async close() {
|
|
12
|
+
await sync.dispose();
|
|
20
13
|
},
|
|
21
14
|
});
|
|
22
15
|
}
|
package/esm/push-server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"push-server.js","sourceRoot":"","sources":["../src/push-server.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"push-server.js","sourceRoot":"","sources":["../src/push-server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAA0B,MAAM,gBAAgB,CAAC;AAC5E,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAMzD,MAAM,UAAU,UAAU,CACtB,MAAW,EACX,UAA6B,EAAE;IAE/B,MAAM,EAAE,IAAI,GAAG,mBAAmB,EAAE,GAAG,OAAO,CAAC;IAE/C,IAAI,IAAc,CAAC;IACnB,OAAO,IAAI,kBAAkB,CAAa;QACtC,KAAK,CAAC,KAAK;YACP,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;YAC3B,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC5B,CAAC;QACD,KAAK,CAAC,KAAK;YACP,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;QACzB,CAAC;KACJ,CAAC,CAAC;AACP,CAAC"}
|
package/esm/utils.d.ts
CHANGED
package/esm/utils.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,wBAAgB,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAIjD
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,wBAAgB,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAIjD"}
|
package/esm/utils.js
CHANGED
|
@@ -3,12 +3,4 @@ export function delay(time) {
|
|
|
3
3
|
globalThis.setTimeout(resolve, time);
|
|
4
4
|
});
|
|
5
5
|
}
|
|
6
|
-
const Utf8Encoder = new TextEncoder();
|
|
7
|
-
const Utf8Decoder = new TextDecoder();
|
|
8
|
-
export function encodeUtf8(input) {
|
|
9
|
-
return Utf8Encoder.encode(input).buffer;
|
|
10
|
-
}
|
|
11
|
-
export function decodeUtf8(buffer) {
|
|
12
|
-
return Utf8Decoder.decode(buffer);
|
|
13
|
-
}
|
|
14
6
|
//# sourceMappingURL=utils.js.map
|
package/esm/utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,KAAK,CAAC,IAAY;IAC9B,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE;QACxB,UAAkB,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;AACP,CAAC
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,KAAK,CAAC,IAAY;IAC9B,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE;QACxB,UAAkB,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;AACP,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yume-chan/scrcpy",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.15",
|
|
4
4
|
"description": "TypeScript implementation of Scrcpy.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"adb",
|
|
@@ -29,10 +29,10 @@
|
|
|
29
29
|
"main": "esm/index.js",
|
|
30
30
|
"types": "esm/index.d.ts",
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@yume-chan/adb": "^0.0.
|
|
32
|
+
"@yume-chan/adb": "^0.0.15",
|
|
33
33
|
"@yume-chan/async": "^2.1.4",
|
|
34
|
-
"@yume-chan/event": "^0.0.
|
|
35
|
-
"@yume-chan/struct": "^0.0.
|
|
34
|
+
"@yume-chan/event": "^0.0.15",
|
|
35
|
+
"@yume-chan/struct": "^0.0.15",
|
|
36
36
|
"tslib": "^2.3.1"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"gh-release-fetch": "^2.0.4",
|
|
43
43
|
"jest": "^27.5.1",
|
|
44
44
|
"tinyh264": "^0.0.7",
|
|
45
|
-
"typescript": "
|
|
45
|
+
"typescript": "4.7.0-beta",
|
|
46
46
|
"yuv-buffer": "^1.0.0",
|
|
47
47
|
"yuv-canvas": "^1.2.7"
|
|
48
48
|
},
|
|
@@ -57,5 +57,5 @@
|
|
|
57
57
|
"build:watch": "build-ts-package --incremental",
|
|
58
58
|
"test": "jest --coverage"
|
|
59
59
|
},
|
|
60
|
-
"readme": "# @yume-chan/scrcpy\r\n\r\nTypeScript implementation of [Scrcpy](https://github.com/Genymobile/scrcpy) client.\r\n\r\nIt uses the official Scrcpy server releases.\r\n\r\n**WARNING:** The public API is UNSTABLE. If you have any questions, please open an issue.\r\n\r\n## Download Server Binary\r\n\r\nThis package has a script `fetch-scrcpy-server` to help you download the official server binary.\r\n\r\nThe server binary is subject to [Apache License 2.0](https://github.com/Genymobile/scrcpy/blob/master/LICENSE).\r\n\r\nUsage:\r\n\r\n```\r\n$ npx fetch-scrcpy-server <version>\r\n```\r\n\r\nFor example:\r\n\r\n```\r\n$ npx fetch-scrcpy-server 1.21\r\n```\r\n\r\nYou can also add it to the `postinstall` script of your `package.json` so it will run automatically when you do `npm install`:\r\n\r\n```json\r\n\"scripts\": {\r\n \"postinstall\": \"fetch-scrcpy-server 1.21\",\r\n},\r\n```\r\n\r\nIt will download the binary to `bin/scrcpy` and write the version string to `bin/version.js`. You can import the version string with\r\n\r\n```js\r\nimport SCRCPY_SERVER_VERSION from '@yume-chan/scrcpy/bin/version';\r\n```\r\n\r\nAnd import the server binary with [file-loader](https://v4.webpack.js.org/loaders/file-loader/) (Webpack 4) or [Asset Modules](https://webpack.js.org/guides/asset-modules/) (Webpack 5).\r\n\r\n## Option versions\r\n\r\nScrcpy server has no backward compatibility on options input format. Currently the following versions are supported:\r\n\r\n| versions | type |\r\n| --------- | ------------------- |\r\n| 1.16~1.17 | `ScrcpyOptions1_16` |\r\n| 1.18~1.20 | `ScrcpyOptions1_18` |\r\n| 1.21 | `ScrcpyOptions1_21` |\r\n| 1.22 | `ScrcpyOptions1_22` |\r\n\r\nYou must use the correct type according to the server version.\r\n\r\n## Video stream\r\n\r\nThe data from `onVideoData` event is a raw H.264 stream. You can process it as you want, or use the following built-in decoders to render it in browsers:\r\n\r\n* WebCodecs decoder: Uses the [WebCodecs API](https://developer.mozilla.org/en-US/docs/Web/API/WebCodecs_API). The video stream will be decoded into `VideoFrame`s and drawn on a 2D canvas.\r\n* TinyH264 decoder: TinyH264 compiles the old Android H.264 software decoder (now deprecated and removed) into WebAssembly, and wrap it in Web Worker to prevent blocking the main thread. The video stream will be decoded into YUV frames, then converted to RGB using a WebGL shader.\r\n\r\n| Name | Chrome | Firefox | Safari | Performance | Supported H.264 profile/level |\r\n| ----------------- | ------ | ------- | ------ | ------------------------------- | ----------------------------- |\r\n| WebCodecs decoder | 94 | No | No | High with Hardware acceleration | High level 5 |\r\n| TinyH264 decoder | 57 | 52 | 11 | Poor | Baseline level 4 |\r\n\r\nTinyH264 decoder needs some extra setup:\r\n\r\n1. `tinyh264`, `yuv-buffer` and `yuv-canvas` packages are peer dependencies. You must install them separately.\r\n2. The bundler you use must support the `new Worker(new URL('./worker.js', import.meta.url))` syntax. It's known to work with Webpack 5.\r\n\r\nExample usage:\r\n\r\n```ts\r\nconst client = new ScrcpyClient(adb);\r\nconst decoder = new WebCodecsDecoder(); // Or `new TinyH264Decoder()`\r\nclient.onSizeChanged(size => decoder.setSize(size));\r\nclient.onVideoData(data => decoder.feed(data));\r\nclient.start(serverPath, serverVersion, new ScrcpyOptionsX_XX({\r\n ...options,\r\n codecOptions: new CodecOptions({\r\n profile: decoder.maxProfile,\r\n level: decoder.maxLevel,\r\n }),\r\n}));\r\ndocument.body.appendChild(decoder.element);\r\n```\r\n"
|
|
60
|
+
"readme": "# @yume-chan/scrcpy\r\n\r\nTypeScript implementation of [Scrcpy](https://github.com/Genymobile/scrcpy) client.\r\n\r\nIt uses the official Scrcpy server releases.\r\n\r\n**WARNING:** The public API is UNSTABLE. If you have any questions, please open an issue.\r\n\r\n## Download Server Binary\r\n\r\nThis package has a script `fetch-scrcpy-server` to help you download the official server binary.\r\n\r\nThe server binary is subject to [Apache License 2.0](https://github.com/Genymobile/scrcpy/blob/master/LICENSE).\r\n\r\nUsage:\r\n\r\n```\r\n$ npx fetch-scrcpy-server <version>\r\n```\r\n\r\nFor example:\r\n\r\n```\r\n$ npx fetch-scrcpy-server 1.21\r\n```\r\n\r\nYou can also add it to the `postinstall` script of your `package.json` so it will run automatically when you do `npm install`:\r\n\r\n```json\r\n\"scripts\": {\r\n \"postinstall\": \"fetch-scrcpy-server 1.21\",\r\n},\r\n```\r\n\r\nIt will download the binary to `bin/scrcpy` and write the version string to `bin/version.js`. You can import the version string with\r\n\r\n```js\r\nimport SCRCPY_SERVER_VERSION from '@yume-chan/scrcpy/bin/version';\r\n```\r\n\r\nAnd import the server binary with [file-loader](https://v4.webpack.js.org/loaders/file-loader/) (Webpack 4) or [Asset Modules](https://webpack.js.org/guides/asset-modules/) (Webpack 5).\r\n\r\n## Option versions\r\n\r\nScrcpy server has no backward compatibility on options input format. Currently the following versions are supported:\r\n\r\n| versions | type |\r\n| --------- | ------------------- |\r\n| 1.16~1.17 | `ScrcpyOptions1_16` |\r\n| 1.18~1.20 | `ScrcpyOptions1_18` |\r\n| 1.21 | `ScrcpyOptions1_21` |\r\n| 1.22 | `ScrcpyOptions1_22` |\r\n| 1.23 | `ScrcpyOptions1_23` |\r\n\r\nYou must use the correct type according to the server version.\r\n\r\n## Video stream\r\n\r\nThe data from `onVideoData` event is a raw H.264 stream. You can process it as you want, or use the following built-in decoders to render it in browsers:\r\n\r\n* WebCodecs decoder: Uses the [WebCodecs API](https://developer.mozilla.org/en-US/docs/Web/API/WebCodecs_API). The video stream will be decoded into `VideoFrame`s and drawn on a 2D canvas.\r\n* TinyH264 decoder: TinyH264 compiles the old Android H.264 software decoder (now deprecated and removed) into WebAssembly, and wrap it in Web Worker to prevent blocking the main thread. The video stream will be decoded into YUV frames, then converted to RGB using a WebGL shader.\r\n\r\n| Name | Chrome | Firefox | Safari | Performance | Supported H.264 profile/level |\r\n| ----------------- | ------ | ------- | ------ | ------------------------------- | ----------------------------- |\r\n| WebCodecs decoder | 94 | No | No | High with Hardware acceleration | High level 5 |\r\n| TinyH264 decoder | 57 | 52 | 11 | Poor | Baseline level 4 |\r\n\r\nTinyH264 decoder needs some extra setup:\r\n\r\n1. `tinyh264`, `yuv-buffer` and `yuv-canvas` packages are peer dependencies. You must install them separately.\r\n2. The bundler you use must support the `new Worker(new URL('./worker.js', import.meta.url))` syntax. It's known to work with Webpack 5.\r\n\r\nExample usage:\r\n\r\n```ts\r\nconst client = new ScrcpyClient(adb);\r\nconst decoder = new WebCodecsDecoder(); // Or `new TinyH264Decoder()`\r\nclient.onSizeChanged(size => decoder.setSize(size));\r\nclient.onVideoData(data => decoder.feed(data));\r\nclient.start(serverPath, serverVersion, new ScrcpyOptionsX_XX({\r\n ...options,\r\n codecOptions: new CodecOptions({\r\n profile: decoder.maxProfile,\r\n level: decoder.maxLevel,\r\n }),\r\n}));\r\ndocument.body.appendChild(decoder.element);\r\n```\r\n"
|
|
61
61
|
}
|
package/src/client.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { AdbBufferedStream,
|
|
1
|
+
import { AbortController, AdbBufferedStream, AdbSubprocessNoneProtocol, DecodeUtf8Stream, InspectStream, ReadableStream, TransformStream, WritableStream, type Adb, type AdbSocket, type AdbSubprocessProtocol, type WritableStreamDefaultWriter } from '@yume-chan/adb';
|
|
2
2
|
import { EventEmitter } from '@yume-chan/event';
|
|
3
3
|
import Struct from '@yume-chan/struct';
|
|
4
|
-
import { AndroidMotionEventAction, ScrcpyControlMessageType, ScrcpyInjectKeyCodeControlMessage, ScrcpyInjectTextControlMessage, ScrcpyInjectTouchControlMessage, type AndroidKeyEventAction } from './message.js';
|
|
4
|
+
import { AndroidMotionEventAction, ScrcpyControlMessageType, ScrcpyInjectKeyCodeControlMessage, ScrcpyInjectTextControlMessage, ScrcpyInjectTouchControlMessage, ScrcpySimpleControlMessage, type AndroidKeyEventAction } from './message.js';
|
|
5
5
|
import type { ScrcpyInjectScrollControlMessage1_22, ScrcpyOptions, VideoStreamPacket } from "./options/index.js";
|
|
6
6
|
|
|
7
7
|
function* splitLines(text: string): Generator<string, void, void> {
|
|
@@ -20,12 +20,87 @@ function* splitLines(text: string): Generator<string, void, void> {
|
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
+
class SplitLinesStream extends TransformStream<string, string>{
|
|
24
|
+
constructor() {
|
|
25
|
+
super({
|
|
26
|
+
transform(chunk, controller) {
|
|
27
|
+
for (const line of splitLines(chunk)) {
|
|
28
|
+
if (line === '') {
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
controller.enqueue(line);
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
class ArrayToStream<T> extends ReadableStream<T>{
|
|
39
|
+
private array!: T[];
|
|
40
|
+
private index = 0;
|
|
41
|
+
|
|
42
|
+
constructor(array: T[]) {
|
|
43
|
+
super({
|
|
44
|
+
start: async () => {
|
|
45
|
+
await Promise.resolve();
|
|
46
|
+
this.array = array;
|
|
47
|
+
},
|
|
48
|
+
pull: (controller) => {
|
|
49
|
+
if (this.index < this.array.length) {
|
|
50
|
+
controller.enqueue(this.array[this.index]!);
|
|
51
|
+
this.index += 1;
|
|
52
|
+
} else {
|
|
53
|
+
controller.close();
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
class ConcatStream<T> extends ReadableStream<T>{
|
|
61
|
+
private streams!: ReadableStream<T>[];
|
|
62
|
+
private index = 0;
|
|
63
|
+
private reader!: ReadableStreamDefaultReader<T>;
|
|
64
|
+
|
|
65
|
+
constructor(...streams: ReadableStream<T>[]) {
|
|
66
|
+
super({
|
|
67
|
+
start: async (controller) => {
|
|
68
|
+
await Promise.resolve();
|
|
69
|
+
|
|
70
|
+
this.streams = streams;
|
|
71
|
+
this.advance(controller);
|
|
72
|
+
},
|
|
73
|
+
pull: async (controller) => {
|
|
74
|
+
const result = await this.reader.read();
|
|
75
|
+
if (!result.done) {
|
|
76
|
+
controller.enqueue(result.value);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
this.advance(controller);
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
private advance(controller: ReadableStreamDefaultController<T>) {
|
|
85
|
+
if (this.index < this.streams.length) {
|
|
86
|
+
this.reader = this.streams[this.index]!.getReader();
|
|
87
|
+
this.index += 1;
|
|
88
|
+
} else {
|
|
89
|
+
controller.close();
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
23
94
|
const ClipboardMessage =
|
|
24
95
|
new Struct()
|
|
25
96
|
.uint32('length')
|
|
26
97
|
.string('content', { lengthField: 'length' });
|
|
27
98
|
|
|
28
99
|
export class ScrcpyClient {
|
|
100
|
+
/**
|
|
101
|
+
* This method will modify the given `options`,
|
|
102
|
+
* so don't reuse it elsewhere.
|
|
103
|
+
*/
|
|
29
104
|
public static async getEncoders(
|
|
30
105
|
adb: Adb,
|
|
31
106
|
path: string,
|
|
@@ -37,6 +112,8 @@ export class ScrcpyClient {
|
|
|
37
112
|
options.value.encoderName = '_';
|
|
38
113
|
// Disable control for faster connection in 1.22+
|
|
39
114
|
options.value.control = false;
|
|
115
|
+
options.value.sendDeviceMeta = false;
|
|
116
|
+
options.value.sendDummyByte = false;
|
|
40
117
|
|
|
41
118
|
// Scrcpy server will open connections, before initializing encoder
|
|
42
119
|
// Thus although an invalid encoder name is given, the start process will success
|
|
@@ -56,6 +133,45 @@ export class ScrcpyClient {
|
|
|
56
133
|
return encoders;
|
|
57
134
|
}
|
|
58
135
|
|
|
136
|
+
/**
|
|
137
|
+
* This method will modify the given `options`,
|
|
138
|
+
* so don't reuse it elsewhere.
|
|
139
|
+
*/
|
|
140
|
+
public static async getDisplays(
|
|
141
|
+
adb: Adb,
|
|
142
|
+
path: string,
|
|
143
|
+
version: string,
|
|
144
|
+
options: ScrcpyOptions<any>
|
|
145
|
+
): Promise<number[]> {
|
|
146
|
+
// Similar to `getEncoders`, pass an invalid option and parse the output
|
|
147
|
+
options.value.displayId = -1;
|
|
148
|
+
|
|
149
|
+
options.value.control = false;
|
|
150
|
+
options.value.sendDeviceMeta = false;
|
|
151
|
+
options.value.sendDummyByte = false;
|
|
152
|
+
|
|
153
|
+
try {
|
|
154
|
+
// Server will exit before opening connections when an invalid display id was given.
|
|
155
|
+
await ScrcpyClient.start(adb, path, version, options);
|
|
156
|
+
} catch (e) {
|
|
157
|
+
if (e instanceof Error) {
|
|
158
|
+
const output = (e as any).output as string[];
|
|
159
|
+
|
|
160
|
+
const displayIdRegex = /\s+scrcpy --display (\d+)/;
|
|
161
|
+
const displays: number[] = [];
|
|
162
|
+
for (const line of output) {
|
|
163
|
+
const match = line.match(displayIdRegex);
|
|
164
|
+
if (match) {
|
|
165
|
+
displays.push(Number.parseInt(match[1]!, 10));
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return displays;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
throw new Error('failed to get displays');
|
|
173
|
+
}
|
|
174
|
+
|
|
59
175
|
public static async start(
|
|
60
176
|
adb: Adb,
|
|
61
177
|
path: string,
|
|
@@ -81,21 +197,54 @@ export class ScrcpyClient {
|
|
|
81
197
|
{
|
|
82
198
|
// Scrcpy server doesn't split stdout and stderr,
|
|
83
199
|
// so disable Shell Protocol to simplify processing
|
|
84
|
-
protocols: [
|
|
200
|
+
protocols: [AdbSubprocessNoneProtocol],
|
|
85
201
|
}
|
|
86
202
|
);
|
|
87
203
|
|
|
204
|
+
const stdout = process.stdout
|
|
205
|
+
.pipeThrough(new DecodeUtf8Stream())
|
|
206
|
+
.pipeThrough(new SplitLinesStream());
|
|
207
|
+
|
|
208
|
+
// Read stdout, otherwise `process.exit` won't resolve.
|
|
209
|
+
const output: string[] = [];
|
|
210
|
+
const abortController = new AbortController();
|
|
211
|
+
const pipe = stdout
|
|
212
|
+
.pipeTo(new WritableStream({
|
|
213
|
+
write(chunk) {
|
|
214
|
+
output.push(chunk);
|
|
215
|
+
}
|
|
216
|
+
}), {
|
|
217
|
+
signal: abortController.signal,
|
|
218
|
+
preventCancel: true,
|
|
219
|
+
})
|
|
220
|
+
.catch(() => { });
|
|
221
|
+
|
|
88
222
|
const result = await Promise.race([
|
|
89
223
|
process.exit,
|
|
90
224
|
connection.getStreams(),
|
|
91
225
|
]);
|
|
92
226
|
|
|
93
227
|
if (typeof result === 'number') {
|
|
94
|
-
|
|
228
|
+
const error = new Error('scrcpy server exited prematurely');
|
|
229
|
+
(error as any).output = output;
|
|
230
|
+
throw error;
|
|
95
231
|
}
|
|
96
232
|
|
|
233
|
+
abortController.abort();
|
|
234
|
+
await pipe;
|
|
235
|
+
|
|
97
236
|
const [videoStream, controlStream] = result;
|
|
98
|
-
return new ScrcpyClient(
|
|
237
|
+
return new ScrcpyClient(
|
|
238
|
+
adb,
|
|
239
|
+
options,
|
|
240
|
+
process,
|
|
241
|
+
new ConcatStream(
|
|
242
|
+
new ArrayToStream(output),
|
|
243
|
+
stdout,
|
|
244
|
+
),
|
|
245
|
+
videoStream,
|
|
246
|
+
controlStream
|
|
247
|
+
);
|
|
99
248
|
} catch (e) {
|
|
100
249
|
await process?.kill();
|
|
101
250
|
throw e;
|
|
@@ -135,28 +284,18 @@ export class ScrcpyClient {
|
|
|
135
284
|
adb: Adb,
|
|
136
285
|
options: ScrcpyOptions<any>,
|
|
137
286
|
process: AdbSubprocessProtocol,
|
|
138
|
-
|
|
287
|
+
stdout: ReadableStream<string>,
|
|
288
|
+
videoStream: AdbSocket,
|
|
139
289
|
controlStream: AdbSocket | undefined,
|
|
140
290
|
) {
|
|
141
291
|
this._adb = adb;
|
|
142
292
|
this.options = options;
|
|
143
293
|
this.process = process;
|
|
144
294
|
|
|
145
|
-
this._stdout =
|
|
146
|
-
.pipeThrough(new DecodeUtf8Stream())
|
|
147
|
-
.pipeThrough(new TransformStream({
|
|
148
|
-
transform(chunk, controller) {
|
|
149
|
-
for (const line of splitLines(chunk)) {
|
|
150
|
-
if (line === '') {
|
|
151
|
-
continue;
|
|
152
|
-
}
|
|
153
|
-
controller.enqueue(line);
|
|
154
|
-
}
|
|
155
|
-
},
|
|
156
|
-
}));
|
|
295
|
+
this._stdout = stdout;
|
|
157
296
|
|
|
158
|
-
this._videoStream =
|
|
159
|
-
.
|
|
297
|
+
this._videoStream = videoStream.readable
|
|
298
|
+
.pipeThrough(options.createVideoStreamTransformer())
|
|
160
299
|
.pipeThrough(new InspectStream(packet => {
|
|
161
300
|
if (packet.type === 'configuration') {
|
|
162
301
|
this._screenWidth = packet.data.croppedWidth;
|
|
@@ -195,12 +334,21 @@ export class ScrcpyClient {
|
|
|
195
334
|
return this._controlStreamWriter;
|
|
196
335
|
}
|
|
197
336
|
|
|
337
|
+
private getControlMessageTypeValue(type: ScrcpyControlMessageType) {
|
|
338
|
+
const list = this.options.getControlMessageTypes();
|
|
339
|
+
const index = list.indexOf(type);
|
|
340
|
+
if (index === -1) {
|
|
341
|
+
throw new Error('Not supported');
|
|
342
|
+
}
|
|
343
|
+
return index;
|
|
344
|
+
}
|
|
345
|
+
|
|
198
346
|
public async injectKeyCode(message: Omit<ScrcpyInjectKeyCodeControlMessage, 'type'>) {
|
|
199
347
|
const controlStream = this.checkControlStream('injectKeyCode');
|
|
200
348
|
|
|
201
349
|
await controlStream.write(ScrcpyInjectKeyCodeControlMessage.serialize({
|
|
202
350
|
...message,
|
|
203
|
-
type: ScrcpyControlMessageType.InjectKeycode,
|
|
351
|
+
type: this.getControlMessageTypeValue(ScrcpyControlMessageType.InjectKeycode),
|
|
204
352
|
}));
|
|
205
353
|
}
|
|
206
354
|
|
|
@@ -208,7 +356,7 @@ export class ScrcpyClient {
|
|
|
208
356
|
const controlStream = this.checkControlStream('injectText');
|
|
209
357
|
|
|
210
358
|
await controlStream.write(ScrcpyInjectTextControlMessage.serialize({
|
|
211
|
-
type: ScrcpyControlMessageType.InjectText,
|
|
359
|
+
type: this.getControlMessageTypeValue(ScrcpyControlMessageType.InjectText),
|
|
212
360
|
text,
|
|
213
361
|
}));
|
|
214
362
|
}
|
|
@@ -234,7 +382,7 @@ export class ScrcpyClient {
|
|
|
234
382
|
this.lastTouchMessage = now;
|
|
235
383
|
await controlStream.write(ScrcpyInjectTouchControlMessage.serialize({
|
|
236
384
|
...message,
|
|
237
|
-
type: ScrcpyControlMessageType.InjectTouch,
|
|
385
|
+
type: this.getControlMessageTypeValue(ScrcpyControlMessageType.InjectTouch),
|
|
238
386
|
screenWidth: this.screenWidth,
|
|
239
387
|
screenHeight: this.screenHeight,
|
|
240
388
|
}));
|
|
@@ -249,7 +397,7 @@ export class ScrcpyClient {
|
|
|
249
397
|
|
|
250
398
|
const buffer = this.options!.serializeInjectScrollControlMessage({
|
|
251
399
|
...message,
|
|
252
|
-
type: ScrcpyControlMessageType.InjectScroll,
|
|
400
|
+
type: this.getControlMessageTypeValue(ScrcpyControlMessageType.InjectScroll),
|
|
253
401
|
screenWidth: this.screenWidth,
|
|
254
402
|
screenHeight: this.screenHeight,
|
|
255
403
|
});
|
|
@@ -260,7 +408,7 @@ export class ScrcpyClient {
|
|
|
260
408
|
const controlStream = this.checkControlStream('pressBackOrTurnOnScreen');
|
|
261
409
|
|
|
262
410
|
const buffer = this.options!.serializeBackOrScreenOnControlMessage({
|
|
263
|
-
type: ScrcpyControlMessageType.BackOrScreenOn,
|
|
411
|
+
type: this.getControlMessageTypeValue(ScrcpyControlMessageType.BackOrScreenOn),
|
|
264
412
|
action,
|
|
265
413
|
});
|
|
266
414
|
if (buffer) {
|
|
@@ -268,6 +416,18 @@ export class ScrcpyClient {
|
|
|
268
416
|
}
|
|
269
417
|
}
|
|
270
418
|
|
|
419
|
+
private async sendSimpleControlMessage(type: ScrcpyControlMessageType, name: string) {
|
|
420
|
+
const controlStream = this.checkControlStream(name);
|
|
421
|
+
const buffer = ScrcpySimpleControlMessage.serialize({
|
|
422
|
+
type: this.getControlMessageTypeValue(type),
|
|
423
|
+
});
|
|
424
|
+
await controlStream.write(buffer);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
public async rotateDevice() {
|
|
428
|
+
await this.sendSimpleControlMessage(ScrcpyControlMessageType.RotateDevice, 'rotateDevice');
|
|
429
|
+
}
|
|
430
|
+
|
|
271
431
|
public async close() {
|
|
272
432
|
// No need to close streams. Kill the process will destroy them from the other side.
|
|
273
433
|
await this.process?.kill();
|