mirror of
https://github.com/yume-chan/ya-webadb.git
synced 2025-10-03 01:39:21 +02:00
feat(adb-scrcpy): infer type of videoStream
from video
option
This commit is contained in:
parent
02f5bd5929
commit
24b65fd2c1
61 changed files with 653 additions and 336 deletions
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
|
@ -115,7 +115,7 @@
|
||||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||||
},
|
},
|
||||||
"explorer.sortOrder": "mixed",
|
"explorer.sortOrder": "mixed",
|
||||||
"prettier.prettierPath": "./node_modules/prettier/index.cjs",
|
"prettier.prettierPath": "./toolchain/eslint-config/node_modules/prettier/index.cjs",
|
||||||
"cSpell.numSuggestions": 4,
|
"cSpell.numSuggestions": 4,
|
||||||
"cSpell.ignoreRegExpList": [
|
"cSpell.ignoreRegExpList": [
|
||||||
"0x[0-9a-f_]+"
|
"0x[0-9a-f_]+"
|
||||||
|
|
|
@ -29,7 +29,8 @@
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsc -b tsconfig.build.json",
|
"build": "tsc -b tsconfig.build.json",
|
||||||
"lint": "run-eslint && prettier src/**/*.ts --write --tab-width 4",
|
"lint": "run-eslint && prettier src/**/*.ts --write --tab-width 4",
|
||||||
"prepublishOnly": "npm run build"
|
"prepublishOnly": "npm run build",
|
||||||
|
"test": "run-test"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@yume-chan/adb": "workspace:^",
|
"@yume-chan/adb": "workspace:^",
|
||||||
|
@ -40,7 +41,9 @@
|
||||||
"@yume-chan/struct": "workspace:^"
|
"@yume-chan/struct": "workspace:^"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/node": "^22.10.10",
|
||||||
"@yume-chan/eslint-config": "workspace:^",
|
"@yume-chan/eslint-config": "workspace:^",
|
||||||
|
"@yume-chan/test-runner": "workspace:^",
|
||||||
"@yume-chan/tsconfig": "workspace:^",
|
"@yume-chan/tsconfig": "workspace:^",
|
||||||
"prettier": "^3.4.2",
|
"prettier": "^3.4.2",
|
||||||
"typescript": "^5.7.3"
|
"typescript": "^5.7.3"
|
||||||
|
|
|
@ -15,7 +15,7 @@ export function createConnection(
|
||||||
adb: Adb,
|
adb: Adb,
|
||||||
options: Required<
|
options: Required<
|
||||||
Pick<
|
Pick<
|
||||||
ScrcpyOptions2_1.Init,
|
ScrcpyOptions2_1.Init<boolean>,
|
||||||
| "tunnelForward"
|
| "tunnelForward"
|
||||||
| "control"
|
| "control"
|
||||||
| "sendDummyByte"
|
| "sendDummyByte"
|
||||||
|
|
|
@ -10,8 +10,10 @@ import {
|
||||||
import type { AdbScrcpyConnection } from "../connection.js";
|
import type { AdbScrcpyConnection } from "../connection.js";
|
||||||
import { AdbScrcpyOptions } from "../types.js";
|
import { AdbScrcpyOptions } from "../types.js";
|
||||||
|
|
||||||
export class AdbScrcpyOptions2_1 extends AdbScrcpyOptions<ScrcpyOptions2_1.Init> {
|
export class AdbScrcpyOptions2_1<
|
||||||
constructor(init: ScrcpyOptions2_1.Init, version?: string) {
|
TVideo extends boolean,
|
||||||
|
> extends AdbScrcpyOptions<ScrcpyOptions2_1.Init<TVideo>> {
|
||||||
|
constructor(init: ScrcpyOptions2_1.Init<TVideo>, version?: string) {
|
||||||
super(new ScrcpyOptions2_1(init, version));
|
super(new ScrcpyOptions2_1(init, version));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,5 +31,6 @@ export class AdbScrcpyOptions2_1 extends AdbScrcpyOptions<ScrcpyOptions2_1.Init>
|
||||||
}
|
}
|
||||||
|
|
||||||
export namespace AdbScrcpyOptions2_1 {
|
export namespace AdbScrcpyOptions2_1 {
|
||||||
export type Init = ScrcpyOptions2_1.Init;
|
export type Init<TVideo extends boolean = boolean> =
|
||||||
|
ScrcpyOptions2_1.Init<TVideo>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,8 +10,10 @@ import {
|
||||||
import type { AdbScrcpyConnection } from "./connection.js";
|
import type { AdbScrcpyConnection } from "./connection.js";
|
||||||
import { AdbScrcpyOptions } from "./types.js";
|
import { AdbScrcpyOptions } from "./types.js";
|
||||||
|
|
||||||
export class AdbScrcpyOptions2_1_1 extends AdbScrcpyOptions<ScrcpyOptions2_1_1.Init> {
|
export class AdbScrcpyOptions2_1_1<
|
||||||
constructor(init: ScrcpyOptions2_1_1.Init, version?: string) {
|
TVideo extends boolean,
|
||||||
|
> extends AdbScrcpyOptions<ScrcpyOptions2_1_1.Init<TVideo>> {
|
||||||
|
constructor(init: ScrcpyOptions2_1_1.Init<TVideo>, version?: string) {
|
||||||
super(new ScrcpyOptions2_1_1(init, version));
|
super(new ScrcpyOptions2_1_1(init, version));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,5 +31,6 @@ export class AdbScrcpyOptions2_1_1 extends AdbScrcpyOptions<ScrcpyOptions2_1_1.I
|
||||||
}
|
}
|
||||||
|
|
||||||
export namespace AdbScrcpyOptions2_1_1 {
|
export namespace AdbScrcpyOptions2_1_1 {
|
||||||
export type Init = ScrcpyOptions2_1_1.Init;
|
export type Init<TVideo extends boolean = boolean> =
|
||||||
|
ScrcpyOptions2_1_1.Init<TVideo>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,8 +10,10 @@ import {
|
||||||
import type { AdbScrcpyConnection } from "./connection.js";
|
import type { AdbScrcpyConnection } from "./connection.js";
|
||||||
import { AdbScrcpyOptions } from "./types.js";
|
import { AdbScrcpyOptions } from "./types.js";
|
||||||
|
|
||||||
export class AdbScrcpyOptions2_2 extends AdbScrcpyOptions<ScrcpyOptions2_2.Init> {
|
export class AdbScrcpyOptions2_2<
|
||||||
constructor(init: ScrcpyOptions2_2.Init, version?: string) {
|
TVideo extends boolean,
|
||||||
|
> extends AdbScrcpyOptions<ScrcpyOptions2_2.Init<TVideo>> {
|
||||||
|
constructor(init: ScrcpyOptions2_2.Init<TVideo>, version?: string) {
|
||||||
super(new ScrcpyOptions2_2(init, version));
|
super(new ScrcpyOptions2_2(init, version));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,5 +31,6 @@ export class AdbScrcpyOptions2_2 extends AdbScrcpyOptions<ScrcpyOptions2_2.Init>
|
||||||
}
|
}
|
||||||
|
|
||||||
export namespace AdbScrcpyOptions2_2 {
|
export namespace AdbScrcpyOptions2_2 {
|
||||||
export type Init = ScrcpyOptions2_2.Init;
|
export type Init<TVideo extends boolean = boolean> =
|
||||||
|
ScrcpyOptions2_2.Init<TVideo>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,8 +10,10 @@ import {
|
||||||
import type { AdbScrcpyConnection } from "./connection.js";
|
import type { AdbScrcpyConnection } from "./connection.js";
|
||||||
import { AdbScrcpyOptions } from "./types.js";
|
import { AdbScrcpyOptions } from "./types.js";
|
||||||
|
|
||||||
export class AdbScrcpyOptions2_3 extends AdbScrcpyOptions<ScrcpyOptions2_3.Init> {
|
export class AdbScrcpyOptions2_3<
|
||||||
constructor(init: ScrcpyOptions2_3.Init, version?: string) {
|
TVideo extends boolean,
|
||||||
|
> extends AdbScrcpyOptions<ScrcpyOptions2_3.Init<TVideo>> {
|
||||||
|
constructor(init: ScrcpyOptions2_3.Init<TVideo>, version?: string) {
|
||||||
super(new ScrcpyOptions2_3(init, version));
|
super(new ScrcpyOptions2_3(init, version));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,5 +31,6 @@ export class AdbScrcpyOptions2_3 extends AdbScrcpyOptions<ScrcpyOptions2_3.Init>
|
||||||
}
|
}
|
||||||
|
|
||||||
export namespace AdbScrcpyOptions2_3 {
|
export namespace AdbScrcpyOptions2_3 {
|
||||||
export type Init = ScrcpyOptions2_3.Init;
|
export type Init<TVideo extends boolean = boolean> =
|
||||||
|
ScrcpyOptions2_3.Init<TVideo>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,8 +10,10 @@ import {
|
||||||
import type { AdbScrcpyConnection } from "./connection.js";
|
import type { AdbScrcpyConnection } from "./connection.js";
|
||||||
import { AdbScrcpyOptions } from "./types.js";
|
import { AdbScrcpyOptions } from "./types.js";
|
||||||
|
|
||||||
export class AdbScrcpyOptions2_3_1 extends AdbScrcpyOptions<ScrcpyOptions2_3_1.Init> {
|
export class AdbScrcpyOptions2_3_1<
|
||||||
constructor(init: ScrcpyOptions2_3_1.Init, version?: string) {
|
TVideo extends boolean,
|
||||||
|
> extends AdbScrcpyOptions<ScrcpyOptions2_3_1.Init<TVideo>> {
|
||||||
|
constructor(init: ScrcpyOptions2_3_1.Init<TVideo>, version?: string) {
|
||||||
super(new ScrcpyOptions2_3_1(init, version));
|
super(new ScrcpyOptions2_3_1(init, version));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,5 +31,6 @@ export class AdbScrcpyOptions2_3_1 extends AdbScrcpyOptions<ScrcpyOptions2_3_1.I
|
||||||
}
|
}
|
||||||
|
|
||||||
export namespace AdbScrcpyOptions2_3_1 {
|
export namespace AdbScrcpyOptions2_3_1 {
|
||||||
export type Init = ScrcpyOptions2_3_1.Init;
|
export type Init<TVideo extends boolean = boolean> =
|
||||||
|
ScrcpyOptions2_3_1.Init<TVideo>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,8 +10,10 @@ import {
|
||||||
import type { AdbScrcpyConnection } from "./connection.js";
|
import type { AdbScrcpyConnection } from "./connection.js";
|
||||||
import { AdbScrcpyOptions } from "./types.js";
|
import { AdbScrcpyOptions } from "./types.js";
|
||||||
|
|
||||||
export class AdbScrcpyOptions2_4 extends AdbScrcpyOptions<ScrcpyOptions2_4.Init> {
|
export class AdbScrcpyOptions2_4<
|
||||||
constructor(init: ScrcpyOptions2_4.Init, version?: string) {
|
TVideo extends boolean,
|
||||||
|
> extends AdbScrcpyOptions<ScrcpyOptions2_4.Init<TVideo>> {
|
||||||
|
constructor(init: ScrcpyOptions2_4.Init<TVideo>, version?: string) {
|
||||||
super(new ScrcpyOptions2_4(init, version));
|
super(new ScrcpyOptions2_4(init, version));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,5 +31,6 @@ export class AdbScrcpyOptions2_4 extends AdbScrcpyOptions<ScrcpyOptions2_4.Init>
|
||||||
}
|
}
|
||||||
|
|
||||||
export namespace AdbScrcpyOptions2_4 {
|
export namespace AdbScrcpyOptions2_4 {
|
||||||
export type Init = ScrcpyOptions2_4.Init;
|
export type Init<TVideo extends boolean = boolean> =
|
||||||
|
ScrcpyOptions2_4.Init<TVideo>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,8 +10,10 @@ import {
|
||||||
import type { AdbScrcpyConnection } from "./connection.js";
|
import type { AdbScrcpyConnection } from "./connection.js";
|
||||||
import { AdbScrcpyOptions } from "./types.js";
|
import { AdbScrcpyOptions } from "./types.js";
|
||||||
|
|
||||||
export class AdbScrcpyOptions2_5 extends AdbScrcpyOptions<ScrcpyOptions2_5.Init> {
|
export class AdbScrcpyOptions2_5<
|
||||||
constructor(init: ScrcpyOptions2_5.Init, version?: string) {
|
TVideo extends boolean,
|
||||||
|
> extends AdbScrcpyOptions<ScrcpyOptions2_5.Init<TVideo>> {
|
||||||
|
constructor(init: ScrcpyOptions2_5.Init<TVideo>, version?: string) {
|
||||||
super(new ScrcpyOptions2_5(init, version));
|
super(new ScrcpyOptions2_5(init, version));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,5 +31,6 @@ export class AdbScrcpyOptions2_5 extends AdbScrcpyOptions<ScrcpyOptions2_5.Init>
|
||||||
}
|
}
|
||||||
|
|
||||||
export namespace AdbScrcpyOptions2_5 {
|
export namespace AdbScrcpyOptions2_5 {
|
||||||
export type Init = ScrcpyOptions2_5.Init;
|
export type Init<TVideo extends boolean = boolean> =
|
||||||
|
ScrcpyOptions2_5.Init<TVideo>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,8 +10,10 @@ import {
|
||||||
import type { AdbScrcpyConnection } from "./connection.js";
|
import type { AdbScrcpyConnection } from "./connection.js";
|
||||||
import { AdbScrcpyOptions } from "./types.js";
|
import { AdbScrcpyOptions } from "./types.js";
|
||||||
|
|
||||||
export class AdbScrcpyOptions2_6 extends AdbScrcpyOptions<ScrcpyOptions2_6.Init> {
|
export class AdbScrcpyOptions2_6<
|
||||||
constructor(init: ScrcpyOptions2_6.Init, version?: string) {
|
TVideo extends boolean,
|
||||||
|
> extends AdbScrcpyOptions<ScrcpyOptions2_6.Init<TVideo>> {
|
||||||
|
constructor(init: ScrcpyOptions2_6.Init<TVideo>, version?: string) {
|
||||||
super(new ScrcpyOptions2_6(init, version));
|
super(new ScrcpyOptions2_6(init, version));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,5 +31,6 @@ export class AdbScrcpyOptions2_6 extends AdbScrcpyOptions<ScrcpyOptions2_6.Init>
|
||||||
}
|
}
|
||||||
|
|
||||||
export namespace AdbScrcpyOptions2_6 {
|
export namespace AdbScrcpyOptions2_6 {
|
||||||
export type Init = ScrcpyOptions2_6.Init;
|
export type Init<TVideo extends boolean = boolean> =
|
||||||
|
ScrcpyOptions2_6.Init<TVideo>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,8 +10,10 @@ import {
|
||||||
import type { AdbScrcpyConnection } from "./connection.js";
|
import type { AdbScrcpyConnection } from "./connection.js";
|
||||||
import { AdbScrcpyOptions } from "./types.js";
|
import { AdbScrcpyOptions } from "./types.js";
|
||||||
|
|
||||||
export class AdbScrcpyOptions2_7 extends AdbScrcpyOptions<ScrcpyOptions2_7.Init> {
|
export class AdbScrcpyOptions2_7<
|
||||||
constructor(init: ScrcpyOptions2_7.Init, version?: string) {
|
TVideo extends boolean,
|
||||||
|
> extends AdbScrcpyOptions<ScrcpyOptions2_7.Init<TVideo>> {
|
||||||
|
constructor(init: ScrcpyOptions2_7.Init<TVideo>, version?: string) {
|
||||||
super(new ScrcpyOptions2_7(init, version));
|
super(new ScrcpyOptions2_7(init, version));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,5 +31,6 @@ export class AdbScrcpyOptions2_7 extends AdbScrcpyOptions<ScrcpyOptions2_7.Init>
|
||||||
}
|
}
|
||||||
|
|
||||||
export namespace AdbScrcpyOptions2_7 {
|
export namespace AdbScrcpyOptions2_7 {
|
||||||
export type Init = ScrcpyOptions2_7.Init;
|
export type Init<TVideo extends boolean = boolean> =
|
||||||
|
ScrcpyOptions2_7.Init<TVideo>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,8 +10,10 @@ import {
|
||||||
import type { AdbScrcpyConnection } from "./connection.js";
|
import type { AdbScrcpyConnection } from "./connection.js";
|
||||||
import { AdbScrcpyOptions } from "./types.js";
|
import { AdbScrcpyOptions } from "./types.js";
|
||||||
|
|
||||||
export class AdbScrcpyOptions3_0 extends AdbScrcpyOptions<ScrcpyOptions3_0.Init> {
|
export class AdbScrcpyOptions3_0<
|
||||||
constructor(init: ScrcpyOptions3_0.Init, version?: string) {
|
TVideo extends boolean,
|
||||||
|
> extends AdbScrcpyOptions<ScrcpyOptions3_0.Init<TVideo>> {
|
||||||
|
constructor(init: ScrcpyOptions3_0.Init<TVideo>, version?: string) {
|
||||||
super(new ScrcpyOptions3_0(init, version));
|
super(new ScrcpyOptions3_0(init, version));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,5 +31,6 @@ export class AdbScrcpyOptions3_0 extends AdbScrcpyOptions<ScrcpyOptions3_0.Init>
|
||||||
}
|
}
|
||||||
|
|
||||||
export namespace AdbScrcpyOptions3_0 {
|
export namespace AdbScrcpyOptions3_0 {
|
||||||
export type Init = ScrcpyOptions3_0.Init;
|
export type Init<TVideo extends boolean = boolean> =
|
||||||
|
ScrcpyOptions3_0.Init<TVideo>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,8 +10,10 @@ import {
|
||||||
import type { AdbScrcpyConnection } from "./connection.js";
|
import type { AdbScrcpyConnection } from "./connection.js";
|
||||||
import { AdbScrcpyOptions } from "./types.js";
|
import { AdbScrcpyOptions } from "./types.js";
|
||||||
|
|
||||||
export class AdbScrcpyOptions3_0_1 extends AdbScrcpyOptions<ScrcpyOptions3_0_1.Init> {
|
export class AdbScrcpyOptions3_0_1<
|
||||||
constructor(init: ScrcpyOptions3_0_1.Init, version?: string) {
|
TVideo extends boolean,
|
||||||
|
> extends AdbScrcpyOptions<ScrcpyOptions3_0_1.Init<TVideo>> {
|
||||||
|
constructor(init: ScrcpyOptions3_0_1.Init<TVideo>, version?: string) {
|
||||||
super(new ScrcpyOptions3_0_1(init, version));
|
super(new ScrcpyOptions3_0_1(init, version));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,5 +31,6 @@ export class AdbScrcpyOptions3_0_1 extends AdbScrcpyOptions<ScrcpyOptions3_0_1.I
|
||||||
}
|
}
|
||||||
|
|
||||||
export namespace AdbScrcpyOptions3_0_1 {
|
export namespace AdbScrcpyOptions3_0_1 {
|
||||||
export type Init = ScrcpyOptions3_0_1.Init;
|
export type Init<TVideo extends boolean = boolean> =
|
||||||
|
ScrcpyOptions3_0_1.Init<TVideo>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,8 +10,10 @@ import {
|
||||||
import type { AdbScrcpyConnection } from "./connection.js";
|
import type { AdbScrcpyConnection } from "./connection.js";
|
||||||
import { AdbScrcpyOptions } from "./types.js";
|
import { AdbScrcpyOptions } from "./types.js";
|
||||||
|
|
||||||
export class AdbScrcpyOptions3_0_2 extends AdbScrcpyOptions<ScrcpyOptions3_0_2.Init> {
|
export class AdbScrcpyOptions3_0_2<
|
||||||
constructor(init: ScrcpyOptions3_0_2.Init, version?: string) {
|
TVideo extends boolean,
|
||||||
|
> extends AdbScrcpyOptions<ScrcpyOptions3_0_2.Init<TVideo>> {
|
||||||
|
constructor(init: ScrcpyOptions3_0_2.Init<TVideo>, version?: string) {
|
||||||
super(new ScrcpyOptions3_0_2(init, version));
|
super(new ScrcpyOptions3_0_2(init, version));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,5 +31,6 @@ export class AdbScrcpyOptions3_0_2 extends AdbScrcpyOptions<ScrcpyOptions3_0_2.I
|
||||||
}
|
}
|
||||||
|
|
||||||
export namespace AdbScrcpyOptions3_0_2 {
|
export namespace AdbScrcpyOptions3_0_2 {
|
||||||
export type Init = ScrcpyOptions3_0_2.Init;
|
export type Init<TVideo extends boolean = boolean> =
|
||||||
|
ScrcpyOptions3_0_2.Init<TVideo>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,8 +10,10 @@ import {
|
||||||
import type { AdbScrcpyConnection } from "./connection.js";
|
import type { AdbScrcpyConnection } from "./connection.js";
|
||||||
import { AdbScrcpyOptions } from "./types.js";
|
import { AdbScrcpyOptions } from "./types.js";
|
||||||
|
|
||||||
export class AdbScrcpyOptions3_1 extends AdbScrcpyOptions<ScrcpyOptions3_1.Init> {
|
export class AdbScrcpyOptions3_1<
|
||||||
constructor(init: ScrcpyOptions3_1.Init, version?: string) {
|
TVideo extends boolean,
|
||||||
|
> extends AdbScrcpyOptions<ScrcpyOptions3_1.Init<TVideo>> {
|
||||||
|
constructor(init: ScrcpyOptions3_1.Init<TVideo>, version?: string) {
|
||||||
super(new ScrcpyOptions3_1(init, version));
|
super(new ScrcpyOptions3_1(init, version));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,5 +31,6 @@ export class AdbScrcpyOptions3_1 extends AdbScrcpyOptions<ScrcpyOptions3_1.Init>
|
||||||
}
|
}
|
||||||
|
|
||||||
export namespace AdbScrcpyOptions3_1 {
|
export namespace AdbScrcpyOptions3_1 {
|
||||||
export type Init = ScrcpyOptions3_1.Init;
|
export type Init<TVideo extends boolean = boolean> =
|
||||||
|
ScrcpyOptions3_1.Init<TVideo>;
|
||||||
}
|
}
|
||||||
|
|
154
libraries/adb-scrcpy/src/client.spec.ts
Normal file
154
libraries/adb-scrcpy/src/client.spec.ts
Normal file
|
@ -0,0 +1,154 @@
|
||||||
|
import { describe, it } from "node:test";
|
||||||
|
|
||||||
|
import type { Adb } from "@yume-chan/adb";
|
||||||
|
import { DefaultServerPath } from "@yume-chan/scrcpy";
|
||||||
|
|
||||||
|
import { AdbScrcpyOptions1_15 } from "./1_15/options.js";
|
||||||
|
import { AdbScrcpyOptions2_0 } from "./2_0/options.js";
|
||||||
|
import { AdbScrcpyOptions2_1 } from "./2_1/options.js";
|
||||||
|
import { AdbScrcpyOptions3_1 } from "./3_1.js";
|
||||||
|
import { AdbScrcpyClient } from "./client.js";
|
||||||
|
import type { AdbScrcpyVideoStream } from "./video.js";
|
||||||
|
|
||||||
|
const TypeOnlyTest = false;
|
||||||
|
declare const adb: Adb;
|
||||||
|
|
||||||
|
function expect(value: true): void {
|
||||||
|
void value;
|
||||||
|
}
|
||||||
|
|
||||||
|
function equal<X>(): <Y>(
|
||||||
|
value: Y,
|
||||||
|
) => (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2
|
||||||
|
? true
|
||||||
|
: false {
|
||||||
|
return (() => {}) as never;
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("AdbScrcpyClient", () => {
|
||||||
|
describe("videoStream", () => {
|
||||||
|
it("should have value in lower versions", async () => {
|
||||||
|
if (TypeOnlyTest) {
|
||||||
|
const client = await AdbScrcpyClient.start(
|
||||||
|
adb,
|
||||||
|
DefaultServerPath,
|
||||||
|
new AdbScrcpyOptions1_15({}),
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
equal<Promise<AdbScrcpyVideoStream>>()(client.videoStream),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TypeOnlyTest) {
|
||||||
|
const client = await AdbScrcpyClient.start(
|
||||||
|
adb,
|
||||||
|
DefaultServerPath,
|
||||||
|
new AdbScrcpyOptions2_0({}),
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
equal<Promise<AdbScrcpyVideoStream>>()(client.videoStream),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should have value when video: true", async () => {
|
||||||
|
if (TypeOnlyTest) {
|
||||||
|
const client = await AdbScrcpyClient.start(
|
||||||
|
adb,
|
||||||
|
DefaultServerPath,
|
||||||
|
new AdbScrcpyOptions2_1({ video: true }),
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
equal<Promise<AdbScrcpyVideoStream>>()(client.videoStream),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TypeOnlyTest) {
|
||||||
|
const client = await AdbScrcpyClient.start(
|
||||||
|
adb,
|
||||||
|
DefaultServerPath,
|
||||||
|
new AdbScrcpyOptions3_1({ video: true }),
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
equal<Promise<AdbScrcpyVideoStream>>()(client.videoStream),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should be undefined when video: false", async () => {
|
||||||
|
if (TypeOnlyTest) {
|
||||||
|
const client = await AdbScrcpyClient.start(
|
||||||
|
adb,
|
||||||
|
DefaultServerPath,
|
||||||
|
new AdbScrcpyOptions2_1({ video: false }),
|
||||||
|
);
|
||||||
|
expect(equal<undefined>()(client.videoStream));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TypeOnlyTest) {
|
||||||
|
const client = await AdbScrcpyClient.start(
|
||||||
|
adb,
|
||||||
|
DefaultServerPath,
|
||||||
|
new AdbScrcpyOptions3_1({ video: false }),
|
||||||
|
);
|
||||||
|
expect(equal<undefined>()(client.videoStream));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should be a union when video: undefined", async () => {
|
||||||
|
if (TypeOnlyTest) {
|
||||||
|
const client = await AdbScrcpyClient.start(
|
||||||
|
adb,
|
||||||
|
DefaultServerPath,
|
||||||
|
new AdbScrcpyOptions2_1({}),
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
equal<Promise<AdbScrcpyVideoStream> | undefined>()(
|
||||||
|
client.videoStream,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TypeOnlyTest) {
|
||||||
|
const client = await AdbScrcpyClient.start(
|
||||||
|
adb,
|
||||||
|
DefaultServerPath,
|
||||||
|
new AdbScrcpyOptions3_1({}),
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
equal<Promise<AdbScrcpyVideoStream> | undefined>()(
|
||||||
|
client.videoStream,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should be a union when video: boolean", async () => {
|
||||||
|
if (TypeOnlyTest) {
|
||||||
|
const client = await AdbScrcpyClient.start(
|
||||||
|
adb,
|
||||||
|
DefaultServerPath,
|
||||||
|
new AdbScrcpyOptions2_1({ video: true as boolean }),
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
equal<Promise<AdbScrcpyVideoStream> | undefined>()(
|
||||||
|
client.videoStream,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TypeOnlyTest) {
|
||||||
|
const client = await AdbScrcpyClient.start(
|
||||||
|
adb,
|
||||||
|
DefaultServerPath,
|
||||||
|
new AdbScrcpyOptions3_1({ video: true as boolean }),
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
equal<Promise<AdbScrcpyVideoStream> | undefined>()(
|
||||||
|
client.videoStream,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -11,15 +11,10 @@ import type {
|
||||||
ScrcpyEncoder,
|
ScrcpyEncoder,
|
||||||
ScrcpyMediaStreamPacket,
|
ScrcpyMediaStreamPacket,
|
||||||
ScrcpyOptions1_15,
|
ScrcpyOptions1_15,
|
||||||
ScrcpyVideoStreamMetadata,
|
|
||||||
} from "@yume-chan/scrcpy";
|
} from "@yume-chan/scrcpy";
|
||||||
import {
|
import {
|
||||||
Av1,
|
|
||||||
DefaultServerPath,
|
DefaultServerPath,
|
||||||
ScrcpyControlMessageWriter,
|
ScrcpyControlMessageWriter,
|
||||||
ScrcpyVideoCodecId,
|
|
||||||
h264ParseConfiguration,
|
|
||||||
h265ParseConfiguration,
|
|
||||||
} from "@yume-chan/scrcpy";
|
} from "@yume-chan/scrcpy";
|
||||||
import type {
|
import type {
|
||||||
Consumable,
|
Consumable,
|
||||||
|
@ -30,7 +25,6 @@ import type {
|
||||||
import {
|
import {
|
||||||
AbortController,
|
AbortController,
|
||||||
BufferedReadableStream,
|
BufferedReadableStream,
|
||||||
InspectStream,
|
|
||||||
PushReadableStream,
|
PushReadableStream,
|
||||||
SplitStringStream,
|
SplitStringStream,
|
||||||
TextDecoderStream,
|
TextDecoderStream,
|
||||||
|
@ -40,6 +34,7 @@ import { ExactReadableEndedError } from "@yume-chan/struct";
|
||||||
|
|
||||||
import type { AdbScrcpyConnection } from "./connection.js";
|
import type { AdbScrcpyConnection } from "./connection.js";
|
||||||
import type { AdbScrcpyOptions } from "./types.js";
|
import type { AdbScrcpyOptions } from "./types.js";
|
||||||
|
import { AdbScrcpyVideoStream } from "./video.js";
|
||||||
|
|
||||||
function arrayToStream<T>(array: T[]): ReadableStream<T> {
|
function arrayToStream<T>(array: T[]): ReadableStream<T> {
|
||||||
return new PushReadableStream(async (controller) => {
|
return new PushReadableStream(async (controller) => {
|
||||||
|
@ -73,8 +68,8 @@ export class AdbScrcpyExitedError extends Error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface AdbScrcpyClientInit {
|
interface AdbScrcpyClientInit<TOptions extends AdbScrcpyOptions<object>> {
|
||||||
options: AdbScrcpyOptions<object>;
|
options: TOptions;
|
||||||
process: AdbSubprocessProtocol;
|
process: AdbSubprocessProtocol;
|
||||||
stdout: ReadableStream<string>;
|
stdout: ReadableStream<string>;
|
||||||
|
|
||||||
|
@ -85,11 +80,6 @@ interface AdbScrcpyClientInit {
|
||||||
| undefined;
|
| undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AdbScrcpyVideoStream {
|
|
||||||
stream: ReadableStream<ScrcpyMediaStreamPacket>;
|
|
||||||
metadata: ScrcpyVideoStreamMetadata;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AdbScrcpyAudioStreamSuccessMetadata
|
export interface AdbScrcpyAudioStreamSuccessMetadata
|
||||||
extends Omit<ScrcpyAudioStreamSuccessMetadata, "stream"> {
|
extends Omit<ScrcpyAudioStreamSuccessMetadata, "stream"> {
|
||||||
readonly stream: ReadableStream<ScrcpyMediaStreamPacket>;
|
readonly stream: ReadableStream<ScrcpyMediaStreamPacket>;
|
||||||
|
@ -100,7 +90,7 @@ export type AdbScrcpyAudioStreamMetadata =
|
||||||
| ScrcpyAudioStreamErroredMetadata
|
| ScrcpyAudioStreamErroredMetadata
|
||||||
| AdbScrcpyAudioStreamSuccessMetadata;
|
| AdbScrcpyAudioStreamSuccessMetadata;
|
||||||
|
|
||||||
export class AdbScrcpyClient {
|
export class AdbScrcpyClient<TOptions extends AdbScrcpyOptions<object>> {
|
||||||
static async pushServer(
|
static async pushServer(
|
||||||
adb: Adb,
|
adb: Adb,
|
||||||
file: ReadableStream<MaybeConsumable<Uint8Array>>,
|
file: ReadableStream<MaybeConsumable<Uint8Array>>,
|
||||||
|
@ -117,13 +107,15 @@ export class AdbScrcpyClient {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static async start(
|
static async start<
|
||||||
adb: Adb,
|
TOptions extends AdbScrcpyOptions<
|
||||||
path: string,
|
|
||||||
options: AdbScrcpyOptions<
|
|
||||||
Pick<ScrcpyOptions1_15.Init, "tunnelForward">
|
Pick<ScrcpyOptions1_15.Init, "tunnelForward">
|
||||||
>,
|
>,
|
||||||
) {
|
>(
|
||||||
|
adb: Adb,
|
||||||
|
path: string,
|
||||||
|
options: TOptions,
|
||||||
|
): Promise<AdbScrcpyClient<TOptions>> {
|
||||||
let connection: AdbScrcpyConnection | undefined;
|
let connection: AdbScrcpyConnection | undefined;
|
||||||
let process: AdbSubprocessProtocol | undefined;
|
let process: AdbSubprocessProtocol | undefined;
|
||||||
|
|
||||||
|
@ -239,7 +231,7 @@ export class AdbScrcpyClient {
|
||||||
return options.getDisplays(adb, path);
|
return options.getDisplays(adb, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
#options: AdbScrcpyOptions<object>;
|
#options: TOptions;
|
||||||
#process: AdbSubprocessProtocol;
|
#process: AdbSubprocessProtocol;
|
||||||
|
|
||||||
#stdout: ReadableStream<string>;
|
#stdout: ReadableStream<string>;
|
||||||
|
@ -251,16 +243,6 @@ export class AdbScrcpyClient {
|
||||||
return this.#process.exit;
|
return this.#process.exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
#screenWidth: number | undefined;
|
|
||||||
get screenWidth() {
|
|
||||||
return this.#screenWidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
#screenHeight: number | undefined;
|
|
||||||
get screenHeight() {
|
|
||||||
return this.#screenHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
#videoStream: Promise<AdbScrcpyVideoStream> | undefined;
|
#videoStream: Promise<AdbScrcpyVideoStream> | undefined;
|
||||||
/**
|
/**
|
||||||
* Gets a `Promise` that resolves to the parsed video stream.
|
* Gets a `Promise` that resolves to the parsed video stream.
|
||||||
|
@ -271,8 +253,12 @@ export class AdbScrcpyClient {
|
||||||
* Note: if it's not `undefined`, it must be consumed to prevent
|
* Note: if it's not `undefined`, it must be consumed to prevent
|
||||||
* the connection from being blocked.
|
* the connection from being blocked.
|
||||||
*/
|
*/
|
||||||
get videoStream() {
|
get videoStream(): TOptions["value"] extends { video: infer T }
|
||||||
return this.#videoStream;
|
? T extends false
|
||||||
|
? undefined
|
||||||
|
: Promise<AdbScrcpyVideoStream>
|
||||||
|
: Promise<AdbScrcpyVideoStream> {
|
||||||
|
return this.#videoStream as never;
|
||||||
}
|
}
|
||||||
|
|
||||||
#audioStream: Promise<AdbScrcpyAudioStreamMetadata> | undefined;
|
#audioStream: Promise<AdbScrcpyAudioStreamMetadata> | undefined;
|
||||||
|
@ -312,7 +298,7 @@ export class AdbScrcpyClient {
|
||||||
videoStream,
|
videoStream,
|
||||||
audioStream,
|
audioStream,
|
||||||
controlStream,
|
controlStream,
|
||||||
}: AdbScrcpyClientInit) {
|
}: AdbScrcpyClientInit<TOptions>) {
|
||||||
this.#options = options;
|
this.#options = options;
|
||||||
this.#process = process;
|
this.#process = process;
|
||||||
this.#stdout = stdout;
|
this.#stdout = stdout;
|
||||||
|
@ -358,65 +344,10 @@ export class AdbScrcpyClient {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#configureH264(data: Uint8Array) {
|
|
||||||
const { croppedWidth, croppedHeight } = h264ParseConfiguration(data);
|
|
||||||
|
|
||||||
this.#screenWidth = croppedWidth;
|
|
||||||
this.#screenHeight = croppedHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
#configureH265(data: Uint8Array) {
|
|
||||||
const { croppedWidth, croppedHeight } = h265ParseConfiguration(data);
|
|
||||||
|
|
||||||
this.#screenWidth = croppedWidth;
|
|
||||||
this.#screenHeight = croppedHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
#configureAv1(data: Uint8Array) {
|
|
||||||
const parser = new Av1(data);
|
|
||||||
const sequenceHeader = parser.searchSequenceHeaderObu();
|
|
||||||
if (!sequenceHeader) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { max_frame_width_minus_1, max_frame_height_minus_1 } =
|
|
||||||
sequenceHeader;
|
|
||||||
|
|
||||||
const width = max_frame_width_minus_1 + 1;
|
|
||||||
const height = max_frame_height_minus_1 + 1;
|
|
||||||
|
|
||||||
this.#screenWidth = width;
|
|
||||||
this.#screenHeight = height;
|
|
||||||
}
|
|
||||||
|
|
||||||
async #createVideoStream(initialStream: ReadableStream<Uint8Array>) {
|
async #createVideoStream(initialStream: ReadableStream<Uint8Array>) {
|
||||||
const { stream, metadata } =
|
const { metadata, stream } =
|
||||||
await this.#options.parseVideoStreamMetadata(initialStream);
|
await this.#options.parseVideoStreamMetadata(initialStream);
|
||||||
|
return new AdbScrcpyVideoStream(this.#options, metadata, stream);
|
||||||
return {
|
|
||||||
stream: stream
|
|
||||||
.pipeThrough(this.#options.createMediaStreamTransformer())
|
|
||||||
.pipeThrough(
|
|
||||||
new InspectStream((packet) => {
|
|
||||||
if (packet.type === "configuration") {
|
|
||||||
switch (metadata.codec) {
|
|
||||||
case ScrcpyVideoCodecId.H264:
|
|
||||||
this.#configureH264(packet.data);
|
|
||||||
break;
|
|
||||||
case ScrcpyVideoCodecId.H265:
|
|
||||||
this.#configureH265(packet.data);
|
|
||||||
break;
|
|
||||||
case ScrcpyVideoCodecId.AV1:
|
|
||||||
// AV1 configuration is in normal stream
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else if (metadata.codec === ScrcpyVideoCodecId.AV1) {
|
|
||||||
this.#configureAv1(packet.data);
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
metadata,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async #createAudioStream(
|
async #createAudioStream(
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
import { AdbScrcpyOptions3_1 } from "./3_1.js";
|
import { AdbScrcpyOptions3_1 } from "./3_1.js";
|
||||||
|
|
||||||
export class AdbScrcpyOptionsLatest extends AdbScrcpyOptions3_1 {
|
export class AdbScrcpyOptionsLatest<
|
||||||
constructor(init: AdbScrcpyOptions3_1.Init, version: string) {
|
TVideo extends boolean,
|
||||||
|
> extends AdbScrcpyOptions3_1<TVideo> {
|
||||||
|
constructor(init: AdbScrcpyOptions3_1.Init<TVideo>, version: string) {
|
||||||
super(init, version);
|
super(init, version);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export namespace AdbScrcpyOptionsLatest {
|
export namespace AdbScrcpyOptionsLatest {
|
||||||
export type Init = AdbScrcpyOptions3_1.Init;
|
export type Init<TVideo extends boolean = boolean> =
|
||||||
|
AdbScrcpyOptions3_1.Init<TVideo>;
|
||||||
}
|
}
|
||||||
|
|
108
libraries/adb-scrcpy/src/video.ts
Normal file
108
libraries/adb-scrcpy/src/video.ts
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
import { EventEmitter } from "@yume-chan/event";
|
||||||
|
import type {
|
||||||
|
ScrcpyMediaStreamPacket,
|
||||||
|
ScrcpyVideoStreamMetadata,
|
||||||
|
} from "@yume-chan/scrcpy";
|
||||||
|
import {
|
||||||
|
Av1,
|
||||||
|
h264ParseConfiguration,
|
||||||
|
h265ParseConfiguration,
|
||||||
|
ScrcpyVideoCodecId,
|
||||||
|
} from "@yume-chan/scrcpy";
|
||||||
|
import type { ReadableStream } from "@yume-chan/stream-extra";
|
||||||
|
import { InspectStream } from "@yume-chan/stream-extra";
|
||||||
|
|
||||||
|
import type { AdbScrcpyOptions } from "./types.js";
|
||||||
|
|
||||||
|
export class AdbScrcpyVideoStream {
|
||||||
|
#options: AdbScrcpyOptions<object>;
|
||||||
|
|
||||||
|
#metadata: ScrcpyVideoStreamMetadata;
|
||||||
|
get metadata(): ScrcpyVideoStreamMetadata {
|
||||||
|
return this.#metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
#stream: ReadableStream<ScrcpyMediaStreamPacket>;
|
||||||
|
get stream(): ReadableStream<ScrcpyMediaStreamPacket> {
|
||||||
|
return this.#stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
#sizeChanged = new EventEmitter<{ width: number; height: number }>();
|
||||||
|
get sizeChanged() {
|
||||||
|
return this.#sizeChanged.event;
|
||||||
|
}
|
||||||
|
|
||||||
|
#width: number = 0;
|
||||||
|
get width() {
|
||||||
|
return this.#width;
|
||||||
|
}
|
||||||
|
|
||||||
|
#height: number = 0;
|
||||||
|
get height() {
|
||||||
|
return this.#height;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
options: AdbScrcpyOptions<object>,
|
||||||
|
metadata: ScrcpyVideoStreamMetadata,
|
||||||
|
stream: ReadableStream<Uint8Array>,
|
||||||
|
) {
|
||||||
|
this.#options = options;
|
||||||
|
this.#metadata = metadata;
|
||||||
|
this.#stream = stream
|
||||||
|
.pipeThrough(this.#options.createMediaStreamTransformer())
|
||||||
|
.pipeThrough(
|
||||||
|
new InspectStream((packet) => {
|
||||||
|
if (packet.type === "configuration") {
|
||||||
|
switch (metadata.codec) {
|
||||||
|
case ScrcpyVideoCodecId.H264:
|
||||||
|
this.#configureH264(packet.data);
|
||||||
|
break;
|
||||||
|
case ScrcpyVideoCodecId.H265:
|
||||||
|
this.#configureH265(packet.data);
|
||||||
|
break;
|
||||||
|
case ScrcpyVideoCodecId.AV1:
|
||||||
|
// AV1 configuration is in data packet
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (metadata.codec === ScrcpyVideoCodecId.AV1) {
|
||||||
|
this.#configureAv1(packet.data);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#configureH264(data: Uint8Array) {
|
||||||
|
const { croppedWidth, croppedHeight } = h264ParseConfiguration(data);
|
||||||
|
|
||||||
|
this.#width = croppedWidth;
|
||||||
|
this.#height = croppedHeight;
|
||||||
|
this.#sizeChanged.fire({ width: croppedWidth, height: croppedHeight });
|
||||||
|
}
|
||||||
|
|
||||||
|
#configureH265(data: Uint8Array) {
|
||||||
|
const { croppedWidth, croppedHeight } = h265ParseConfiguration(data);
|
||||||
|
|
||||||
|
this.#width = croppedWidth;
|
||||||
|
this.#height = croppedHeight;
|
||||||
|
this.#sizeChanged.fire({ width: croppedWidth, height: croppedHeight });
|
||||||
|
}
|
||||||
|
|
||||||
|
#configureAv1(data: Uint8Array) {
|
||||||
|
const parser = new Av1(data);
|
||||||
|
const sequenceHeader = parser.searchSequenceHeaderObu();
|
||||||
|
if (!sequenceHeader) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { max_frame_width_minus_1, max_frame_height_minus_1 } =
|
||||||
|
sequenceHeader;
|
||||||
|
|
||||||
|
const width = max_frame_width_minus_1 + 1;
|
||||||
|
const height = max_frame_height_minus_1 + 1;
|
||||||
|
|
||||||
|
this.#width = width;
|
||||||
|
this.#height = height;
|
||||||
|
this.#sizeChanged.fire({ width, height });
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,6 +2,7 @@
|
||||||
"extends": "./tsconfig.build.json",
|
"extends": "./tsconfig.build.json",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"types": [
|
"types": [
|
||||||
|
"node"
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
"exclude": []
|
"exclude": []
|
||||||
|
|
|
@ -50,6 +50,16 @@ export class TinyH264Decoder implements ScrcpyVideoDecoder {
|
||||||
return this.#sizeChanged.event;
|
return this.#sizeChanged.event;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#width: number = 0;
|
||||||
|
get width() {
|
||||||
|
return this.#width;
|
||||||
|
}
|
||||||
|
|
||||||
|
#height: number = 0;
|
||||||
|
get height() {
|
||||||
|
return this.#height;
|
||||||
|
}
|
||||||
|
|
||||||
#frameRendered = 0;
|
#frameRendered = 0;
|
||||||
get framesRendered() {
|
get framesRendered() {
|
||||||
return this.#frameRendered;
|
return this.#frameRendered;
|
||||||
|
@ -124,12 +134,16 @@ export class TinyH264Decoder implements ScrcpyVideoDecoder {
|
||||||
cropLeft,
|
cropLeft,
|
||||||
cropTop,
|
cropTop,
|
||||||
} = h264ParseConfiguration(data);
|
} = h264ParseConfiguration(data);
|
||||||
|
|
||||||
|
this.#width = croppedWidth;
|
||||||
|
this.#height = croppedHeight;
|
||||||
this.#sizeChanged.fire({
|
this.#sizeChanged.fire({
|
||||||
width: croppedWidth,
|
width: croppedWidth,
|
||||||
height: croppedHeight,
|
height: croppedHeight,
|
||||||
});
|
});
|
||||||
|
|
||||||
// H.264 Baseline profile only supports YUV 420 pixel format
|
// H.264 Baseline profile only supports YUV 420 pixel format
|
||||||
|
// So chroma width/height is each half of video width/height
|
||||||
const chromaWidth = encodedWidth / 2;
|
const chromaWidth = encodedWidth / 2;
|
||||||
const chromaHeight = encodedHeight / 2;
|
const chromaHeight = encodedHeight / 2;
|
||||||
|
|
||||||
|
|
|
@ -12,8 +12,12 @@ export interface ScrcpyVideoDecoderCapability {
|
||||||
|
|
||||||
export interface ScrcpyVideoDecoder extends Disposable {
|
export interface ScrcpyVideoDecoder extends Disposable {
|
||||||
readonly sizeChanged: Event<{ width: number; height: number }>;
|
readonly sizeChanged: Event<{ width: number; height: number }>;
|
||||||
|
readonly width: number;
|
||||||
|
readonly height: number;
|
||||||
|
|
||||||
readonly framesRendered: number;
|
readonly framesRendered: number;
|
||||||
readonly framesSkipped: number;
|
readonly framesSkipped: number;
|
||||||
|
|
||||||
readonly writable: WritableStream<ScrcpyMediaStreamPacket>;
|
readonly writable: WritableStream<ScrcpyMediaStreamPacket>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,87 +10,9 @@ import { WritableStream } from "@yume-chan/stream-extra";
|
||||||
|
|
||||||
import { Av1Codec, H264Decoder, H265Decoder } from "./codec/index.js";
|
import { Av1Codec, H264Decoder, H265Decoder } from "./codec/index.js";
|
||||||
import type { CodecDecoder } from "./codec/type.js";
|
import type { CodecDecoder } from "./codec/type.js";
|
||||||
|
import { Pool } from "./pool.js";
|
||||||
import type { VideoFrameRenderer } from "./render/index.js";
|
import type { VideoFrameRenderer } from "./render/index.js";
|
||||||
|
import { VideoFrameCapturer } from "./snapshot.js";
|
||||||
class Pool<T> {
|
|
||||||
#controller!: ReadableStreamDefaultController<T>;
|
|
||||||
#readable = new ReadableStream<T>(
|
|
||||||
{
|
|
||||||
start: (controller) => {
|
|
||||||
this.#controller = controller;
|
|
||||||
},
|
|
||||||
pull: (controller) => {
|
|
||||||
controller.enqueue(this.#initializer());
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{ highWaterMark: 0 },
|
|
||||||
);
|
|
||||||
#reader = this.#readable.getReader();
|
|
||||||
|
|
||||||
#initializer: () => T;
|
|
||||||
|
|
||||||
#size = 0;
|
|
||||||
#capacity: number;
|
|
||||||
|
|
||||||
constructor(initializer: () => T, capacity: number) {
|
|
||||||
this.#initializer = initializer;
|
|
||||||
this.#capacity = capacity;
|
|
||||||
}
|
|
||||||
|
|
||||||
async borrow() {
|
|
||||||
const result = await this.#reader.read();
|
|
||||||
return result.value!;
|
|
||||||
}
|
|
||||||
|
|
||||||
return(value: T) {
|
|
||||||
if (this.#size < this.#capacity) {
|
|
||||||
this.#controller.enqueue(value);
|
|
||||||
this.#size += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class VideoFrameCapturer {
|
|
||||||
#canvas: OffscreenCanvas | HTMLCanvasElement;
|
|
||||||
#context: ImageBitmapRenderingContext;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
if (typeof OffscreenCanvas !== "undefined") {
|
|
||||||
this.#canvas = new OffscreenCanvas(1, 1);
|
|
||||||
} else {
|
|
||||||
this.#canvas = document.createElement("canvas");
|
|
||||||
this.#canvas.width = 1;
|
|
||||||
this.#canvas.height = 1;
|
|
||||||
}
|
|
||||||
this.#context = this.#canvas.getContext("bitmaprenderer", {
|
|
||||||
alpha: false,
|
|
||||||
})!;
|
|
||||||
}
|
|
||||||
|
|
||||||
async capture(frame: VideoFrame): Promise<Blob> {
|
|
||||||
this.#canvas.width = frame.displayWidth;
|
|
||||||
this.#canvas.height = frame.displayHeight;
|
|
||||||
|
|
||||||
const bitmap = await createImageBitmap(frame);
|
|
||||||
this.#context.transferFromImageBitmap(bitmap);
|
|
||||||
|
|
||||||
if (this.#canvas instanceof OffscreenCanvas) {
|
|
||||||
return await this.#canvas.convertToBlob({
|
|
||||||
type: "image/png",
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
(this.#canvas as HTMLCanvasElement).toBlob((blob) => {
|
|
||||||
if (!blob) {
|
|
||||||
reject(new Error("Failed to convert canvas to blob"));
|
|
||||||
} else {
|
|
||||||
resolve(blob);
|
|
||||||
}
|
|
||||||
}, "image/png");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const VideoFrameCapturerPool =
|
const VideoFrameCapturerPool =
|
||||||
/* #__PURE__ */
|
/* #__PURE__ */
|
||||||
|
@ -144,6 +66,16 @@ export class WebCodecsVideoDecoder implements ScrcpyVideoDecoder {
|
||||||
return this.#sizeChanged.event;
|
return this.#sizeChanged.event;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#width: number = 0;
|
||||||
|
get width() {
|
||||||
|
return this.#width;
|
||||||
|
}
|
||||||
|
|
||||||
|
#height: number = 0;
|
||||||
|
get height() {
|
||||||
|
return this.#height;
|
||||||
|
}
|
||||||
|
|
||||||
#decoder: VideoDecoder;
|
#decoder: VideoDecoder;
|
||||||
|
|
||||||
#drawing = false;
|
#drawing = false;
|
||||||
|
@ -218,7 +150,7 @@ export class WebCodecsVideoDecoder implements ScrcpyVideoDecoder {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
this.#onVerticalSync();
|
this.#handleAnimationFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
#setError(error: Error) {
|
#setError(error: Error) {
|
||||||
|
@ -261,16 +193,20 @@ export class WebCodecsVideoDecoder implements ScrcpyVideoDecoder {
|
||||||
|
|
||||||
#updateSize = (width: number, height: number) => {
|
#updateSize = (width: number, height: number) => {
|
||||||
this.#renderer.setSize(width, height);
|
this.#renderer.setSize(width, height);
|
||||||
|
this.#width = width;
|
||||||
|
this.#height = height;
|
||||||
this.#sizeChanged.fire({ width, height });
|
this.#sizeChanged.fire({ width, height });
|
||||||
};
|
};
|
||||||
|
|
||||||
#onVerticalSync = () => {
|
#handleAnimationFrame = () => {
|
||||||
if (this.#framesDraw > 0) {
|
if (this.#framesDraw > 0) {
|
||||||
this.#framesPresented += 1;
|
this.#framesPresented += 1;
|
||||||
this.#framesSkipped += this.#framesDraw - 1;
|
this.#framesSkipped += this.#framesDraw - 1;
|
||||||
this.#framesDraw = 0;
|
this.#framesDraw = 0;
|
||||||
}
|
}
|
||||||
this.#animationFrameId = requestAnimationFrame(this.#onVerticalSync);
|
this.#animationFrameId = requestAnimationFrame(
|
||||||
|
this.#handleAnimationFrame,
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
async snapshot() {
|
async snapshot() {
|
||||||
|
|
37
libraries/scrcpy-decoder-webcodecs/src/video/pool.ts
Normal file
37
libraries/scrcpy-decoder-webcodecs/src/video/pool.ts
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
export class Pool<T> {
|
||||||
|
#controller!: ReadableStreamDefaultController<T>;
|
||||||
|
#readable = new ReadableStream<T>(
|
||||||
|
{
|
||||||
|
start: (controller) => {
|
||||||
|
this.#controller = controller;
|
||||||
|
},
|
||||||
|
pull: (controller) => {
|
||||||
|
controller.enqueue(this.#initializer());
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ highWaterMark: 0 },
|
||||||
|
);
|
||||||
|
#reader = this.#readable.getReader();
|
||||||
|
|
||||||
|
#initializer: () => T;
|
||||||
|
|
||||||
|
#size = 0;
|
||||||
|
#capacity: number;
|
||||||
|
|
||||||
|
constructor(initializer: () => T, capacity: number) {
|
||||||
|
this.#initializer = initializer;
|
||||||
|
this.#capacity = capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
async borrow() {
|
||||||
|
const result = await this.#reader.read();
|
||||||
|
return result.value!;
|
||||||
|
}
|
||||||
|
|
||||||
|
return(value: T) {
|
||||||
|
if (this.#size < this.#capacity) {
|
||||||
|
this.#controller.enqueue(value);
|
||||||
|
this.#size += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
41
libraries/scrcpy-decoder-webcodecs/src/video/snapshot.ts
Normal file
41
libraries/scrcpy-decoder-webcodecs/src/video/snapshot.ts
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
export class VideoFrameCapturer {
|
||||||
|
#canvas: OffscreenCanvas | HTMLCanvasElement;
|
||||||
|
#context: ImageBitmapRenderingContext;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
if (typeof OffscreenCanvas !== "undefined") {
|
||||||
|
this.#canvas = new OffscreenCanvas(1, 1);
|
||||||
|
} else {
|
||||||
|
this.#canvas = document.createElement("canvas");
|
||||||
|
this.#canvas.width = 1;
|
||||||
|
this.#canvas.height = 1;
|
||||||
|
}
|
||||||
|
this.#context = this.#canvas.getContext("bitmaprenderer", {
|
||||||
|
alpha: false,
|
||||||
|
})!;
|
||||||
|
}
|
||||||
|
|
||||||
|
async capture(frame: VideoFrame): Promise<Blob> {
|
||||||
|
this.#canvas.width = frame.displayWidth;
|
||||||
|
this.#canvas.height = frame.displayHeight;
|
||||||
|
|
||||||
|
const bitmap = await createImageBitmap(frame);
|
||||||
|
this.#context.transferFromImageBitmap(bitmap);
|
||||||
|
|
||||||
|
if (this.#canvas instanceof OffscreenCanvas) {
|
||||||
|
return await this.#canvas.convertToBlob({
|
||||||
|
type: "image/png",
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
(this.#canvas as HTMLCanvasElement).toBlob((blob) => {
|
||||||
|
if (!blob) {
|
||||||
|
reject(new Error("Failed to convert canvas to blob"));
|
||||||
|
} else {
|
||||||
|
resolve(blob);
|
||||||
|
}
|
||||||
|
}, "image/png");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -36,8 +36,8 @@ export const InjectTouchControlMessage = struct(
|
||||||
pointerId: u64,
|
pointerId: u64,
|
||||||
pointerX: u32,
|
pointerX: u32,
|
||||||
pointerY: u32,
|
pointerY: u32,
|
||||||
screenWidth: u16,
|
videoWidth: u16,
|
||||||
screenHeight: u16,
|
videoHeight: u16,
|
||||||
pressure: UnsignedFloat,
|
pressure: UnsignedFloat,
|
||||||
buttons: u32,
|
buttons: u32,
|
||||||
},
|
},
|
||||||
|
|
|
@ -12,8 +12,8 @@ describe("ScrollController", () => {
|
||||||
type: ScrcpyControlMessageType.InjectScroll,
|
type: ScrcpyControlMessageType.InjectScroll,
|
||||||
pointerX: 0,
|
pointerX: 0,
|
||||||
pointerY: 0,
|
pointerY: 0,
|
||||||
screenWidth: 0,
|
videoWidth: 0,
|
||||||
screenHeight: 0,
|
videoHeight: 0,
|
||||||
scrollX: 0.5,
|
scrollX: 0.5,
|
||||||
scrollY: 0.5,
|
scrollY: 0.5,
|
||||||
buttons: 0,
|
buttons: 0,
|
||||||
|
@ -27,8 +27,8 @@ describe("ScrollController", () => {
|
||||||
type: ScrcpyControlMessageType.InjectScroll,
|
type: ScrcpyControlMessageType.InjectScroll,
|
||||||
pointerX: 0,
|
pointerX: 0,
|
||||||
pointerY: 0,
|
pointerY: 0,
|
||||||
screenWidth: 0,
|
videoWidth: 0,
|
||||||
screenHeight: 0,
|
videoHeight: 0,
|
||||||
scrollX: 1.5,
|
scrollX: 1.5,
|
||||||
scrollY: 1.5,
|
scrollY: 1.5,
|
||||||
buttons: 0,
|
buttons: 0,
|
||||||
|
@ -43,8 +43,8 @@ describe("ScrollController", () => {
|
||||||
type: ScrcpyControlMessageType.InjectScroll,
|
type: ScrcpyControlMessageType.InjectScroll,
|
||||||
pointerX: 0,
|
pointerX: 0,
|
||||||
pointerY: 0,
|
pointerY: 0,
|
||||||
screenWidth: 0,
|
videoWidth: 0,
|
||||||
screenHeight: 0,
|
videoHeight: 0,
|
||||||
scrollX: 0.5,
|
scrollX: 0.5,
|
||||||
scrollY: 0.5,
|
scrollY: 0.5,
|
||||||
buttons: 0,
|
buttons: 0,
|
||||||
|
@ -53,8 +53,8 @@ describe("ScrollController", () => {
|
||||||
type: ScrcpyControlMessageType.InjectScroll,
|
type: ScrcpyControlMessageType.InjectScroll,
|
||||||
pointerX: 0,
|
pointerX: 0,
|
||||||
pointerY: 0,
|
pointerY: 0,
|
||||||
screenWidth: 0,
|
videoWidth: 0,
|
||||||
screenHeight: 0,
|
videoHeight: 0,
|
||||||
scrollX: 0.5,
|
scrollX: 0.5,
|
||||||
scrollY: 0.5,
|
scrollY: 0.5,
|
||||||
buttons: 0,
|
buttons: 0,
|
||||||
|
@ -69,8 +69,8 @@ describe("ScrollController", () => {
|
||||||
type: ScrcpyControlMessageType.InjectScroll,
|
type: ScrcpyControlMessageType.InjectScroll,
|
||||||
pointerX: 0,
|
pointerX: 0,
|
||||||
pointerY: 0,
|
pointerY: 0,
|
||||||
screenWidth: 0,
|
videoWidth: 0,
|
||||||
screenHeight: 0,
|
videoHeight: 0,
|
||||||
scrollX: -0.5,
|
scrollX: -0.5,
|
||||||
scrollY: -0.5,
|
scrollY: -0.5,
|
||||||
buttons: 0,
|
buttons: 0,
|
||||||
|
@ -79,8 +79,8 @@ describe("ScrollController", () => {
|
||||||
type: ScrcpyControlMessageType.InjectScroll,
|
type: ScrcpyControlMessageType.InjectScroll,
|
||||||
pointerX: 0,
|
pointerX: 0,
|
||||||
pointerY: 0,
|
pointerY: 0,
|
||||||
screenWidth: 0,
|
videoWidth: 0,
|
||||||
screenHeight: 0,
|
videoHeight: 0,
|
||||||
scrollX: -0.5,
|
scrollX: -0.5,
|
||||||
scrollY: -0.5,
|
scrollY: -0.5,
|
||||||
buttons: 0,
|
buttons: 0,
|
||||||
|
|
|
@ -9,8 +9,8 @@ export const InjectScrollControlMessage = struct(
|
||||||
type: u8,
|
type: u8,
|
||||||
pointerX: u32,
|
pointerX: u32,
|
||||||
pointerY: u32,
|
pointerY: u32,
|
||||||
screenWidth: u16,
|
videoWidth: u16,
|
||||||
screenHeight: u16,
|
videoHeight: u16,
|
||||||
scrollX: s32,
|
scrollX: s32,
|
||||||
scrollY: s32,
|
scrollY: s32,
|
||||||
},
|
},
|
||||||
|
|
|
@ -12,8 +12,8 @@ describe("ScrollController", () => {
|
||||||
type: ScrcpyControlMessageType.InjectScroll,
|
type: ScrcpyControlMessageType.InjectScroll,
|
||||||
pointerX: 0,
|
pointerX: 0,
|
||||||
pointerY: 0,
|
pointerY: 0,
|
||||||
screenWidth: 0,
|
videoWidth: 0,
|
||||||
screenHeight: 0,
|
videoHeight: 0,
|
||||||
scrollX: 1.5,
|
scrollX: 1.5,
|
||||||
scrollY: 1.5,
|
scrollY: 1.5,
|
||||||
buttons: 0,
|
buttons: 0,
|
||||||
|
|
|
@ -102,8 +102,8 @@ describe("ScrollController", () => {
|
||||||
type: ScrcpyControlMessageType.InjectScroll,
|
type: ScrcpyControlMessageType.InjectScroll,
|
||||||
pointerX: 0,
|
pointerX: 0,
|
||||||
pointerY: 0,
|
pointerY: 0,
|
||||||
screenWidth: 0,
|
videoWidth: 0,
|
||||||
screenHeight: 0,
|
videoHeight: 0,
|
||||||
scrollX: 0.5,
|
scrollX: 0.5,
|
||||||
scrollY: 0.5,
|
scrollY: 0.5,
|
||||||
buttons: 0,
|
buttons: 0,
|
||||||
|
@ -115,8 +115,8 @@ describe("ScrollController", () => {
|
||||||
type: ScrcpyControlMessageType.InjectScroll,
|
type: ScrcpyControlMessageType.InjectScroll,
|
||||||
pointerX: 0,
|
pointerX: 0,
|
||||||
pointerY: 0,
|
pointerY: 0,
|
||||||
screenWidth: 0,
|
videoWidth: 0,
|
||||||
screenHeight: 0,
|
videoHeight: 0,
|
||||||
scrollX: 1.5,
|
scrollX: 1.5,
|
||||||
scrollY: 1.5,
|
scrollY: 1.5,
|
||||||
buttons: 0,
|
buttons: 0,
|
||||||
|
|
|
@ -29,8 +29,8 @@ export const InjectScrollControlMessage = /* #__PURE__ */ (() =>
|
||||||
type: u8(ScrcpyControlMessageType.InjectScroll),
|
type: u8(ScrcpyControlMessageType.InjectScroll),
|
||||||
pointerX: u32,
|
pointerX: u32,
|
||||||
pointerY: u32,
|
pointerY: u32,
|
||||||
screenWidth: u16,
|
videoWidth: u16,
|
||||||
screenHeight: u16,
|
videoHeight: u16,
|
||||||
scrollX: SignedFloat,
|
scrollX: SignedFloat,
|
||||||
scrollY: SignedFloat,
|
scrollY: SignedFloat,
|
||||||
buttons: u32,
|
buttons: u32,
|
||||||
|
|
|
@ -15,8 +15,8 @@ export const InjectTouchControlMessage = /* #__PURE__ */ (() =>
|
||||||
pointerId: u64,
|
pointerId: u64,
|
||||||
pointerX: u32,
|
pointerX: u32,
|
||||||
pointerY: u32,
|
pointerY: u32,
|
||||||
screenWidth: u16,
|
videoWidth: u16,
|
||||||
screenHeight: u16,
|
videoHeight: u16,
|
||||||
pressure: PrevImpl.UnsignedFloat,
|
pressure: PrevImpl.UnsignedFloat,
|
||||||
actionButton: u32,
|
actionButton: u32,
|
||||||
buttons: u32,
|
buttons: u32,
|
||||||
|
|
|
@ -11,7 +11,7 @@ import { ScrcpyAudioCodec } from "../../base/index.js";
|
||||||
|
|
||||||
export async function parseAudioStreamMetadata(
|
export async function parseAudioStreamMetadata(
|
||||||
stream: ReadableStream<Uint8Array>,
|
stream: ReadableStream<Uint8Array>,
|
||||||
options: Pick<Required<Init>, "sendCodecMeta" | "audioCodec">,
|
options: Pick<Required<Init<boolean>>, "sendCodecMeta" | "audioCodec">,
|
||||||
): Promise<ScrcpyAudioStreamMetadata> {
|
): Promise<ScrcpyAudioStreamMetadata> {
|
||||||
const buffered = new BufferedReadableStream(stream);
|
const buffered = new BufferedReadableStream(stream);
|
||||||
|
|
||||||
|
|
|
@ -6,4 +6,4 @@ export const Defaults = /* #__PURE__ */ (() =>
|
||||||
...PrevImpl.Defaults,
|
...PrevImpl.Defaults,
|
||||||
video: true,
|
video: true,
|
||||||
audioSource: "output",
|
audioSource: "output",
|
||||||
}) as const satisfies Required<Init>)();
|
}) as const satisfies Required<Init<true>>)();
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import type { PrevImpl } from "./prev.js";
|
import type { PrevImpl } from "./prev.js";
|
||||||
|
|
||||||
export interface Init extends PrevImpl.Init {
|
export interface Init<TVideo extends boolean> extends PrevImpl.Init {
|
||||||
video?: boolean;
|
video?: TVideo;
|
||||||
audioSource?: "output" | "mic";
|
audioSource?: "output" | "mic";
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,12 +37,14 @@ import {
|
||||||
setListEncoders,
|
setListEncoders,
|
||||||
} from "./impl/index.js";
|
} from "./impl/index.js";
|
||||||
|
|
||||||
export class ScrcpyOptions2_1 implements ScrcpyOptions<Init> {
|
export class ScrcpyOptions2_1<TVideo extends boolean>
|
||||||
|
implements ScrcpyOptions<Init<TVideo>>
|
||||||
|
{
|
||||||
static readonly Defaults = Defaults;
|
static readonly Defaults = Defaults;
|
||||||
|
|
||||||
readonly version: string;
|
readonly version: string;
|
||||||
|
|
||||||
readonly value: Required<Init>;
|
readonly value: Required<Init<TVideo>>;
|
||||||
|
|
||||||
get controlMessageTypes(): readonly ScrcpyControlMessageType[] {
|
get controlMessageTypes(): readonly ScrcpyControlMessageType[] {
|
||||||
return ControlMessageTypes;
|
return ControlMessageTypes;
|
||||||
|
@ -55,8 +57,8 @@ export class ScrcpyOptions2_1 implements ScrcpyOptions<Init> {
|
||||||
|
|
||||||
#ackClipboardHandler: AckClipboardHandler | undefined;
|
#ackClipboardHandler: AckClipboardHandler | undefined;
|
||||||
|
|
||||||
constructor(init: Init, version = "2.1") {
|
constructor(init: Init<TVideo>, version = "2.1") {
|
||||||
this.value = { ...Defaults, ...init };
|
this.value = { ...Defaults, ...init } as never;
|
||||||
this.version = version;
|
this.version = version;
|
||||||
|
|
||||||
if (this.value.control && this.value.clipboardAutosync) {
|
if (this.value.control && this.value.clipboardAutosync) {
|
||||||
|
@ -66,7 +68,7 @@ export class ScrcpyOptions2_1 implements ScrcpyOptions<Init> {
|
||||||
}
|
}
|
||||||
|
|
||||||
serialize(): string[] {
|
serialize(): string[] {
|
||||||
return serialize(this.value, Defaults);
|
return serialize<Init<boolean>>(this.value, Defaults);
|
||||||
}
|
}
|
||||||
|
|
||||||
setListDisplays(): void {
|
setListDisplays(): void {
|
||||||
|
@ -154,8 +156,8 @@ export class ScrcpyOptions2_1 implements ScrcpyOptions<Init> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type Init_ = Init;
|
type Init_<TVideo extends boolean> = Init<TVideo>;
|
||||||
|
|
||||||
export namespace ScrcpyOptions2_1 {
|
export namespace ScrcpyOptions2_1 {
|
||||||
export type Init = Init_;
|
export type Init<TVideo extends boolean = boolean> = Init_<TVideo>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
import { ScrcpyOptions2_1 } from "./2_1/index.js";
|
import { ScrcpyOptions2_1 } from "./2_1/index.js";
|
||||||
|
|
||||||
export class ScrcpyOptions2_1_1 extends ScrcpyOptions2_1 {
|
export class ScrcpyOptions2_1_1<
|
||||||
constructor(init: ScrcpyOptions2_1.Init, version = "2.1.1") {
|
TVideo extends boolean,
|
||||||
|
> extends ScrcpyOptions2_1<TVideo> {
|
||||||
|
constructor(init: ScrcpyOptions2_1.Init<TVideo>, version = "2.1.1") {
|
||||||
super(init, version);
|
super(init, version);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export namespace ScrcpyOptions2_1_1 {
|
export namespace ScrcpyOptions2_1_1 {
|
||||||
export type Init = ScrcpyOptions2_1.Init;
|
export type Init<TVideo extends boolean = boolean> =
|
||||||
|
ScrcpyOptions2_1.Init<TVideo>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,4 +14,4 @@ export const Defaults = /* #__PURE__ */ (() =>
|
||||||
cameraHighSpeed: false,
|
cameraHighSpeed: false,
|
||||||
listCameras: false,
|
listCameras: false,
|
||||||
listCameraSizes: false,
|
listCameraSizes: false,
|
||||||
}) as const satisfies Required<Init>)();
|
}) as const satisfies Required<Init<true>>)();
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import type { PrevImpl } from "./prev.js";
|
import type { PrevImpl } from "./prev.js";
|
||||||
|
|
||||||
export interface Init extends PrevImpl.Init {
|
export interface Init<TVideo extends boolean> extends PrevImpl.Init<TVideo> {
|
||||||
videoSource?: "display" | "camera";
|
videoSource?: "display" | "camera";
|
||||||
cameraId?: string | undefined;
|
cameraId?: string | undefined;
|
||||||
cameraSize?: string | undefined;
|
cameraSize?: string | undefined;
|
||||||
|
|
|
@ -37,12 +37,14 @@ import {
|
||||||
setListEncoders,
|
setListEncoders,
|
||||||
} from "./impl/index.js";
|
} from "./impl/index.js";
|
||||||
|
|
||||||
export class ScrcpyOptions2_2 implements ScrcpyOptions<Init> {
|
export class ScrcpyOptions2_2<TVideo extends boolean>
|
||||||
|
implements ScrcpyOptions<Init<TVideo>>
|
||||||
|
{
|
||||||
static readonly Defaults = Defaults;
|
static readonly Defaults = Defaults;
|
||||||
|
|
||||||
readonly version: string;
|
readonly version: string;
|
||||||
|
|
||||||
readonly value: Required<Init>;
|
readonly value: Required<Init<TVideo>>;
|
||||||
|
|
||||||
get controlMessageTypes(): readonly ScrcpyControlMessageType[] {
|
get controlMessageTypes(): readonly ScrcpyControlMessageType[] {
|
||||||
return ControlMessageTypes;
|
return ControlMessageTypes;
|
||||||
|
@ -55,8 +57,8 @@ export class ScrcpyOptions2_2 implements ScrcpyOptions<Init> {
|
||||||
|
|
||||||
#ackClipboardHandler: AckClipboardHandler | undefined;
|
#ackClipboardHandler: AckClipboardHandler | undefined;
|
||||||
|
|
||||||
constructor(init: Init, version = "v2.2") {
|
constructor(init: Init<TVideo>, version = "v2.2") {
|
||||||
this.value = { ...Defaults, ...init };
|
this.value = { ...Defaults, ...init } as never;
|
||||||
this.version = version;
|
this.version = version;
|
||||||
|
|
||||||
if (this.value.videoSource === "camera") {
|
if (this.value.videoSource === "camera") {
|
||||||
|
@ -70,7 +72,7 @@ export class ScrcpyOptions2_2 implements ScrcpyOptions<Init> {
|
||||||
}
|
}
|
||||||
|
|
||||||
serialize(): string[] {
|
serialize(): string[] {
|
||||||
return serialize(this.value, Defaults);
|
return serialize<Init<boolean>>(this.value, Defaults);
|
||||||
}
|
}
|
||||||
|
|
||||||
setListDisplays(): void {
|
setListDisplays(): void {
|
||||||
|
@ -158,8 +160,8 @@ export class ScrcpyOptions2_2 implements ScrcpyOptions<Init> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type Init_ = Init;
|
type Init_<TVideo extends boolean> = Init<TVideo>;
|
||||||
|
|
||||||
export namespace ScrcpyOptions2_2 {
|
export namespace ScrcpyOptions2_2 {
|
||||||
export type Init = Init_;
|
export type Init<TVideo extends boolean = boolean> = Init_<TVideo>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import type { PrevImpl } from "./prev.js";
|
import type { PrevImpl } from "./prev.js";
|
||||||
|
|
||||||
export interface Init extends Omit<PrevImpl.Init, "audioCodec"> {
|
export interface Init<TVideo extends boolean>
|
||||||
audioCodec?: PrevImpl.Init["audioCodec"] | "flac";
|
extends Omit<PrevImpl.Init<TVideo>, "audioCodec"> {
|
||||||
|
audioCodec?: PrevImpl.Init<TVideo>["audioCodec"] | "flac";
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,12 +37,14 @@ import {
|
||||||
setListEncoders,
|
setListEncoders,
|
||||||
} from "./impl/index.js";
|
} from "./impl/index.js";
|
||||||
|
|
||||||
export class ScrcpyOptions2_3 implements ScrcpyOptions<Init> {
|
export class ScrcpyOptions2_3<TVideo extends boolean>
|
||||||
|
implements ScrcpyOptions<Init<TVideo>>
|
||||||
|
{
|
||||||
static readonly Defaults = Defaults;
|
static readonly Defaults = Defaults;
|
||||||
|
|
||||||
readonly version: string;
|
readonly version: string;
|
||||||
|
|
||||||
readonly value: Required<Init>;
|
readonly value: Required<Init<TVideo>>;
|
||||||
|
|
||||||
get controlMessageTypes(): readonly ScrcpyControlMessageType[] {
|
get controlMessageTypes(): readonly ScrcpyControlMessageType[] {
|
||||||
return ControlMessageTypes;
|
return ControlMessageTypes;
|
||||||
|
@ -55,8 +57,8 @@ export class ScrcpyOptions2_3 implements ScrcpyOptions<Init> {
|
||||||
|
|
||||||
#ackClipboardHandler: AckClipboardHandler | undefined;
|
#ackClipboardHandler: AckClipboardHandler | undefined;
|
||||||
|
|
||||||
constructor(init: Init, version = "2.3") {
|
constructor(init: Init<TVideo>, version = "2.3") {
|
||||||
this.value = { ...Defaults, ...init };
|
this.value = { ...Defaults, ...init } as never;
|
||||||
this.version = version;
|
this.version = version;
|
||||||
|
|
||||||
if (this.value.videoSource === "camera") {
|
if (this.value.videoSource === "camera") {
|
||||||
|
@ -70,7 +72,7 @@ export class ScrcpyOptions2_3 implements ScrcpyOptions<Init> {
|
||||||
}
|
}
|
||||||
|
|
||||||
serialize(): string[] {
|
serialize(): string[] {
|
||||||
return serialize(this.value, Defaults);
|
return serialize<Init<boolean>>(this.value, Defaults);
|
||||||
}
|
}
|
||||||
|
|
||||||
setListDisplays(): void {
|
setListDisplays(): void {
|
||||||
|
@ -158,8 +160,8 @@ export class ScrcpyOptions2_3 implements ScrcpyOptions<Init> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type Init_ = Init;
|
type Init_<TVideo extends boolean> = Init<TVideo>;
|
||||||
|
|
||||||
export namespace ScrcpyOptions2_3 {
|
export namespace ScrcpyOptions2_3 {
|
||||||
export type Init = Init_;
|
export type Init<TVideo extends boolean = boolean> = Init_<TVideo>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
import { ScrcpyOptions2_3 } from "./2_3/index.js";
|
import { ScrcpyOptions2_3 } from "./2_3/index.js";
|
||||||
|
|
||||||
export class ScrcpyOptions2_3_1 extends ScrcpyOptions2_3 {
|
export class ScrcpyOptions2_3_1<
|
||||||
constructor(init: ScrcpyOptions2_3.Init, version = "2.3.1") {
|
TVideo extends boolean,
|
||||||
|
> extends ScrcpyOptions2_3<TVideo> {
|
||||||
|
constructor(init: ScrcpyOptions2_3.Init<TVideo>, version = "2.3.1") {
|
||||||
super(init, version);
|
super(init, version);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export namespace ScrcpyOptions2_3_1 {
|
export namespace ScrcpyOptions2_3_1 {
|
||||||
export type Init = ScrcpyOptions2_3.Init;
|
export type Init<TVideo extends boolean = boolean> =
|
||||||
|
ScrcpyOptions2_3.Init<TVideo>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,12 +41,14 @@ import {
|
||||||
UHidOutputStream,
|
UHidOutputStream,
|
||||||
} from "./impl/index.js";
|
} from "./impl/index.js";
|
||||||
|
|
||||||
export class ScrcpyOptions2_4 implements ScrcpyOptions<Init> {
|
export class ScrcpyOptions2_4<TVideo extends boolean>
|
||||||
|
implements ScrcpyOptions<Init<TVideo>>
|
||||||
|
{
|
||||||
static readonly Defaults = Defaults;
|
static readonly Defaults = Defaults;
|
||||||
|
|
||||||
readonly version: string;
|
readonly version: string;
|
||||||
|
|
||||||
readonly value: Required<Init>;
|
readonly value: Required<Init<TVideo>>;
|
||||||
|
|
||||||
get controlMessageTypes(): readonly ScrcpyControlMessageType[] {
|
get controlMessageTypes(): readonly ScrcpyControlMessageType[] {
|
||||||
return ControlMessageTypes;
|
return ControlMessageTypes;
|
||||||
|
@ -66,8 +68,8 @@ export class ScrcpyOptions2_4 implements ScrcpyOptions<Init> {
|
||||||
return this.#uHidOutput;
|
return this.#uHidOutput;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(init: Init, version = "2.4") {
|
constructor(init: Init<TVideo>, version = "2.4") {
|
||||||
this.value = { ...Defaults, ...init };
|
this.value = { ...Defaults, ...init } as never;
|
||||||
this.version = version;
|
this.version = version;
|
||||||
|
|
||||||
if (this.value.videoSource === "camera") {
|
if (this.value.videoSource === "camera") {
|
||||||
|
@ -85,7 +87,7 @@ export class ScrcpyOptions2_4 implements ScrcpyOptions<Init> {
|
||||||
}
|
}
|
||||||
|
|
||||||
serialize(): string[] {
|
serialize(): string[] {
|
||||||
return serialize(this.value, Defaults);
|
return serialize<Init<boolean>>(this.value, Defaults);
|
||||||
}
|
}
|
||||||
|
|
||||||
setListDisplays(): void {
|
setListDisplays(): void {
|
||||||
|
@ -185,8 +187,8 @@ export class ScrcpyOptions2_4 implements ScrcpyOptions<Init> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type Init_ = Init;
|
type Init_<TVideo extends boolean> = Init<TVideo>;
|
||||||
|
|
||||||
export namespace ScrcpyOptions2_4 {
|
export namespace ScrcpyOptions2_4 {
|
||||||
export type Init = Init_;
|
export type Init<TVideo extends boolean = boolean> = Init_<TVideo>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
import { ScrcpyOptions2_4 } from "./2_4/index.js";
|
import { ScrcpyOptions2_4 } from "./2_4/index.js";
|
||||||
|
|
||||||
export class ScrcpyOptions2_5 extends ScrcpyOptions2_4 {
|
export class ScrcpyOptions2_5<
|
||||||
constructor(init: ScrcpyOptions2_4.Init, version = "2.5") {
|
TVideo extends boolean,
|
||||||
|
> extends ScrcpyOptions2_4<TVideo> {
|
||||||
|
constructor(init: ScrcpyOptions2_4.Init<TVideo>, version = "2.5") {
|
||||||
super(init, version);
|
super(init, version);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export namespace ScrcpyOptions2_5 {
|
export namespace ScrcpyOptions2_5 {
|
||||||
export type Init = ScrcpyOptions2_4.Init;
|
export type Init<TVideo extends boolean = boolean> =
|
||||||
|
ScrcpyOptions2_4.Init<TVideo>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,4 +5,4 @@ export const Defaults = /* #__PURE__ */ (() =>
|
||||||
({
|
({
|
||||||
...PrevImpl.Defaults,
|
...PrevImpl.Defaults,
|
||||||
audioDup: false,
|
audioDup: false,
|
||||||
}) as const satisfies Required<Init>)();
|
}) as const satisfies Required<Init<true>>)();
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import type { PrevImpl } from "./prev.js";
|
import type { PrevImpl } from "./prev.js";
|
||||||
|
|
||||||
export interface Init extends Omit<PrevImpl.Init, "audioSource"> {
|
export interface Init<TVideo extends boolean>
|
||||||
audioSource?: PrevImpl.Init["audioSource"] | "playback";
|
extends Omit<PrevImpl.Init<TVideo>, "audioSource"> {
|
||||||
|
audioSource?: PrevImpl.Init<TVideo>["audioSource"] | "playback";
|
||||||
audioDup?: boolean;
|
audioDup?: boolean;
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,12 +41,14 @@ import {
|
||||||
UHidOutputStream,
|
UHidOutputStream,
|
||||||
} from "./impl/index.js";
|
} from "./impl/index.js";
|
||||||
|
|
||||||
export class ScrcpyOptions2_6 implements ScrcpyOptions<Init> {
|
export class ScrcpyOptions2_6<TVideo extends boolean>
|
||||||
|
implements ScrcpyOptions<Init<TVideo>>
|
||||||
|
{
|
||||||
static readonly Defaults = Defaults;
|
static readonly Defaults = Defaults;
|
||||||
|
|
||||||
readonly version: string;
|
readonly version: string;
|
||||||
|
|
||||||
readonly value: Required<Init>;
|
readonly value: Required<Init<TVideo>>;
|
||||||
|
|
||||||
get controlMessageTypes(): readonly ScrcpyControlMessageType[] {
|
get controlMessageTypes(): readonly ScrcpyControlMessageType[] {
|
||||||
return ControlMessageTypes;
|
return ControlMessageTypes;
|
||||||
|
@ -66,8 +68,8 @@ export class ScrcpyOptions2_6 implements ScrcpyOptions<Init> {
|
||||||
return this.#uHidOutput;
|
return this.#uHidOutput;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(init: Init, version = "2.6") {
|
constructor(init: Init<TVideo>, version = "2.6") {
|
||||||
this.value = { ...Defaults, ...init };
|
this.value = { ...Defaults, ...init } as never;
|
||||||
this.version = version;
|
this.version = version;
|
||||||
|
|
||||||
if (this.value.videoSource === "camera") {
|
if (this.value.videoSource === "camera") {
|
||||||
|
@ -89,7 +91,7 @@ export class ScrcpyOptions2_6 implements ScrcpyOptions<Init> {
|
||||||
}
|
}
|
||||||
|
|
||||||
serialize(): string[] {
|
serialize(): string[] {
|
||||||
return serialize(this.value, Defaults);
|
return serialize<Init<boolean>>(this.value, Defaults);
|
||||||
}
|
}
|
||||||
|
|
||||||
setListDisplays(): void {
|
setListDisplays(): void {
|
||||||
|
@ -183,8 +185,8 @@ export class ScrcpyOptions2_6 implements ScrcpyOptions<Init> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type Init_ = Init;
|
type Init_<TVideo extends boolean> = Init<TVideo>;
|
||||||
|
|
||||||
export namespace ScrcpyOptions2_6 {
|
export namespace ScrcpyOptions2_6 {
|
||||||
export type Init = Init_;
|
export type Init<TVideo extends boolean = boolean> = Init_<TVideo>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
import { ScrcpyOptions2_6 } from "./2_6/index.js";
|
import { ScrcpyOptions2_6 } from "./2_6/index.js";
|
||||||
|
|
||||||
export class ScrcpyOptions2_6_1 extends ScrcpyOptions2_6 {
|
export class ScrcpyOptions2_6_1<
|
||||||
constructor(init: ScrcpyOptions2_6.Init, version = "2.6.1") {
|
TVideo extends boolean,
|
||||||
|
> extends ScrcpyOptions2_6<TVideo> {
|
||||||
|
constructor(init: ScrcpyOptions2_6.Init<TVideo>, version = "2.6.1") {
|
||||||
super(init, version);
|
super(init, version);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export namespace ScrcpyOptions2_6_1 {
|
export namespace ScrcpyOptions2_6_1 {
|
||||||
export type Init = ScrcpyOptions2_6.Init;
|
export type Init<TVideo extends boolean = boolean> =
|
||||||
|
ScrcpyOptions2_6.Init<TVideo>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,12 +41,14 @@ import {
|
||||||
UHidOutputStream,
|
UHidOutputStream,
|
||||||
} from "./impl/index.js";
|
} from "./impl/index.js";
|
||||||
|
|
||||||
export class ScrcpyOptions2_7 implements ScrcpyOptions<Init> {
|
export class ScrcpyOptions2_7<TVideo extends boolean>
|
||||||
|
implements ScrcpyOptions<Init<TVideo>>
|
||||||
|
{
|
||||||
static readonly Defaults = Defaults;
|
static readonly Defaults = Defaults;
|
||||||
|
|
||||||
readonly version: string;
|
readonly version: string;
|
||||||
|
|
||||||
readonly value: Required<Init>;
|
readonly value: Required<Init<TVideo>>;
|
||||||
|
|
||||||
get controlMessageTypes(): readonly ScrcpyControlMessageType[] {
|
get controlMessageTypes(): readonly ScrcpyControlMessageType[] {
|
||||||
return ControlMessageTypes;
|
return ControlMessageTypes;
|
||||||
|
@ -66,8 +68,8 @@ export class ScrcpyOptions2_7 implements ScrcpyOptions<Init> {
|
||||||
return this.#uHidOutput;
|
return this.#uHidOutput;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(init: Init, version = "2.7") {
|
constructor(init: Init<TVideo>, version = "2.7") {
|
||||||
this.value = { ...Defaults, ...init };
|
this.value = { ...Defaults, ...init } as never;
|
||||||
this.version = version;
|
this.version = version;
|
||||||
|
|
||||||
if (this.value.videoSource === "camera") {
|
if (this.value.videoSource === "camera") {
|
||||||
|
@ -89,7 +91,7 @@ export class ScrcpyOptions2_7 implements ScrcpyOptions<Init> {
|
||||||
}
|
}
|
||||||
|
|
||||||
serialize(): string[] {
|
serialize(): string[] {
|
||||||
return serialize(this.value, Defaults);
|
return serialize<Init<boolean>>(this.value, Defaults);
|
||||||
}
|
}
|
||||||
|
|
||||||
setListDisplays(): void {
|
setListDisplays(): void {
|
||||||
|
@ -183,8 +185,8 @@ export class ScrcpyOptions2_7 implements ScrcpyOptions<Init> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type Init_ = Init;
|
type Init_<TVideo extends boolean> = Init<TVideo>;
|
||||||
|
|
||||||
export namespace ScrcpyOptions2_7 {
|
export namespace ScrcpyOptions2_7 {
|
||||||
export type Init = Init_;
|
export type Init<TVideo extends boolean = boolean> = Init_<TVideo>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,4 +12,4 @@ export const Defaults = /* #__PURE__ */ (() =>
|
||||||
listApps: false,
|
listApps: false,
|
||||||
newDisplay: undefined,
|
newDisplay: undefined,
|
||||||
vdSystemDecorations: true,
|
vdSystemDecorations: true,
|
||||||
}) as const satisfies Required<Init>)();
|
}) as const satisfies Required<Init<true>>)();
|
||||||
|
|
|
@ -106,7 +106,8 @@ export class NewDisplay implements ScrcpyOptionValue {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Init extends Omit<PrevImpl.Init, "lockVideoOrientation"> {
|
export interface Init<TVideo extends boolean>
|
||||||
|
extends Omit<PrevImpl.Init<TVideo>, "lockVideoOrientation"> {
|
||||||
captureOrientation?: CaptureOrientation | string | undefined;
|
captureOrientation?: CaptureOrientation | string | undefined;
|
||||||
angle?: number;
|
angle?: number;
|
||||||
screenOffTimeout?: number | undefined;
|
screenOffTimeout?: number | undefined;
|
||||||
|
|
|
@ -41,12 +41,14 @@ import {
|
||||||
UHidOutputStream,
|
UHidOutputStream,
|
||||||
} from "./impl/index.js";
|
} from "./impl/index.js";
|
||||||
|
|
||||||
export class ScrcpyOptions3_0 implements ScrcpyOptions<Init> {
|
export class ScrcpyOptions3_0<TVideo extends boolean>
|
||||||
|
implements ScrcpyOptions<Init<TVideo>>
|
||||||
|
{
|
||||||
static readonly Defaults = Defaults;
|
static readonly Defaults = Defaults;
|
||||||
|
|
||||||
readonly version: string;
|
readonly version: string;
|
||||||
|
|
||||||
readonly value: Required<Init>;
|
readonly value: Required<Init<TVideo>>;
|
||||||
|
|
||||||
get controlMessageTypes(): readonly ScrcpyControlMessageType[] {
|
get controlMessageTypes(): readonly ScrcpyControlMessageType[] {
|
||||||
return ControlMessageTypes;
|
return ControlMessageTypes;
|
||||||
|
@ -66,8 +68,8 @@ export class ScrcpyOptions3_0 implements ScrcpyOptions<Init> {
|
||||||
return this.#uHidOutput;
|
return this.#uHidOutput;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(init: Init, version = "3.0") {
|
constructor(init: Init<TVideo>, version = "3.0") {
|
||||||
this.value = { ...Defaults, ...init };
|
this.value = { ...Defaults, ...init } as never;
|
||||||
this.version = version;
|
this.version = version;
|
||||||
|
|
||||||
if (this.value.videoSource === "camera") {
|
if (this.value.videoSource === "camera") {
|
||||||
|
@ -89,7 +91,7 @@ export class ScrcpyOptions3_0 implements ScrcpyOptions<Init> {
|
||||||
}
|
}
|
||||||
|
|
||||||
serialize(): string[] {
|
serialize(): string[] {
|
||||||
return serialize(this.value, Defaults);
|
return serialize<Init<boolean>>(this.value, Defaults);
|
||||||
}
|
}
|
||||||
|
|
||||||
setListDisplays(): void {
|
setListDisplays(): void {
|
||||||
|
@ -183,8 +185,8 @@ export class ScrcpyOptions3_0 implements ScrcpyOptions<Init> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type Init_ = Init;
|
type Init_<TVideo extends boolean> = Init<TVideo>;
|
||||||
|
|
||||||
export namespace ScrcpyOptions3_0 {
|
export namespace ScrcpyOptions3_0 {
|
||||||
export type Init = Init_;
|
export type Init<TVideo extends boolean = boolean> = Init_<TVideo>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
import { ScrcpyOptions3_0 } from "./3_0/index.js";
|
import { ScrcpyOptions3_0 } from "./3_0/index.js";
|
||||||
|
|
||||||
export class ScrcpyOptions3_0_1 extends ScrcpyOptions3_0 {
|
export class ScrcpyOptions3_0_1<
|
||||||
constructor(init: ScrcpyOptions3_0.Init, version = "3.0.1") {
|
TVideo extends boolean,
|
||||||
|
> extends ScrcpyOptions3_0<TVideo> {
|
||||||
|
constructor(init: ScrcpyOptions3_0.Init<TVideo>, version = "3.0.1") {
|
||||||
super(init, version);
|
super(init, version);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export namespace ScrcpyOptions3_0_1 {
|
export namespace ScrcpyOptions3_0_1 {
|
||||||
export type Init = ScrcpyOptions3_0.Init;
|
export type Init<TVideo extends boolean = boolean> =
|
||||||
|
ScrcpyOptions3_0.Init<TVideo>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
import { ScrcpyOptions3_0 } from "./3_0/index.js";
|
import { ScrcpyOptions3_0 } from "./3_0/index.js";
|
||||||
|
|
||||||
export class ScrcpyOptions3_0_2 extends ScrcpyOptions3_0 {
|
export class ScrcpyOptions3_0_2<
|
||||||
constructor(init: ScrcpyOptions3_0.Init, version = "3.0.2") {
|
TVideo extends boolean,
|
||||||
|
> extends ScrcpyOptions3_0<TVideo> {
|
||||||
|
constructor(init: ScrcpyOptions3_0.Init<TVideo>, version = "3.0.2") {
|
||||||
super(init, version);
|
super(init, version);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export namespace ScrcpyOptions3_0_2 {
|
export namespace ScrcpyOptions3_0_2 {
|
||||||
export type Init = ScrcpyOptions3_0.Init;
|
export type Init<TVideo extends boolean = boolean> =
|
||||||
|
ScrcpyOptions3_0.Init<TVideo>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,4 +5,4 @@ export const Defaults = /* #__PURE__ */ (() =>
|
||||||
({
|
({
|
||||||
...PrevImpl.Defaults,
|
...PrevImpl.Defaults,
|
||||||
vdDestroyContent: false,
|
vdDestroyContent: false,
|
||||||
}) as const satisfies Required<Init>)();
|
}) as const satisfies Required<Init<true>>)();
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import type { PrevImpl } from "./prev.js";
|
import type { PrevImpl } from "./prev.js";
|
||||||
|
|
||||||
export interface Init extends PrevImpl.Init {
|
export interface Init<TVideo extends boolean> extends PrevImpl.Init<TVideo> {
|
||||||
vdDestroyContent?: boolean;
|
vdDestroyContent?: boolean;
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,12 +41,14 @@ import {
|
||||||
UHidOutputStream,
|
UHidOutputStream,
|
||||||
} from "./impl/index.js";
|
} from "./impl/index.js";
|
||||||
|
|
||||||
export class ScrcpyOptions3_1 implements ScrcpyOptions<Init> {
|
export class ScrcpyOptions3_1<TVideo extends boolean>
|
||||||
|
implements ScrcpyOptions<Init<TVideo>>
|
||||||
|
{
|
||||||
static readonly Defaults = Defaults;
|
static readonly Defaults = Defaults;
|
||||||
|
|
||||||
readonly version: string;
|
readonly version: string;
|
||||||
|
|
||||||
readonly value: Required<Init>;
|
readonly value: Required<Init<TVideo>>;
|
||||||
|
|
||||||
get controlMessageTypes(): readonly ScrcpyControlMessageType[] {
|
get controlMessageTypes(): readonly ScrcpyControlMessageType[] {
|
||||||
return ControlMessageTypes;
|
return ControlMessageTypes;
|
||||||
|
@ -66,8 +68,8 @@ export class ScrcpyOptions3_1 implements ScrcpyOptions<Init> {
|
||||||
return this.#uHidOutput;
|
return this.#uHidOutput;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(init: Init, version = "3.1") {
|
constructor(init: Init<TVideo>, version = "3.1") {
|
||||||
this.value = { ...Defaults, ...init };
|
this.value = { ...Defaults, ...init } as never;
|
||||||
this.version = version;
|
this.version = version;
|
||||||
|
|
||||||
if (this.value.videoSource === "camera") {
|
if (this.value.videoSource === "camera") {
|
||||||
|
@ -89,7 +91,7 @@ export class ScrcpyOptions3_1 implements ScrcpyOptions<Init> {
|
||||||
}
|
}
|
||||||
|
|
||||||
serialize(): string[] {
|
serialize(): string[] {
|
||||||
return serialize(this.value, Defaults);
|
return serialize<Init<boolean>>(this.value, Defaults);
|
||||||
}
|
}
|
||||||
|
|
||||||
setListDisplays(): void {
|
setListDisplays(): void {
|
||||||
|
@ -183,8 +185,8 @@ export class ScrcpyOptions3_1 implements ScrcpyOptions<Init> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type Init_ = Init;
|
type Init_<TVideo extends boolean> = Init<TVideo>;
|
||||||
|
|
||||||
export namespace ScrcpyOptions3_1 {
|
export namespace ScrcpyOptions3_1 {
|
||||||
export type Init = Init_;
|
export type Init<TVideo extends boolean = boolean> = Init_<TVideo>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,16 @@
|
||||||
import { ScrcpyOptions3_1 } from "./3_1/options.js";
|
import { ScrcpyOptions3_1 } from "./3_1/options.js";
|
||||||
|
|
||||||
export class ScrcpyOptionsLatest extends ScrcpyOptions3_1 {
|
export class ScrcpyOptionsLatest<
|
||||||
constructor(init: ScrcpyOptions3_1.Init, version: string) {
|
TVideo extends boolean,
|
||||||
|
> extends ScrcpyOptions3_1<TVideo> {
|
||||||
|
constructor(init: ScrcpyOptions3_1.Init<TVideo>, version: string) {
|
||||||
super(init, version);
|
super(init, version);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export namespace ScrcpyOptionsLatest {
|
export namespace ScrcpyOptionsLatest {
|
||||||
export type Init = ScrcpyOptions3_1.Init;
|
export type Init<TVideo extends boolean = boolean> =
|
||||||
|
ScrcpyOptions3_1.Init<TVideo>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
|
6
pnpm-lock.yaml
generated
6
pnpm-lock.yaml
generated
|
@ -163,9 +163,15 @@ importers:
|
||||||
specifier: workspace:^
|
specifier: workspace:^
|
||||||
version: link:../struct
|
version: link:../struct
|
||||||
devDependencies:
|
devDependencies:
|
||||||
|
'@types/node':
|
||||||
|
specifier: ^22.10.10
|
||||||
|
version: 22.10.10
|
||||||
'@yume-chan/eslint-config':
|
'@yume-chan/eslint-config':
|
||||||
specifier: workspace:^
|
specifier: workspace:^
|
||||||
version: link:../../toolchain/eslint-config
|
version: link:../../toolchain/eslint-config
|
||||||
|
'@yume-chan/test-runner':
|
||||||
|
specifier: workspace:^
|
||||||
|
version: link:../../toolchain/test-runner
|
||||||
'@yume-chan/tsconfig':
|
'@yume-chan/tsconfig':
|
||||||
specifier: workspace:^
|
specifier: workspace:^
|
||||||
version: link:../../toolchain/tsconfig
|
version: link:../../toolchain/tsconfig
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue