Skip to content

Commit e779f80

Browse files
committed
refactor(scrcpy): uncouple from ADB
refs #427
1 parent 6887d85 commit e779f80

55 files changed

Lines changed: 706 additions & 613 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

apps/demo/package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,11 @@
2222
"@yume-chan/adb-backend-ws": "^0.0.9",
2323
"@yume-chan/adb-credential-web": "^0.0.16",
2424
"@yume-chan/android-bin": "^0.0.16",
25-
"@yume-chan/async": "^2.1.4",
25+
"@yume-chan/async": "^2.2.0",
2626
"@yume-chan/b-tree": "^0.0.16",
2727
"@yume-chan/event": "^0.0.16",
2828
"@yume-chan/scrcpy": "^0.0.16",
29+
"@yume-chan/stream-extra": "^0.0.16",
2930
"@yume-chan/struct": "^0.0.16",
3031
"mobx": "^6.5.0",
3132
"mobx-react-lite": "^3.4.0",
@@ -45,6 +46,6 @@
4546
"eslint": "8.8.0",
4647
"eslint-config-next": "12.1.6",
4748
"source-map-loader": "^3.0.1",
48-
"typescript": "4.7.2"
49+
"typescript": "^4.7.3"
4950
}
5051
}

apps/demo/src/components/connect.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import { DefaultButton, Dialog, Dropdown, IDropdownOption, PrimaryButton, ProgressIndicator, Stack, StackItem } from '@fluentui/react';
2-
import { Adb, AdbBackend, AdbPacketData, AdbPacketInit, InspectStream, pipeFrom, ReadableStream, WritableStream } from '@yume-chan/adb';
2+
import { Adb, AdbBackend, AdbPacketData, AdbPacketInit } from '@yume-chan/adb';
33
import AdbDirectSocketsBackend from "@yume-chan/adb-backend-direct-sockets";
44
import AdbWebUsbBackend, { AdbWebUsbBackendWatcher } from '@yume-chan/adb-backend-webusb';
55
import AdbWsBackend from '@yume-chan/adb-backend-ws';
66
import AdbWebCredentialStore from '@yume-chan/adb-credential-web';
7+
import { InspectStream, pipeFrom, ReadableStream, WritableStream } from '@yume-chan/stream-extra';
78
import { observer } from 'mobx-react-lite';
89
import { useCallback, useEffect, useMemo, useState } from 'react';
910
import { GlobalState } from '../state';

apps/demo/src/components/grid.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ export const Grid = withDisplayName('Grid')(({
170170
const [autoScroll, setAutoScroll] = useState(true);
171171

172172
const handleScroll = useStableCallback(() => {
173-
if (bodyRef) {
173+
if (bodyRef && bodyRef.scrollTop !== scrollTop) {
174174
if (autoScroll) {
175175
if (scrollTop < bodyRef.scrollHeight - bodyRef.clientHeight && bodyRef.scrollTop < scrollTop) {
176176
setAutoScroll(false);

apps/demo/src/components/terminal.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
// cspell: ignore scrollback
22

3-
import { AbortController, AdbSubprocessProtocol, encodeUtf8, WritableStream } from "@yume-chan/adb";
3+
import { AdbSubprocessProtocol, encodeUtf8 } from "@yume-chan/adb";
44
import { AutoDisposable } from "@yume-chan/event";
5+
import { AbortController, WritableStream } from '@yume-chan/stream-extra';
56
import { Terminal } from 'xterm';
67
import { FitAddon } from 'xterm-addon-fit';
78
import { SearchAddon } from 'xterm-addon-search';

apps/demo/src/pages/file-manager.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ import { Breadcrumb, concatStyleSets, ContextualMenu, ContextualMenuItem, Detail
22
import { FileIconType, getFileTypeIconProps, initializeFileTypeIcons } from "@fluentui/react-file-type-icons";
33
import { useConst } from '@fluentui/react-hooks';
44
import { getIcon } from '@fluentui/style-utilities';
5-
import { AdbFeatures, ADB_SYNC_MAX_PACKET_SIZE, ChunkStream, LinuxFileType, type AdbSyncEntry } from '@yume-chan/adb';
5+
import { AdbFeatures, ADB_SYNC_MAX_PACKET_SIZE, LinuxFileType, type AdbSyncEntry } from '@yume-chan/adb';
6+
import { ChunkStream } from '@yume-chan/stream-extra';
67
import { action, autorun, makeAutoObservable, observable, runInAction } from "mobx";
78
import { observer } from "mobx-react-lite";
89
import { NextPage } from "next";

apps/demo/src/pages/install.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { DefaultButton, ProgressIndicator, Stack } from "@fluentui/react";
2-
import { ADB_SYNC_MAX_PACKET_SIZE, ChunkStream, ReadableStream } from "@yume-chan/adb";
2+
import { ADB_SYNC_MAX_PACKET_SIZE } from "@yume-chan/adb";
3+
import { ChunkStream } from '@yume-chan/stream-extra';
34
import { action, makeAutoObservable, observable, runInAction } from "mobx";
45
import { observer } from "mobx-react-lite";
56
import { NextPage } from "next";

apps/demo/src/pages/logcat.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { ICommandBarItemProps, Stack, StackItem } from "@fluentui/react";
22
import { makeStyles, mergeClasses, shorthands } from "@griffel/react";
3-
import { AbortController, ReadableStream, WritableStream } from '@yume-chan/adb';
43
import { AndroidLogEntry, AndroidLogPriority, Logcat } from '@yume-chan/android-bin';
4+
import { AbortController, ReadableStream, WritableStream } from '@yume-chan/stream-extra';
55
import { action, autorun, makeAutoObservable, observable, runInAction } from "mobx";
66
import { observer } from "mobx-react-lite";
77
import { NextPage } from "next";

apps/demo/src/pages/reverse.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { decodeUtf8, WritableStream } from "@yume-chan/adb";
1+
import { decodeUtf8 } from "@yume-chan/adb";
2+
import { WritableStream } from '@yume-chan/stream-extra';
23
import { makeAutoObservable, reaction, runInAction } from "mobx";
34
import { observer } from "mobx-react-lite";
45
import { NextPage } from "next";

apps/demo/src/pages/scrcpy.tsx

Lines changed: 38 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,17 @@ import { NextPage } from "next";
77
import Head from "next/head";
88
import { CSSProperties, ReactNode, useEffect, useState } from "react";
99

10-
import { ADB_SYNC_MAX_PACKET_SIZE, ChunkStream, InspectStream, ReadableStream, WritableStream } from '@yume-chan/adb';
10+
import { ADB_SYNC_MAX_PACKET_SIZE } from '@yume-chan/adb';
1111
import { EventEmitter } from "@yume-chan/event";
12-
import { AdbScrcpyClient, AndroidKeyCode, AndroidKeyEventAction, AndroidMotionEventAction, CodecOptions, DEFAULT_SERVER_PATH, ScrcpyClient, ScrcpyLogLevel, ScrcpyOptions1_24, ScrcpyVideoOrientation, TinyH264Decoder, WebCodecsDecoder, type H264Decoder, type H264DecoderConstructor, type VideoStreamPacket } from "@yume-chan/scrcpy";
12+
import { AdbScrcpyClient, AdbScrcpyOptions1_22, AndroidKeyCode, AndroidKeyEventAction, AndroidMotionEventAction, CodecOptions, DEFAULT_SERVER_PATH, ScrcpyLogLevel, ScrcpyOptions1_24, ScrcpyVideoOrientation, TinyH264Decoder, WebCodecsDecoder, type H264Decoder, type H264DecoderConstructor, type VideoStreamPacket } from "@yume-chan/scrcpy";
1313
import SCRCPY_SERVER_VERSION from '@yume-chan/scrcpy/bin/version';
14+
import { ChunkStream, InspectStream, ReadableStream, WritableStream } from '@yume-chan/stream-extra';
1415

1516
import { DemoModePanel, DeviceView, DeviceViewRef, ExternalLink } from "../components";
1617
import { GlobalState } from "../state";
1718
import { CommonStackTokens, formatSpeed, Icons, ProgressStream, RouteStackProps } from "../utils";
1819

19-
const SERVER_URL = new URL('@yume-chan/scrcpy/bin/scrcpy-server?url', import.meta.url).toString();
20+
const SERVER_URL = new URL('@yume-chan/scrcpy/bin/scrcpy-server?url', import.meta.url);
2021

2122
class FetchWithProgress {
2223
public readonly promise: Promise<Uint8Array>;
@@ -30,11 +31,11 @@ class FetchWithProgress {
3031
private progressEvent = new EventEmitter<[download: number, total: number]>();
3132
public get onProgress() { return this.progressEvent.event; }
3233

33-
public constructor(url: string) {
34+
public constructor(url: string | URL) {
3435
this.promise = this.fetch(url);
3536
}
3637

37-
private async fetch(url: string) {
38+
private async fetch(url: string | URL) {
3839
const response = await window.fetch(url);
3940
this._total = Number.parseInt(response.headers.get('Content-Length') ?? '0', 10);
4041
this.progressEvent.fire([this._downloaded, this._total]);
@@ -223,8 +224,6 @@ const SettingItem = observer(function SettingItem({
223224
});
224225

225226
class ScrcpyPageState {
226-
adbScrcpyClient: AdbScrcpyClient | null = null;
227-
228227
running = false;
229228

230229
deviceView: DeviceViewRef | null = null;
@@ -243,7 +242,7 @@ class ScrcpyPageState {
243242
get rotatedWidth() { return state.rotate & 1 ? state.height : state.width; }
244243
get rotatedHeight() { return state.rotate & 1 ? state.width : state.height; }
245244

246-
client: ScrcpyClient | undefined = undefined;
245+
client: AdbScrcpyClient | undefined = undefined;
247246

248247
async pushServer() {
249248
const serverBuffer = await fetchServer();
@@ -254,21 +253,22 @@ class ScrcpyPageState {
254253
controller.close();
255254
},
256255
})
257-
.pipeTo(this.adbScrcpyClient!.pushServer());
256+
.pipeTo(AdbScrcpyClient.pushServer(GlobalState.device!));
258257
}
259258

260259
encoders: string[] = [];
261260
updateEncoders = async () => {
262261
try {
263262
await this.pushServer();
264263

265-
const encoders = await this.adbScrcpyClient!.getEncoders(
264+
const encoders = await AdbScrcpyClient.getEncoders(
265+
GlobalState.device!,
266266
DEFAULT_SERVER_PATH,
267267
SCRCPY_SERVER_VERSION,
268-
new ScrcpyOptions1_24({
268+
new AdbScrcpyOptions1_22(new ScrcpyOptions1_24({
269269
logLevel: ScrcpyLogLevel.Debug,
270270
tunnelForward: this.settings.tunnelForward,
271-
})
271+
}))
272272
);
273273

274274
runInAction(() => {
@@ -297,13 +297,14 @@ class ScrcpyPageState {
297297
try {
298298
await this.pushServer();
299299

300-
const displays = await this.adbScrcpyClient!.getDisplays(
300+
const displays = await AdbScrcpyClient.getDisplays(
301+
GlobalState.device!,
301302
DEFAULT_SERVER_PATH,
302303
SCRCPY_SERVER_VERSION,
303-
new ScrcpyOptions1_24({
304+
new AdbScrcpyOptions1_22(new ScrcpyOptions1_24({
304305
logLevel: ScrcpyLogLevel.Debug,
305306
tunnelForward: this.settings.tunnelForward,
306-
})
307+
}))
307308
);
308309

309310
runInAction(() => {
@@ -362,7 +363,7 @@ class ScrcpyPageState {
362363
iconProps: { iconName: Icons.Orientation },
363364
iconOnly: true,
364365
text: 'Rotate Device',
365-
onClick: () => { this.client!.rotateDevice(); },
366+
onClick: () => { this.client!.control!.rotateDevice(); },
366367
});
367368

368369
result.push({
@@ -631,8 +632,6 @@ class ScrcpyPageState {
631632
autorun(() => {
632633
if (GlobalState.device) {
633634
runInAction(() => {
634-
this.adbScrcpyClient = new AdbScrcpyClient(GlobalState.device!);
635-
636635
this.encoders = [];
637636
this.settings.encoderName = undefined;
638637

@@ -723,7 +722,7 @@ class ScrcpyPageState {
723722
.pipeThrough(new ProgressStream(action((progress) => {
724723
this.serverUploadedSize = progress;
725724
})))
726-
.pipeTo(this.adbScrcpyClient!.pushServer());
725+
.pipeTo(AdbScrcpyClient.pushServer(GlobalState.device!));
727726

728727
runInAction(() => {
729728
this.serverUploadSpeed = this.serverUploadedSize - this.debouncedServerUploadedSize;
@@ -746,7 +745,7 @@ class ScrcpyPageState {
746745
}), 1000);
747746
});
748747

749-
const options = new ScrcpyOptions1_24({
748+
const options = new AdbScrcpyOptions1_22(new ScrcpyOptions1_24({
750749
logLevel: ScrcpyLogLevel.Debug,
751750
...this.settings,
752751
sendDeviceMeta: false,
@@ -757,15 +756,16 @@ class ScrcpyPageState {
757756
level: decoder.maxLevel,
758757
})
759758
: undefined,
760-
});
759+
}));
761760

762761
runInAction(() => {
763762
this.log = [];
764763
this.log.push(`[client] Server version: ${SCRCPY_SERVER_VERSION}`);
765764
this.log.push(`[client] Server arguments: ${options.formatServerArguments().join(' ')}`);
766765
});
767766

768-
const client = await this.adbScrcpyClient!.start(
767+
const client = await AdbScrcpyClient.start(
768+
GlobalState.device!,
769769
DEFAULT_SERVER_PATH,
770770
SCRCPY_SERVER_VERSION,
771771
options
@@ -792,7 +792,7 @@ class ScrcpyPageState {
792792

793793
client.exit.then(this.dispose);
794794

795-
client.onClipboardChange(content => {
795+
client.control!.onClipboardChange(content => {
796796
window.navigator.clipboard.writeText(content);
797797
});
798798

@@ -846,7 +846,7 @@ class ScrcpyPageState {
846846
}
847847
e.currentTarget.setPointerCapture(e.pointerId);
848848

849-
this.client.pressBackOrTurnOnScreen(AndroidKeyEventAction.Down);
849+
this.client.control!.pressBackOrTurnOnScreen(AndroidKeyEventAction.Down);
850850
};
851851

852852
handleBackPointerUp = (e: React.PointerEvent<HTMLDivElement>) => {
@@ -858,7 +858,7 @@ class ScrcpyPageState {
858858
return;
859859
}
860860

861-
this.client.pressBackOrTurnOnScreen(AndroidKeyEventAction.Up);
861+
this.client.control!.pressBackOrTurnOnScreen(AndroidKeyEventAction.Up);
862862
};
863863

864864
handleHomePointerDown = async (e: React.PointerEvent<HTMLDivElement>) => {
@@ -871,7 +871,7 @@ class ScrcpyPageState {
871871
}
872872
e.currentTarget.setPointerCapture(e.pointerId);
873873

874-
await this.client.injectKeyCode({
874+
await this.client.control!.injectKeyCode({
875875
action: AndroidKeyEventAction.Down,
876876
keyCode: AndroidKeyCode.Home,
877877
repeat: 0,
@@ -888,7 +888,7 @@ class ScrcpyPageState {
888888
return;
889889
}
890890

891-
await this.client.injectKeyCode({
891+
await this.client.control!.injectKeyCode({
892892
action: AndroidKeyEventAction.Up,
893893
keyCode: AndroidKeyCode.Home,
894894
repeat: 0,
@@ -906,7 +906,7 @@ class ScrcpyPageState {
906906
}
907907
e.currentTarget.setPointerCapture(e.pointerId);
908908

909-
await this.client.injectKeyCode({
909+
await this.client.control!.injectKeyCode({
910910
action: AndroidKeyEventAction.Down,
911911
keyCode: AndroidKeyCode.AppSwitch,
912912
repeat: 0,
@@ -923,7 +923,7 @@ class ScrcpyPageState {
923923
return;
924924
}
925925

926-
await this.client.injectKeyCode({
926+
await this.client.control!.injectKeyCode({
927927
action: AndroidKeyEventAction.Up,
928928
keyCode: AndroidKeyCode.AppSwitch,
929929
repeat: 0,
@@ -967,9 +967,11 @@ class ScrcpyPageState {
967967
}
968968

969969
const { x, y } = this.calculatePointerPosition(e.clientX, e.clientY);
970-
this.client.injectTouch({
970+
this.client.control!.injectTouch({
971971
action,
972972
pointerId: e.pointerType === "mouse" ? BigInt(-1) : BigInt(e.pointerId),
973+
screenWidth: this.client!.screenWidth!,
974+
screenHeight: this.client!.screenHeight!,
973975
pointerX: x,
974976
pointerY: y,
975977
pressure: e.pressure * 65535,
@@ -1004,7 +1006,9 @@ class ScrcpyPageState {
10041006
e.stopPropagation();
10051007

10061008
const { x, y } = this.calculatePointerPosition(e.clientX, e.clientY);
1007-
this.client.injectScroll({
1009+
this.client.control!.injectScroll({
1010+
screenWidth: this.client!.screenWidth!,
1011+
screenHeight: this.client!.screenHeight!,
10081012
pointerX: x,
10091013
pointerY: y,
10101014
scrollX: -Math.sign(e.deltaX),
@@ -1024,7 +1028,7 @@ class ScrcpyPageState {
10241028

10251029
const { key, code } = e;
10261030
if (key.match(/^[!-`{-~]$/i)) {
1027-
this.client!.injectText(key);
1031+
this.client.control!.injectText(key);
10281032
return;
10291033
}
10301034

@@ -1035,13 +1039,13 @@ class ScrcpyPageState {
10351039
} as Record<string, AndroidKeyCode | undefined>)[code];
10361040

10371041
if (keyCode) {
1038-
await this.client.injectKeyCode({
1042+
await this.client.control!.injectKeyCode({
10391043
action: AndroidKeyEventAction.Down,
10401044
keyCode,
10411045
metaState: 0,
10421046
repeat: 0,
10431047
});
1044-
await this.client.injectKeyCode({
1048+
await this.client.control!.injectKeyCode({
10451049
action: AndroidKeyEventAction.Up,
10461050
keyCode,
10471051
metaState: 0,

apps/demo/src/pages/shell.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { Icons, RouteStackProps } from '../utils';
1111

1212
let terminal: import('../components/terminal').AdbTerminal;
1313
if (typeof window !== 'undefined') {
14-
const { AdbTerminal } = await import('../components/terminal');
14+
const { AdbTerminal } = require('../components/terminal');
1515
terminal = new AdbTerminal();
1616
}
1717

0 commit comments

Comments
 (0)