Skip to content

Commit

Permalink
feat(flat-web): integrate agora-rtc-sdk-ng
Browse files Browse the repository at this point in the history
Revert "feat(flat-web): integrate agora-rtc-sdk-ng"

This reverts commit 6e1463d.

wip
  • Loading branch information
hyrious committed Jun 7, 2021
1 parent b8b5bec commit 3c401f1
Show file tree
Hide file tree
Showing 15 changed files with 277 additions and 30 deletions.
3 changes: 2 additions & 1 deletion web/flat-web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"@ant-design/icons": "^4.6.2",
"@loadable/component": "^5.15.0",
"agora-rtc-sdk-ng": "^4.5.0",
"agora-rtm-sdk": "^1.4.3",
"antd": "^4.15.4",
"eventemitter3": "^4.0.7",
"mobx-react-lite": "^3.2.0",
Expand All @@ -42,7 +43,7 @@
"white-web-sdk": "^2.12.15"
},
"scripts": {
"postinstall": "esbuild-dev ./scripts/white-web-sdk.ts",
"postinstall": "esbuild-dev ./scripts/post-install.ts",
"start": "vite --open",
"build": "vite build",
"serve": "vite preview",
Expand Down
17 changes: 17 additions & 0 deletions web/flat-web/scripts/agora-rtm-sdk.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/**
* Get rid of "process.env.NODE_ENV" replace error in agora-rtm-sdk.
*
* @TODO: Remove this file when agora-rtm-sdk fix the code.
*/

/// <reference types="node" />

// https://vitejs.dev/guide/env-and-mode.html#production-replacement

import fs from "fs";
// NOTE: `import.meta.resolve` is still experimental
const file = require.resolve("agora-rtm-sdk");
const code = fs.readFileSync(file, "utf-8");
const modified = code.replace("process.env.NODE_ENV", "process\u200b.env.NODE_ENV");
fs.writeFileSync(file, modified);
console.log("agora-rtm-sdk: done!");
2 changes: 2 additions & 0 deletions web/flat-web/scripts/post-install.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import "./white-web-sdk";
import "./agora-rtm-sdk";
2 changes: 1 addition & 1 deletion web/flat-web/scripts/white-web-sdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ function hackAndReplaceMainScript(script: string, main: string): void {
// webpack will add polyfill under the hood so it is ok, but not rollup/esbuild
script = script.replace(/=require\([^)]+\)/g, "=void 0");
fs.writeFileSync(path.resolve(sdkPath, main), script);
console.log("hack: done!");
console.log("white-web-sdk: done!");
}

if (fs.existsSync(pkgJSON)) {
Expand Down
2 changes: 1 addition & 1 deletion web/flat-web/src/apiMiddleware/CloudRecording.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ export class CloudRecording {
height: 360,
fps: 15,
bitrate: 500,
defaultUserBackgroundImage: process.env.CLOUD_RECORDING_DEFAULT_AVATAR,
defaultUserBackgroundImage: import.meta.env.CLOUD_RECORDING_DEFAULT_AVATAR,
},
},
},
Expand Down
4 changes: 2 additions & 2 deletions web/flat-web/src/apiMiddleware/Rtm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import AgoraRTM, { RtmChannel, RtmClient } from "agora-rtm-sdk";
import polly from "polly-js";
import { v4 as uuidv4 } from "uuid";
import { AGORA, NODE_ENV } from "../constants/Process";
import { EventEmitter } from "events";
import { EventEmitter } from "eventemitter3";
import { RoomStatus } from "./flatServer/constants";
import { generateRTMToken } from "./flatServer/agora";
import { globalStore } from "../stores/GlobalStore";
Expand Down Expand Up @@ -145,7 +145,7 @@ export declare interface Rtm {
}

// eslint-disable-next-line no-redeclare
export class Rtm extends EventEmitter {
export class Rtm extends EventEmitter<keyof RTMEvents> {
public static MessageType = AgoraRTM.MessageType;

public client: RtmClient;
Expand Down
154 changes: 154 additions & 0 deletions web/flat-web/src/apiMiddleware/rtc/avatar.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
import type {
IAgoraRTCClient,
IAgoraRTCRemoteUser,
ICameraVideoTrack,
IMicrophoneAudioTrack,
IRemoteAudioTrack,
IRemoteVideoTrack,
ITrack,
} from "agora-rtc-sdk-ng";
import AgoraRTC from "agora-rtc-sdk-ng";
import type { User } from "../../stores/UserStore";
import type { RtcRoom } from "./room";

export interface RtcAvatarParams {
rtc: RtcRoom;
userUUID: string;
avatarUser: User;
}

/**
* @example
* const avatar = new RtcAvatar({ rtc, userUUID, avatarUser })
* avatar.element = el
* avatar.setCamera(true)
*/
export class RtcAvatar {
private readonly rtc: RtcRoom;

public readonly userUUID: string;
public readonly avatarUser: User;
public element?: HTMLElement;
public audioTrack?: ITrack;
public videoTrack?: ITrack;

private readonly isLocal: boolean;
private readonly remoteAudioTrack: Promise<IRemoteAudioTrack>;
private readonly remoteVideoTrack: Promise<IRemoteVideoTrack>;

private resolveRemoteAudioTrack?: (value: IRemoteAudioTrack) => void;
private resolveRemoteVideoTrack?: (value: IRemoteVideoTrack) => void;

constructor({ rtc, userUUID, avatarUser }: RtcAvatarParams) {
this.rtc = rtc;
this.userUUID = userUUID;
this.avatarUser = avatarUser;
this.isLocal = userUUID === avatarUser.userUUID;
this.remoteAudioTrack = new Promise<IRemoteAudioTrack>(resolve => {
this.resolveRemoteAudioTrack = resolve;
});
this.remoteVideoTrack = new Promise<IRemoteVideoTrack>(resolve => {
this.resolveRemoteVideoTrack = resolve;
});
if (!this.isLocal) {
this.setupExistingTracks();
this.client.on("user-published", this.onUserPublished);
}
}

private get client(): IAgoraRTCClient {
return this.rtc.client!;
}

private async setupExistingTracks(): Promise<void> {
const exist = this.client.remoteUsers.find(e => e.uid === this.avatarUser.rtcUID);
if (exist) {
if (exist.hasAudio) {
const audioTrack = await this.client.subscribe(exist, "audio");
this.resolveRemoteAudioTrack?.(audioTrack);
this.resolveRemoteAudioTrack = undefined;
}
if (exist.hasVideo) {
const videoTrack = await this.client.subscribe(exist, "video");
this.resolveRemoteVideoTrack?.(videoTrack);
this.resolveRemoteVideoTrack = undefined;
}
}
}

public destroy(): void {
if (!this.isLocal && this.client) {
this.client.off("user-published", this.onUserPublished);
}
this.resolveRemoteAudioTrack = undefined;
this.resolveRemoteVideoTrack = undefined;
}

private onUserPublished = async (
user: IAgoraRTCRemoteUser,
mediaType: "video" | "audio",
): Promise<void> => {
if (user.uid === this.avatarUser.rtcUID) {
const track = await this.client.subscribe(user, mediaType);
if (mediaType === "audio") {
this.resolveRemoteAudioTrack?.(track as IRemoteAudioTrack);
this.resolveRemoteAudioTrack = undefined;
} else {
this.resolveRemoteVideoTrack?.(track as IRemoteVideoTrack);
this.resolveRemoteVideoTrack = undefined;
}
}
};

public async setCamera(enable: boolean): Promise<void> {
try {
if (this.isLocal) {
const videoTrack = this.videoTrack as ICameraVideoTrack | undefined;
if (videoTrack) {
videoTrack.setEnabled(enable);
} else if (enable) {
const videoTrack = await AgoraRTC.createCameraVideoTrack({
encoderConfig: { width: 288, height: 216 },
});
this.videoTrack = videoTrack;
this.element && videoTrack.play(this.element);
await this.client.publish([videoTrack]);
}
} else {
if (!this.videoTrack && enable) {
const videoTrack = await this.remoteVideoTrack;
this.videoTrack = videoTrack;
this.element && videoTrack.play(this.element);
}
}
} catch (error) {
console.info("setCamera failed", error);
}
}

public async setMic(enable: boolean): Promise<void> {
try {
if (this.isLocal) {
const audioTrack = this.audioTrack as IMicrophoneAudioTrack | undefined;
if (audioTrack) {
audioTrack.setEnabled(enable);
} else if (enable) {
const audioTrack = await AgoraRTC.createMicrophoneAudioTrack();
this.audioTrack = audioTrack;
audioTrack.play();
await this.client.publish(audioTrack);
}
} else {
if (!this.audioTrack && enable) {
const audioTrack = await this.remoteAudioTrack;
this.audioTrack = audioTrack;
audioTrack.play();
}
}
} catch (error) {
console.info("setMic failed", error);
}
}
}

(window as any).RtcAvatar = RtcAvatar;
75 changes: 75 additions & 0 deletions web/flat-web/src/apiMiddleware/rtc/room.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import AgoraRTC, { IAgoraRTCClient } from "agora-rtc-sdk-ng";
import { AGORA } from "../../constants/Process";
import { globalStore } from "../../stores/GlobalStore";
import { generateRTCToken } from "../flatServer/agora";

AgoraRTC.setLogLevel(/* WARNING */ 2);

export enum RtcChannelType {
Communication = 0,
Broadcast = 1,
}

/**
* Flow:
* ```
* join() -> now it has `client`
* getLatency() -> number
* destroy()
* ```
*/
export class RtcRoom {
public client?: IAgoraRTCClient;

private roomUUID?: string;

public async join({
roomUUID,
isCreator,
rtcUID,
channelType,
}: {
roomUUID: string;
isCreator: boolean;
rtcUID: number;
channelType: RtcChannelType;
}): Promise<void> {
if (this.client) {
await this.destroy();
}

const mode = channelType === RtcChannelType.Communication ? "rtc" : "live";
this.client = AgoraRTC.createClient({ mode, codec: "vp8" });

this.client.on("token-privilege-will-expire", this.renewToken);

await this.client.setClientRole(
channelType === RtcChannelType.Broadcast && !isCreator ? "audience" : "host",
);
const token = globalStore.rtcToken || (await generateRTCToken(roomUUID));
await this.client.join(AGORA.APP_ID, roomUUID, token, rtcUID);

this.roomUUID = roomUUID;
}

public getLatency(): number {
return this.client?.getRTCStats().RTT ?? NaN;
}

public async destroy(): Promise<void> {
if (this.client) {
this.client.off("token-privilege-will-expire", this.renewToken);
await this.client.leave();
this.client = undefined;
}
}

private renewToken = async (): Promise<void> => {
if (this.client && this.roomUUID) {
const token = await generateRTCToken(this.roomUUID);
await this.client.renewToken(token);
}
};
}

(window as any).RtcRoom = RtcRoom;
Empty file.
2 changes: 1 addition & 1 deletion web/flat-web/src/constants/Process.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export const NODE_ENV = process.env.NODE_ENV;
export const NODE_ENV = import.meta.env.MODE;

export const NETLESS = Object.freeze({
APP_IDENTIFIER: import.meta.env.NETLESS_APP_IDENTIFIER,
Expand Down
30 changes: 9 additions & 21 deletions web/flat-web/src/stores/ClassRoomStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { message } from "antd";
import { action, autorun, makeAutoObservable, observable, runInAction } from "mobx";
import { v4 as uuidv4 } from "uuid";
import dateSub from "date-fns/sub";
import { Rtc as RTCAPI, RtcChannelType } from "../apiMiddleware/Rtc";
import { RtcRoom as RTCAPI, RtcChannelType } from "../apiMiddleware/rtc/room";
import {
ClassModeType,
NonDefaultUserProp,
Expand All @@ -30,11 +30,11 @@ import { globalStore } from "./GlobalStore";
import { NODE_ENV } from "../constants/Process";
import { useAutoRun } from "../utils/mobx";
import { User, UserStore } from "./UserStore";
import type { AgoraNetworkQuality, RtcStats } from "agora-electron-sdk/types/Api/native_type";
import { errorTips } from "../components/Tips/ErrorTips";
import { WhiteboardStore } from "./WhiteboardStore";
import { RouteNameType, usePushHistory } from "../utils/routes";
import { useSafePromise } from "../utils/hooks/lifecycle";
import { NetworkQuality } from "agora-rtc-sdk-ng";

export type { User } from "./UserStore";

Expand Down Expand Up @@ -118,6 +118,7 @@ export class ClassRoomStore {
this.rtcChannelType = config.recordingConfig.channelType ?? RtcChannelType.Communication;

this.rtc = new RTCAPI();
(window as any).rtc = this.rtc;
this.rtm = new RTMAPI();
this.cloudRecording = new CloudRecording({ roomUUID: config.roomUUID });

Expand Down Expand Up @@ -229,7 +230,6 @@ export class ClassRoomStore {
if (this.isRecording) {
await this.stopRecording();
}
this.rtc.leave();
} catch (e) {
console.error(e);
this.updateCalling(true);
Expand Down Expand Up @@ -496,13 +496,11 @@ export class ClassRoomStore {
}

public onRTCEvents(): void {
this.rtc.rtcEngine.on("rtcStats", this.checkDelay);
this.rtc.rtcEngine.on("networkQuality", this.checkNetworkQuality);
this.rtc.client?.on("network-quality", this.checkNetworkQuality);
}

public offRTCEvents(): void {
this.rtc.rtcEngine.off("rtcStats", this.checkDelay);
this.rtc.rtcEngine.off("networkQuality", this.checkNetworkQuality);
this.rtc.client?.off("network-quality", this.checkNetworkQuality);
}

public async destroy(): Promise<void> {
Expand Down Expand Up @@ -953,21 +951,11 @@ export class ClassRoomStore {
window.clearTimeout(this._collectChannelStatusTimeout);
}

private checkDelay = action((stats: RtcStats): void => {
this.networkQuality.delay = stats.lastmileDelay;
});

private checkNetworkQuality = action(
(
uid: number,
uplinkQuality: AgoraNetworkQuality,
downlinkQuality: AgoraNetworkQuality,
): void => {
if (uid === 0) {
// current user
this.networkQuality.uplink = uplinkQuality;
this.networkQuality.downlink = downlinkQuality;
}
({ uplinkNetworkQuality, downlinkNetworkQuality }: NetworkQuality): void => {
this.networkQuality.uplink = uplinkNetworkQuality;
this.networkQuality.downlink = downlinkNetworkQuality;
this.networkQuality.delay = this.rtc.getLatency();
},
);
}
Expand Down
2 changes: 1 addition & 1 deletion web/flat-web/src/stores/WhiteboardStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ export class WhiteboardStore {
},
floatBar: true,
isWritable: this.isWritable,
disableNewPencil: false,
disableNewPencil: true,
hotKeys: {
...DefaultHotKeys,
changeToSelector: "s",
Expand Down
Loading

0 comments on commit 3c401f1

Please sign in to comment.