feat(scrcpy): support server version 2.1

This commit is contained in:
Simon Chan 2023-06-22 12:58:47 +08:00
parent ef583779fa
commit 419a7559fe
No known key found for this signature in database
GPG key ID: A8B69F750B9BCEDD
16 changed files with 243 additions and 94 deletions

View file

@ -3,7 +3,7 @@
"version": "0.1.0", "version": "0.1.0",
"private": true, "private": true,
"scripts": { "scripts": {
"postinstall": "fetch-scrcpy-server 2.0 && node scripts/manifest.mjs", "postinstall": "fetch-scrcpy-server 2.1 && node scripts/manifest.mjs",
"dev": "next dev", "dev": "next dev",
"build": "next build", "build": "next build",
"start": "next start", "start": "next start",

View file

@ -320,7 +320,7 @@ export class ScrcpyPageState {
RECORD_STATE.recorder = new MatroskaMuxingRecorder(); RECORD_STATE.recorder = new MatroskaMuxingRecorder();
client.videoStream.then(({ stream, metadata }) => { client.videoStream!.then(({ stream, metadata }) => {
runInAction(() => { runInAction(() => {
RECORD_STATE.recorder.videoMetadata = metadata; RECORD_STATE.recorder.videoMetadata = metadata;
}); });

View file

@ -23,6 +23,7 @@ Similar to `@yume-chan/scrcpy`, this package supports multiple Scrcpy versions,
| 1.16~1.21 | `AdbScrcpyOptions1_16` | | 1.16~1.21 | `AdbScrcpyOptions1_16` |
| 1.22~1.25 | `AdbScrcpyOptions1_22` | | 1.22~1.25 | `AdbScrcpyOptions1_22` |
| 2.0 | `AdbScrcpyOptions2_0` | | 2.0 | `AdbScrcpyOptions2_0` |
| 2.1 | `AdbScrcpyOptions2_1` |
### Push server binary ### Push server binary
@ -73,9 +74,9 @@ To start the server, use the `AdbScrcpyClient.start()` method. It automatically
```js ```js
import { import {
AdbScrcpyClient, AdbScrcpyClient,
AdbScrcpyOptions2_0, AdbScrcpyOptions2_1,
DEFAULT_SERVER_PATH, DEFAULT_SERVER_PATH,
ScrcpyOptions2_0, ScrcpyOptions2_1,
} from "@yume-chan/scrcpy"; } from "@yume-chan/scrcpy";
import SCRCPY_SERVER_VERSION from "@yume-chan/scrcpy/bin/version.js"; import SCRCPY_SERVER_VERSION from "@yume-chan/scrcpy/bin/version.js";
@ -84,18 +85,40 @@ const client: AdbScrcpyClient = await AdbScrcpyClient.start(
DEFAULT_SERVER_PATH, DEFAULT_SERVER_PATH,
// If server binary was downloaded manually, must provide the correct version // If server binary was downloaded manually, must provide the correct version
SCRCPY_SERVER_VERSION, SCRCPY_SERVER_VERSION,
new AdbScrcpyOptions2_0( new AdbScrcpyOptions2_1(
ScrcpyOptions2_0({ ScrcpyOptions2_1({
// options // options
}) })
) )
); );
const stdout: ReadableStream<string> = client.stdout; const stdout: ReadableStream<string> = client.stdout;
const { metadata: videoMetadata, stream: videoPacketStream } =
await client.videoStream; // `undefined` if `video: false` option was given
const { metadata: audioMetadata, stream: audioPacketStream } = if (client.videoSteam) {
await client.audioStream; 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 = const controlMessageWriter: ScrcpyControlMessageWriter | undefined =
client.controlMessageWriter; client.controlMessageWriter;
const deviceMessageStream: ReadableStream<ScrcpyDeviceMessage> | undefined = 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. 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 ```ts
// when using `AdbScrcpyClient`
stdout stdout
.pipeTo( .pipeTo(
new WritableStream<string>({ new WritableStream<string>({
@ -126,7 +148,7 @@ stdout
videoPacketStream videoPacketStream
.pipeTo( .pipeTo(
new WritableStream<ScrcpyVideoStreamPacket>({ new WritableStream<ScrcpyMediaStreamPacket>({
write: (packet) => { write: (packet) => {
// Handle or ignore the video packet // Handle or ignore the video packet
}, },
@ -134,6 +156,16 @@ videoPacketStream
) )
.catch(() => {}); .catch(() => {});
audioPacketStream
.pipeTo(
new WritableStream<ScrcpyMediaStreamPacket>({
write: (packet) => {
// Handle or ignore the audio packet
},
})
)
.catch(() => {});
deviceMessageStream deviceMessageStream
.pipeTo( .pipeTo(
new WritableStream<ScrcpyDeviceMessage>({ new WritableStream<ScrcpyDeviceMessage>({

View file

@ -75,7 +75,7 @@ interface AdbScrcpyClientInit {
process: AdbSubprocessProtocol; process: AdbSubprocessProtocol;
stdout: ReadableStream<string>; stdout: ReadableStream<string>;
videoStream: ReadableStream<Uint8Array>; videoStream: ReadableStream<Uint8Array> | undefined;
audioStream: ReadableStream<Uint8Array> | undefined; audioStream: ReadableStream<Uint8Array> | undefined;
controlStream: controlStream:
| ReadableWritablePair<Uint8Array, Consumable<Uint8Array>> | ReadableWritablePair<Uint8Array, Consumable<Uint8Array>>
@ -259,7 +259,7 @@ export class AdbScrcpyClient {
return this._screenHeight; return this._screenHeight;
} }
private _videoStream: Promise<AdbScrcpyVideoStream>; private _videoStream: Promise<AdbScrcpyVideoStream> | undefined;
public get videoStream() { public get videoStream() {
return this._videoStream; return this._videoStream;
} }
@ -293,7 +293,9 @@ export class AdbScrcpyClient {
this._process = process; this._process = process;
this._stdout = stdout; this._stdout = stdout;
this._videoStream = this.createVideoStream(videoStream); this._videoStream = videoStream
? this.createVideoStream(videoStream)
: undefined;
this._audioStream = audioStream this._audioStream = audioStream
? this.createAudioStream(audioStream) ? this.createAudioStream(audioStream)

View file

@ -17,6 +17,10 @@ import type { ValueOrPromise } from "@yume-chan/struct";
export interface AdbScrcpyConnectionOptions { export interface AdbScrcpyConnectionOptions {
scid: number; scid: number;
video: boolean;
audio: boolean;
/** /**
* Whether to create a control stream * 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 * In forward tunnel mode, read a byte from video socket on start to detect connection issues
*/ */
sendDummyByte: boolean; sendDummyByte: boolean;
audio: boolean;
} }
export const SCRCPY_SOCKET_NAME_PREFIX = "scrcpy"; export const SCRCPY_SOCKET_NAME_PREFIX = "scrcpy";
export interface AdbScrcpyConnectionStreams { export interface AdbScrcpyConnectionStreams {
video: ReadableStream<Uint8Array>; video?: ReadableStream<Uint8Array>;
audio: ReadableStream<Uint8Array> | undefined; audio?: ReadableStream<Uint8Array>;
control: control?: ReadableWritablePair<Uint8Array, Consumable<Uint8Array>>;
| ReadableWritablePair<Uint8Array, Consumable<Uint8Array>>
| undefined;
} }
export abstract class AdbScrcpyConnection implements Disposable { export abstract class AdbScrcpyConnection implements Disposable {
@ -81,12 +81,25 @@ export class AdbScrcpyForwardConnection extends AdbScrcpyConnection {
return this.adb.createSocket(this.socketName); return this.adb.createSocket(this.socketName);
} }
private async connectAndRetry(): Promise< private async connectAndRetry(
ReadableWritablePair<Uint8Array, Consumable<Uint8Array>> sendDummyByte: boolean
> { ): Promise<ReadableWritablePair<Uint8Array, Consumable<Uint8Array>>> {
for (let i = 0; !this._disposed && i < 100; i += 1) { for (let i = 0; !this._disposed && i < 100; i += 1) {
try { 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) { } catch (e) {
// Maybe the server is still starting // Maybe the server is still starting
await delay(100); await delay(100);
@ -95,30 +108,30 @@ export class AdbScrcpyForwardConnection extends AdbScrcpyConnection {
throw new Error(`Can't connect to server after 100 retries`); 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> { public override async getStreams(): Promise<AdbScrcpyConnectionStreams> {
const video = await this.connectVideoStream(); let { sendDummyByte } = this.options;
const audio = this.options.audio const streams: AdbScrcpyConnectionStreams = {};
? (await this.connectAndRetry()).readable
: undefined;
const control = this.options.control if (this.options.video) {
? await this.connectAndRetry() const video = await this.connectAndRetry(sendDummyByte);
: undefined; 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 { public override dispose(): void {
@ -161,15 +174,24 @@ export class AdbScrcpyReverseConnection extends AdbScrcpyConnection {
} }
public async getStreams(): Promise<AdbScrcpyConnectionStreams> { public async getStreams(): Promise<AdbScrcpyConnectionStreams> {
const { readable: video } = await this.accept(); const streams: AdbScrcpyConnectionStreams = {};
const audio = this.options.audio if (this.options.video) {
? (await this.accept()).readable const video = await this.accept();
: undefined; 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() { public override dispose() {

View file

@ -107,11 +107,12 @@ export class AdbScrcpyOptions1_16 extends AdbScrcpyOptionsBase<ScrcpyOptionsInit
adb, adb,
{ {
scid: -1, scid: -1,
video: true,
audio: false,
// Old versions always have control stream no matter what the option is // Old versions always have control stream no matter what the option is
// Pass `control: false` to `Connection` will disable the control stream // Pass `control: false` to `Connection` will disable the control stream
control: true, control: true,
sendDummyByte: true, sendDummyByte: true,
audio: false,
}, },
this.tunnelForwardOverride || this.value.tunnelForward this.tunnelForwardOverride || this.value.tunnelForward
); );

View file

@ -32,9 +32,10 @@ export class AdbScrcpyOptions1_22 extends AdbScrcpyOptionsBase<ScrcpyOptionsInit
adb, adb,
{ {
scid: -1, scid: -1,
video: true,
audio: false,
control: this.value.control, control: this.value.control,
sendDummyByte: this.value.sendDummyByte, sendDummyByte: this.value.sendDummyByte,
audio: false,
}, },
this.tunnelForwardOverride || this.value.tunnelForward this.tunnelForwardOverride || this.value.tunnelForward
); );

View file

@ -9,27 +9,29 @@ import { AdbScrcpyClient, AdbScrcpyExitedError } from "../client.js";
import type { AdbScrcpyConnection } from "../connection.js"; import type { AdbScrcpyConnection } from "../connection.js";
import { AdbScrcpyOptions1_16 } from "./1_16.js"; import { AdbScrcpyOptions1_16 } from "./1_16.js";
import type { AdbScrcpyOptions } from "./types.js";
import { AdbScrcpyOptionsBase } from "./types.js"; import { AdbScrcpyOptionsBase } from "./types.js";
export class AdbScrcpyOptions2_0 extends AdbScrcpyOptionsBase<ScrcpyOptionsInit2_0> { export class AdbScrcpyOptions2_0 extends AdbScrcpyOptionsBase<ScrcpyOptionsInit2_0> {
public override async getEncoders( public static async getEncoders(
adb: Adb, adb: Adb,
path: string, path: string,
version: string version: string,
): Promise<ScrcpyEncoder[]> { options: AdbScrcpyOptions<object>
) {
try { try {
const client = await AdbScrcpyClient.start( const client = await AdbScrcpyClient.start(
adb, adb,
path, path,
version, version,
this options
); );
await client.close(); await client.close();
} catch (e) { } catch (e) {
if (e instanceof AdbScrcpyExitedError) { if (e instanceof AdbScrcpyExitedError) {
const encoders: ScrcpyEncoder[] = []; const encoders: ScrcpyEncoder[] = [];
for (const line of e.output) { for (const line of e.output) {
const encoder = this.parseEncoder(line); const encoder = options.parseEncoder(line);
if (encoder) { if (encoder) {
encoders.push(encoder); encoders.push(encoder);
} }
@ -40,6 +42,14 @@ export class AdbScrcpyOptions2_0 extends AdbScrcpyOptionsBase<ScrcpyOptionsInit2
throw new Error("Unexpected error"); 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( public override getDisplays(
adb: Adb, adb: Adb,
path: string, path: string,
@ -53,9 +63,10 @@ export class AdbScrcpyOptions2_0 extends AdbScrcpyOptionsBase<ScrcpyOptionsInit2
adb, adb,
{ {
scid: this.value.scid.value, scid: this.value.scid.value,
video: true,
audio: this.value.audio,
control: this.value.control, control: this.value.control,
sendDummyByte: this.value.sendDummyByte, sendDummyByte: this.value.sendDummyByte,
audio: this.value.audio,
}, },
this.tunnelForwardOverride || this.value.tunnelForward this.tunnelForwardOverride || this.value.tunnelForward
); );

View 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
);
}
}

View file

@ -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"
},
]
} }

View file

@ -1,20 +1,5 @@
{ {
"references": [ "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" "path": "./tsconfig.test.json"
}, },

View file

@ -67,7 +67,7 @@ npx fetch-scrcpy-server <version>
For example: 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: 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 ```json
{ {
"scripts": { "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 ```js
import SCRCPY_SERVER_VERSION from "@yume-chan/scrcpy/bin/version.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 ### 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.24 | `ScrcpyOptions1_24` |
| 1.25 | `ScrcpyOptions1_25` | | 1.25 | `ScrcpyOptions1_25` |
| 2.0 | `ScrcpyOptions2_0` | | 2.0 | `ScrcpyOptions2_0` |
| 2.1 | `ScrcpyOptions2_1` |
## Reading and writing packets ## 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. Requires a `ReadableStream<Uint8Array>` that reads from the video socket.
```ts ```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 // 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 ```ts
import { import {
ScrcpyControlMessageWriter, ScrcpyControlMessageWriter,
ScrcpyOptions1_25, ScrcpyOptions2_1,
} from "@yume-chan/scrcpy"; } from "@yume-chan/scrcpy";
const options = new ScrcpyOptions1_25({ const options = new ScrcpyOptions2_1({
// use the same version and options when starting the server // 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. Requires a `ReadableStream<Uint8Array>` that reads from the control socket.
```ts ```ts
import { import { ScrcpyDeviceMessageDeserializeStream } from "@yume-chan/scrcpy";
ScrcpyDeviceMessageDeserializeStream,
ScrcpyOptions1_24,
} from "@yume-chan/scrcpy";
const controlStream: ReadableWritablePair<Uint8Array, Uint8Array>; // get the stream yourself 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. 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 ```ts
// when using `AdbScrcpyClient` // if using `AdbScrcpyClient`
stdout stdout
.pipeTo( .pipeTo(
new WritableStream<string>({ new WritableStream<string>({

View file

@ -115,7 +115,7 @@ export class ScrcpyOptions1_18 extends ScrcpyOptionsBase<
); );
} }
public serialize(): string[] { public override serialize(): string[] {
return ScrcpyOptions1_16.serialize( return ScrcpyOptions1_16.serialize(
this.value, this.value,
ScrcpyOptions1_18.SERIALIZE_ORDER ScrcpyOptions1_18.SERIALIZE_ORDER

View 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);
}
}

View file

@ -7,6 +7,7 @@ export * from "./1_23.js";
export * from "./1_24.js"; export * from "./1_24.js";
export * from "./1_25/index.js"; export * from "./1_25/index.js";
export * from "./2_0.js"; export * from "./2_0.js";
export * from "./2_1.js";
export * from "./codec.js"; export * from "./codec.js";
export * from "./latest.js"; export * from "./latest.js";
export * from "./types.js"; export * from "./types.js";

View file

@ -1,6 +1,6 @@
import { ScrcpyLogLevel1_18, ScrcpyVideoOrientation1_18 } from "./1_18.js"; import { ScrcpyLogLevel1_18, ScrcpyVideoOrientation1_18 } from "./1_18.js";
import type { ScrcpyOptionsInit2_0 } from "./2_0.js"; import type { ScrcpyOptionsInit2_1 } from "./2_1.js";
import { ScrcpyOptions2_0 } from "./2_0.js"; import { ScrcpyOptions2_1 } from "./2_1.js";
export const ScrcpyLogLevel = ScrcpyLogLevel1_18; export const ScrcpyLogLevel = ScrcpyLogLevel1_18;
export type ScrcpyLogLevel = ScrcpyLogLevel1_18; export type ScrcpyLogLevel = ScrcpyLogLevel1_18;
@ -8,7 +8,7 @@ export type ScrcpyLogLevel = ScrcpyLogLevel1_18;
export const ScrcpyVideoOrientation = ScrcpyVideoOrientation1_18; export const ScrcpyVideoOrientation = ScrcpyVideoOrientation1_18;
export type ScrcpyVideoOrientation = ScrcpyVideoOrientation1_18; export type ScrcpyVideoOrientation = ScrcpyVideoOrientation1_18;
export type ScrcpyOptionsInitLatest = ScrcpyOptionsInit2_0; export type ScrcpyOptionsInitLatest = ScrcpyOptionsInit2_1;
export class ScrcpyOptionsLatest extends ScrcpyOptions2_0 {} export class ScrcpyOptionsLatest extends ScrcpyOptions2_1 {}
export const ScrcpyLatestVersion = "2.0"; export const ScrcpyLatestVersion = "2.1";