mirror of
https://github.com/yume-chan/ya-webadb.git
synced 2025-10-03 09:49:24 +02:00
feat(scrcpy): support server version 2.1
This commit is contained in:
parent
ef583779fa
commit
419a7559fe
16 changed files with 243 additions and 94 deletions
|
@ -3,7 +3,7 @@
|
|||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"postinstall": "fetch-scrcpy-server 2.0 && node scripts/manifest.mjs",
|
||||
"postinstall": "fetch-scrcpy-server 2.1 && node scripts/manifest.mjs",
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
|
|
|
@ -320,7 +320,7 @@ export class ScrcpyPageState {
|
|||
|
||||
RECORD_STATE.recorder = new MatroskaMuxingRecorder();
|
||||
|
||||
client.videoStream.then(({ stream, metadata }) => {
|
||||
client.videoStream!.then(({ stream, metadata }) => {
|
||||
runInAction(() => {
|
||||
RECORD_STATE.recorder.videoMetadata = metadata;
|
||||
});
|
||||
|
|
|
@ -23,6 +23,7 @@ Similar to `@yume-chan/scrcpy`, this package supports multiple Scrcpy versions,
|
|||
| 1.16~1.21 | `AdbScrcpyOptions1_16` |
|
||||
| 1.22~1.25 | `AdbScrcpyOptions1_22` |
|
||||
| 2.0 | `AdbScrcpyOptions2_0` |
|
||||
| 2.1 | `AdbScrcpyOptions2_1` |
|
||||
|
||||
### Push server binary
|
||||
|
||||
|
@ -73,9 +74,9 @@ To start the server, use the `AdbScrcpyClient.start()` method. It automatically
|
|||
```js
|
||||
import {
|
||||
AdbScrcpyClient,
|
||||
AdbScrcpyOptions2_0,
|
||||
AdbScrcpyOptions2_1,
|
||||
DEFAULT_SERVER_PATH,
|
||||
ScrcpyOptions2_0,
|
||||
ScrcpyOptions2_1,
|
||||
} from "@yume-chan/scrcpy";
|
||||
import SCRCPY_SERVER_VERSION from "@yume-chan/scrcpy/bin/version.js";
|
||||
|
||||
|
@ -84,18 +85,40 @@ const client: AdbScrcpyClient = await AdbScrcpyClient.start(
|
|||
DEFAULT_SERVER_PATH,
|
||||
// If server binary was downloaded manually, must provide the correct version
|
||||
SCRCPY_SERVER_VERSION,
|
||||
new AdbScrcpyOptions2_0(
|
||||
ScrcpyOptions2_0({
|
||||
new AdbScrcpyOptions2_1(
|
||||
ScrcpyOptions2_1({
|
||||
// options
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
const stdout: ReadableStream<string> = client.stdout;
|
||||
const { metadata: videoMetadata, stream: videoPacketStream } =
|
||||
await client.videoStream;
|
||||
const { metadata: audioMetadata, stream: audioPacketStream } =
|
||||
await client.audioStream;
|
||||
|
||||
// `undefined` if `video: false` option was given
|
||||
if (client.videoSteam) {
|
||||
const { metadata: videoMetadata, stream: videoPacketStream } =
|
||||
await client.videoStream;
|
||||
}
|
||||
|
||||
// `undefined` if `audio: false` option was given
|
||||
if (client.audioStream) {
|
||||
const metadata = await client.audioStream;
|
||||
switch (metadata.type) {
|
||||
case "disabled":
|
||||
// Audio not supported by device
|
||||
break;
|
||||
case "errored":
|
||||
// Other error when initializing audio
|
||||
break;
|
||||
case "success":
|
||||
// Audio packets in the codec specified in options
|
||||
const audioPacketStream: ReadableStream<ScrcpyMediaStreamPacket> =
|
||||
metadata.stream;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// `undefined` if `control: false` option was given
|
||||
const controlMessageWriter: ScrcpyControlMessageWriter | undefined =
|
||||
client.controlMessageWriter;
|
||||
const deviceMessageStream: ReadableStream<ScrcpyDeviceMessage> | undefined =
|
||||
|
@ -110,7 +133,6 @@ client.close();
|
|||
In Web Streams API, pipes will block its upstream when downstream's queue is full (back-pressure mechanism). If multiple streams are separated from the same source (for example, all Scrcpy streams are from the same USB or TCP connection), blocking one stream means blocking all of them, so it's important to always read from all streams, even if you don't care about their data.
|
||||
|
||||
```ts
|
||||
// when using `AdbScrcpyClient`
|
||||
stdout
|
||||
.pipeTo(
|
||||
new WritableStream<string>({
|
||||
|
@ -126,7 +148,7 @@ stdout
|
|||
|
||||
videoPacketStream
|
||||
.pipeTo(
|
||||
new WritableStream<ScrcpyVideoStreamPacket>({
|
||||
new WritableStream<ScrcpyMediaStreamPacket>({
|
||||
write: (packet) => {
|
||||
// Handle or ignore the video packet
|
||||
},
|
||||
|
@ -134,6 +156,16 @@ videoPacketStream
|
|||
)
|
||||
.catch(() => {});
|
||||
|
||||
audioPacketStream
|
||||
.pipeTo(
|
||||
new WritableStream<ScrcpyMediaStreamPacket>({
|
||||
write: (packet) => {
|
||||
// Handle or ignore the audio packet
|
||||
},
|
||||
})
|
||||
)
|
||||
.catch(() => {});
|
||||
|
||||
deviceMessageStream
|
||||
.pipeTo(
|
||||
new WritableStream<ScrcpyDeviceMessage>({
|
||||
|
|
|
@ -75,7 +75,7 @@ interface AdbScrcpyClientInit {
|
|||
process: AdbSubprocessProtocol;
|
||||
stdout: ReadableStream<string>;
|
||||
|
||||
videoStream: ReadableStream<Uint8Array>;
|
||||
videoStream: ReadableStream<Uint8Array> | undefined;
|
||||
audioStream: ReadableStream<Uint8Array> | undefined;
|
||||
controlStream:
|
||||
| ReadableWritablePair<Uint8Array, Consumable<Uint8Array>>
|
||||
|
@ -259,7 +259,7 @@ export class AdbScrcpyClient {
|
|||
return this._screenHeight;
|
||||
}
|
||||
|
||||
private _videoStream: Promise<AdbScrcpyVideoStream>;
|
||||
private _videoStream: Promise<AdbScrcpyVideoStream> | undefined;
|
||||
public get videoStream() {
|
||||
return this._videoStream;
|
||||
}
|
||||
|
@ -293,7 +293,9 @@ export class AdbScrcpyClient {
|
|||
this._process = process;
|
||||
this._stdout = stdout;
|
||||
|
||||
this._videoStream = this.createVideoStream(videoStream);
|
||||
this._videoStream = videoStream
|
||||
? this.createVideoStream(videoStream)
|
||||
: undefined;
|
||||
|
||||
this._audioStream = audioStream
|
||||
? this.createAudioStream(audioStream)
|
||||
|
|
|
@ -17,6 +17,10 @@ import type { ValueOrPromise } from "@yume-chan/struct";
|
|||
export interface AdbScrcpyConnectionOptions {
|
||||
scid: number;
|
||||
|
||||
video: boolean;
|
||||
|
||||
audio: boolean;
|
||||
|
||||
/**
|
||||
* Whether to create a control stream
|
||||
*/
|
||||
|
@ -26,18 +30,14 @@ export interface AdbScrcpyConnectionOptions {
|
|||
* In forward tunnel mode, read a byte from video socket on start to detect connection issues
|
||||
*/
|
||||
sendDummyByte: boolean;
|
||||
|
||||
audio: boolean;
|
||||
}
|
||||
|
||||
export const SCRCPY_SOCKET_NAME_PREFIX = "scrcpy";
|
||||
|
||||
export interface AdbScrcpyConnectionStreams {
|
||||
video: ReadableStream<Uint8Array>;
|
||||
audio: ReadableStream<Uint8Array> | undefined;
|
||||
control:
|
||||
| ReadableWritablePair<Uint8Array, Consumable<Uint8Array>>
|
||||
| undefined;
|
||||
video?: ReadableStream<Uint8Array>;
|
||||
audio?: ReadableStream<Uint8Array>;
|
||||
control?: ReadableWritablePair<Uint8Array, Consumable<Uint8Array>>;
|
||||
}
|
||||
|
||||
export abstract class AdbScrcpyConnection implements Disposable {
|
||||
|
@ -81,12 +81,25 @@ export class AdbScrcpyForwardConnection extends AdbScrcpyConnection {
|
|||
return this.adb.createSocket(this.socketName);
|
||||
}
|
||||
|
||||
private async connectAndRetry(): Promise<
|
||||
ReadableWritablePair<Uint8Array, Consumable<Uint8Array>>
|
||||
> {
|
||||
private async connectAndRetry(
|
||||
sendDummyByte: boolean
|
||||
): Promise<ReadableWritablePair<Uint8Array, Consumable<Uint8Array>>> {
|
||||
for (let i = 0; !this._disposed && i < 100; i += 1) {
|
||||
try {
|
||||
return await this.connect();
|
||||
const stream = await this.connect();
|
||||
if (sendDummyByte) {
|
||||
// Can't guarantee the stream will preserve message boundaries,
|
||||
// so buffer the stream
|
||||
const buffered = new BufferedReadableStream(
|
||||
stream.readable
|
||||
);
|
||||
await buffered.readExactly(1);
|
||||
return {
|
||||
readable: buffered.release(),
|
||||
writable: stream.writable,
|
||||
};
|
||||
}
|
||||
return stream;
|
||||
} catch (e) {
|
||||
// Maybe the server is still starting
|
||||
await delay(100);
|
||||
|
@ -95,30 +108,30 @@ export class AdbScrcpyForwardConnection extends AdbScrcpyConnection {
|
|||
throw new Error(`Can't connect to server after 100 retries`);
|
||||
}
|
||||
|
||||
private async connectVideoStream(): Promise<ReadableStream<Uint8Array>> {
|
||||
const { readable: stream } = await this.connectAndRetry();
|
||||
if (this.options.sendDummyByte) {
|
||||
// Can't guarantee the stream will preserve message boundaries,
|
||||
// so buffer the stream
|
||||
const buffered = new BufferedReadableStream(stream);
|
||||
await buffered.readExactly(1);
|
||||
return buffered.release();
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
public override async getStreams(): Promise<AdbScrcpyConnectionStreams> {
|
||||
const video = await this.connectVideoStream();
|
||||
let { sendDummyByte } = this.options;
|
||||
|
||||
const audio = this.options.audio
|
||||
? (await this.connectAndRetry()).readable
|
||||
: undefined;
|
||||
const streams: AdbScrcpyConnectionStreams = {};
|
||||
|
||||
const control = this.options.control
|
||||
? await this.connectAndRetry()
|
||||
: undefined;
|
||||
if (this.options.video) {
|
||||
const video = await this.connectAndRetry(sendDummyByte);
|
||||
streams.video = video.readable;
|
||||
sendDummyByte = false;
|
||||
}
|
||||
|
||||
return { video, audio, control };
|
||||
if (this.options.audio) {
|
||||
const audio = await this.connectAndRetry(sendDummyByte);
|
||||
streams.audio = audio.readable;
|
||||
sendDummyByte = false;
|
||||
}
|
||||
|
||||
if (this.options.control) {
|
||||
const control = await this.connectAndRetry(sendDummyByte);
|
||||
sendDummyByte = false;
|
||||
streams.control = control;
|
||||
}
|
||||
|
||||
return streams;
|
||||
}
|
||||
|
||||
public override dispose(): void {
|
||||
|
@ -161,15 +174,24 @@ export class AdbScrcpyReverseConnection extends AdbScrcpyConnection {
|
|||
}
|
||||
|
||||
public async getStreams(): Promise<AdbScrcpyConnectionStreams> {
|
||||
const { readable: video } = await this.accept();
|
||||
const streams: AdbScrcpyConnectionStreams = {};
|
||||
|
||||
const audio = this.options.audio
|
||||
? (await this.accept()).readable
|
||||
: undefined;
|
||||
if (this.options.video) {
|
||||
const video = await this.accept();
|
||||
streams.video = video.readable;
|
||||
}
|
||||
|
||||
const control = this.options.control ? await this.accept() : undefined;
|
||||
if (this.options.audio) {
|
||||
const audio = await this.accept();
|
||||
streams.audio = audio.readable;
|
||||
}
|
||||
|
||||
return { video, audio, control };
|
||||
if (this.options.control) {
|
||||
const control = await this.accept();
|
||||
streams.control = control;
|
||||
}
|
||||
|
||||
return streams;
|
||||
}
|
||||
|
||||
public override dispose() {
|
||||
|
|
|
@ -107,11 +107,12 @@ export class AdbScrcpyOptions1_16 extends AdbScrcpyOptionsBase<ScrcpyOptionsInit
|
|||
adb,
|
||||
{
|
||||
scid: -1,
|
||||
video: true,
|
||||
audio: false,
|
||||
// Old versions always have control stream no matter what the option is
|
||||
// Pass `control: false` to `Connection` will disable the control stream
|
||||
control: true,
|
||||
sendDummyByte: true,
|
||||
audio: false,
|
||||
},
|
||||
this.tunnelForwardOverride || this.value.tunnelForward
|
||||
);
|
||||
|
|
|
@ -32,9 +32,10 @@ export class AdbScrcpyOptions1_22 extends AdbScrcpyOptionsBase<ScrcpyOptionsInit
|
|||
adb,
|
||||
{
|
||||
scid: -1,
|
||||
video: true,
|
||||
audio: false,
|
||||
control: this.value.control,
|
||||
sendDummyByte: this.value.sendDummyByte,
|
||||
audio: false,
|
||||
},
|
||||
this.tunnelForwardOverride || this.value.tunnelForward
|
||||
);
|
||||
|
|
|
@ -9,27 +9,29 @@ import { AdbScrcpyClient, AdbScrcpyExitedError } from "../client.js";
|
|||
import type { AdbScrcpyConnection } from "../connection.js";
|
||||
|
||||
import { AdbScrcpyOptions1_16 } from "./1_16.js";
|
||||
import type { AdbScrcpyOptions } from "./types.js";
|
||||
import { AdbScrcpyOptionsBase } from "./types.js";
|
||||
|
||||
export class AdbScrcpyOptions2_0 extends AdbScrcpyOptionsBase<ScrcpyOptionsInit2_0> {
|
||||
public override async getEncoders(
|
||||
public static async getEncoders(
|
||||
adb: Adb,
|
||||
path: string,
|
||||
version: string
|
||||
): Promise<ScrcpyEncoder[]> {
|
||||
version: string,
|
||||
options: AdbScrcpyOptions<object>
|
||||
) {
|
||||
try {
|
||||
const client = await AdbScrcpyClient.start(
|
||||
adb,
|
||||
path,
|
||||
version,
|
||||
this
|
||||
options
|
||||
);
|
||||
await client.close();
|
||||
} catch (e) {
|
||||
if (e instanceof AdbScrcpyExitedError) {
|
||||
const encoders: ScrcpyEncoder[] = [];
|
||||
for (const line of e.output) {
|
||||
const encoder = this.parseEncoder(line);
|
||||
const encoder = options.parseEncoder(line);
|
||||
if (encoder) {
|
||||
encoders.push(encoder);
|
||||
}
|
||||
|
@ -40,6 +42,14 @@ export class AdbScrcpyOptions2_0 extends AdbScrcpyOptionsBase<ScrcpyOptionsInit2
|
|||
throw new Error("Unexpected error");
|
||||
}
|
||||
|
||||
public override async getEncoders(
|
||||
adb: Adb,
|
||||
path: string,
|
||||
version: string
|
||||
): Promise<ScrcpyEncoder[]> {
|
||||
return AdbScrcpyOptions2_0.getEncoders(adb, path, version, this);
|
||||
}
|
||||
|
||||
public override getDisplays(
|
||||
adb: Adb,
|
||||
path: string,
|
||||
|
@ -53,9 +63,10 @@ export class AdbScrcpyOptions2_0 extends AdbScrcpyOptionsBase<ScrcpyOptionsInit2
|
|||
adb,
|
||||
{
|
||||
scid: this.value.scid.value,
|
||||
video: true,
|
||||
audio: this.value.audio,
|
||||
control: this.value.control,
|
||||
sendDummyByte: this.value.sendDummyByte,
|
||||
audio: this.value.audio,
|
||||
},
|
||||
this.tunnelForwardOverride || this.value.tunnelForward
|
||||
);
|
||||
|
|
44
libraries/adb-scrcpy/src/options/2_1.ts
Normal file
44
libraries/adb-scrcpy/src/options/2_1.ts
Normal file
|
@ -0,0 +1,44 @@
|
|||
import type { Adb } from "@yume-chan/adb";
|
||||
import type {
|
||||
ScrcpyDisplay,
|
||||
ScrcpyEncoder,
|
||||
ScrcpyOptionsInit2_1,
|
||||
} from "@yume-chan/scrcpy";
|
||||
|
||||
import type { AdbScrcpyConnection } from "../connection.js";
|
||||
|
||||
import { AdbScrcpyOptions1_16 } from "./1_16.js";
|
||||
import { AdbScrcpyOptions2_0 } from "./2_0.js";
|
||||
import { AdbScrcpyOptionsBase } from "./types.js";
|
||||
|
||||
export class AdbScrcpyOptions2_1 extends AdbScrcpyOptionsBase<ScrcpyOptionsInit2_1> {
|
||||
public override async getEncoders(
|
||||
adb: Adb,
|
||||
path: string,
|
||||
version: string
|
||||
): Promise<ScrcpyEncoder[]> {
|
||||
return AdbScrcpyOptions2_0.getEncoders(adb, path, version, this);
|
||||
}
|
||||
|
||||
public override getDisplays(
|
||||
adb: Adb,
|
||||
path: string,
|
||||
version: string
|
||||
): Promise<ScrcpyDisplay[]> {
|
||||
return AdbScrcpyOptions1_16.getDisplays(adb, path, version, this);
|
||||
}
|
||||
|
||||
public override createConnection(adb: Adb): AdbScrcpyConnection {
|
||||
return AdbScrcpyOptions1_16.createConnection(
|
||||
adb,
|
||||
{
|
||||
scid: this.value.scid.value,
|
||||
video: this.value.video,
|
||||
audio: this.value.audio,
|
||||
control: this.value.control,
|
||||
sendDummyByte: this.value.sendDummyByte,
|
||||
},
|
||||
this.tunnelForwardOverride || this.value.tunnelForward
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,3 +1,20 @@
|
|||
{
|
||||
"extends": "./node_modules/@yume-chan/tsconfig/tsconfig.base.json"
|
||||
"extends": "./node_modules/@yume-chan/tsconfig/tsconfig.base.json",
|
||||
"references": [
|
||||
{
|
||||
"path": "../adb/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../event/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../scrcpy/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../stream-extra/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../struct/tsconfig.build.json"
|
||||
},
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,20 +1,5 @@
|
|||
{
|
||||
"references": [
|
||||
{
|
||||
"path": "../adb/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../event/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../scrcpy/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../stream-extra/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../struct/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.test.json"
|
||||
},
|
||||
|
|
|
@ -67,7 +67,7 @@ npx fetch-scrcpy-server <version>
|
|||
For example:
|
||||
|
||||
```
|
||||
npx fetch-scrcpy-server 1.25
|
||||
npx fetch-scrcpy-server 2.1
|
||||
```
|
||||
|
||||
Add it to `scripts.postinstall` in your `package.json`, so running `npm install` automatically invokes the script:
|
||||
|
@ -75,7 +75,7 @@ Add it to `scripts.postinstall` in your `package.json`, so running `npm install`
|
|||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"postinstall": "fetch-scrcpy-server 1.25"
|
||||
"postinstall": "fetch-scrcpy-server 2.1"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
@ -87,7 +87,7 @@ It will also save the version number to `bin/version.js`.
|
|||
```js
|
||||
import SCRCPY_SERVER_VERSION from "@yume-chan/scrcpy/bin/version.js";
|
||||
|
||||
console.log(SCRCPY_SERVER_VERSION); // "1.25"
|
||||
console.log(SCRCPY_SERVER_VERSION); // "2.1"
|
||||
```
|
||||
|
||||
### Use the server binary
|
||||
|
@ -171,6 +171,7 @@ The latest one may continue to work for future server versions, but there is no
|
|||
| 1.24 | `ScrcpyOptions1_24` |
|
||||
| 1.25 | `ScrcpyOptions1_25` |
|
||||
| 2.0 | `ScrcpyOptions2_0` |
|
||||
| 2.1 | `ScrcpyOptions2_1` |
|
||||
|
||||
## Reading and writing packets
|
||||
|
||||
|
@ -183,9 +184,9 @@ This packets operates on Web Streams API streams.
|
|||
Requires a `ReadableStream<Uint8Array>` that reads from the video socket.
|
||||
|
||||
```ts
|
||||
import { ScrcpyOptions1_25, ScrcpyVideoStreamPacket } from "@yume-chan/scrcpy";
|
||||
import { ScrcpyOptions2_1, ScrcpyVideoStreamPacket } from "@yume-chan/scrcpy";
|
||||
|
||||
const options = new ScrcpyOptions1_25({
|
||||
const options = new ScrcpyOptions2_1({
|
||||
// use the same version and options when starting the server
|
||||
});
|
||||
|
||||
|
@ -212,10 +213,10 @@ Control socket is optional if control is not enabled. Video socket and control s
|
|||
```ts
|
||||
import {
|
||||
ScrcpyControlMessageWriter,
|
||||
ScrcpyOptions1_25,
|
||||
ScrcpyOptions2_1,
|
||||
} from "@yume-chan/scrcpy";
|
||||
|
||||
const options = new ScrcpyOptions1_25({
|
||||
const options = new ScrcpyOptions2_1({
|
||||
// use the same version and options when starting the server
|
||||
});
|
||||
|
||||
|
@ -235,10 +236,7 @@ controlMessageWriter.injectText("Hello World!");
|
|||
Requires a `ReadableStream<Uint8Array>` that reads from the control socket.
|
||||
|
||||
```ts
|
||||
import {
|
||||
ScrcpyDeviceMessageDeserializeStream,
|
||||
ScrcpyOptions1_24,
|
||||
} from "@yume-chan/scrcpy";
|
||||
import { ScrcpyDeviceMessageDeserializeStream } from "@yume-chan/scrcpy";
|
||||
|
||||
const controlStream: ReadableWritablePair<Uint8Array, Uint8Array>; // get the stream yourself
|
||||
|
||||
|
@ -253,7 +251,7 @@ const deviceMessageStream: ReadableStream<ScrcpyDeviceMessage> =
|
|||
In Web Streams API, pipes will block its upstream when downstream's queue is full (back-pressure mechanism). If multiple streams are separated from the same source (for example, all Scrcpy streams are from the same USB or TCP connection), blocking one stream means blocking all of them, so it's important to always read from all streams, even if you don't care about their data.
|
||||
|
||||
```ts
|
||||
// when using `AdbScrcpyClient`
|
||||
// if using `AdbScrcpyClient`
|
||||
stdout
|
||||
.pipeTo(
|
||||
new WritableStream<string>({
|
||||
|
|
|
@ -115,7 +115,7 @@ export class ScrcpyOptions1_18 extends ScrcpyOptionsBase<
|
|||
);
|
||||
}
|
||||
|
||||
public serialize(): string[] {
|
||||
public override serialize(): string[] {
|
||||
return ScrcpyOptions1_16.serialize(
|
||||
this.value,
|
||||
ScrcpyOptions1_18.SERIALIZE_ORDER
|
||||
|
|
35
libraries/scrcpy/src/options/2_1.ts
Normal file
35
libraries/scrcpy/src/options/2_1.ts
Normal file
|
@ -0,0 +1,35 @@
|
|||
import { ScrcpyOptions1_21 } from "./1_21.js";
|
||||
import type { ScrcpyOptionsInit2_0 } from "./2_0.js";
|
||||
import { ScrcpyOptions2_0 } from "./2_0.js";
|
||||
import { ScrcpyOptionsBase } from "./types.js";
|
||||
|
||||
export interface ScrcpyOptionsInit2_1 extends ScrcpyOptionsInit2_0 {
|
||||
video?: boolean;
|
||||
audioSource?: "output" | "mic";
|
||||
}
|
||||
|
||||
export class ScrcpyOptions2_1 extends ScrcpyOptionsBase<
|
||||
ScrcpyOptionsInit2_1,
|
||||
ScrcpyOptions2_0
|
||||
> {
|
||||
public static readonly DEFAULTS = {
|
||||
...ScrcpyOptions2_0.DEFAULTS,
|
||||
video: true,
|
||||
audioSource: "output",
|
||||
} as const satisfies Required<ScrcpyOptionsInit2_1>;
|
||||
|
||||
public override get defaults(): Required<ScrcpyOptionsInit2_1> {
|
||||
return ScrcpyOptions2_1.DEFAULTS;
|
||||
}
|
||||
|
||||
public constructor(init: ScrcpyOptionsInit2_1) {
|
||||
super(new ScrcpyOptions2_0(init), {
|
||||
...ScrcpyOptions2_1.DEFAULTS,
|
||||
...init,
|
||||
});
|
||||
}
|
||||
|
||||
public override serialize(): string[] {
|
||||
return ScrcpyOptions1_21.serialize(this.value, this.defaults);
|
||||
}
|
||||
}
|
|
@ -7,6 +7,7 @@ export * from "./1_23.js";
|
|||
export * from "./1_24.js";
|
||||
export * from "./1_25/index.js";
|
||||
export * from "./2_0.js";
|
||||
export * from "./2_1.js";
|
||||
export * from "./codec.js";
|
||||
export * from "./latest.js";
|
||||
export * from "./types.js";
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { ScrcpyLogLevel1_18, ScrcpyVideoOrientation1_18 } from "./1_18.js";
|
||||
import type { ScrcpyOptionsInit2_0 } from "./2_0.js";
|
||||
import { ScrcpyOptions2_0 } from "./2_0.js";
|
||||
import type { ScrcpyOptionsInit2_1 } from "./2_1.js";
|
||||
import { ScrcpyOptions2_1 } from "./2_1.js";
|
||||
|
||||
export const ScrcpyLogLevel = ScrcpyLogLevel1_18;
|
||||
export type ScrcpyLogLevel = ScrcpyLogLevel1_18;
|
||||
|
@ -8,7 +8,7 @@ export type ScrcpyLogLevel = ScrcpyLogLevel1_18;
|
|||
export const ScrcpyVideoOrientation = ScrcpyVideoOrientation1_18;
|
||||
export type ScrcpyVideoOrientation = ScrcpyVideoOrientation1_18;
|
||||
|
||||
export type ScrcpyOptionsInitLatest = ScrcpyOptionsInit2_0;
|
||||
export class ScrcpyOptionsLatest extends ScrcpyOptions2_0 {}
|
||||
export type ScrcpyOptionsInitLatest = ScrcpyOptionsInit2_1;
|
||||
export class ScrcpyOptionsLatest extends ScrcpyOptions2_1 {}
|
||||
|
||||
export const ScrcpyLatestVersion = "2.0";
|
||||
export const ScrcpyLatestVersion = "2.1";
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue