Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(service-providers): add agora cloud recording #1669

Merged
merged 1 commit into from
Aug 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions desktop/renderer-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"@netless/flat-i18n": "workspace:*",
"@netless/flat-pages": "workspace:*",
"@netless/flat-server-api": "workspace:*",
"@netless/flat-service-provider-agora-cloud-recording": "workspace:*",
"@netless/flat-service-provider-agora-rtc-electron": "workspace:*",
"@netless/flat-service-provider-agora-rtm": "workspace:*",
"@netless/flat-service-provider-fastboard": "workspace:*",
Expand Down
7 changes: 7 additions & 0 deletions desktop/renderer-app/src/tasks/init-flat-services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,13 @@ export function initFlatServices(): void {
return service;
});

flatServices.register("recording", async () => {
const { AgoraCloudRecording } = await import(
"@netless/flat-service-provider-agora-cloud-recording"
);
return new AgoraCloudRecording();
});

flatServices.register(
[
"file-convert:doc",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,7 @@
display: flex;
justify-content: center;
align-items: center;
margin: 0
(
(
@topbar-right-btn-gap -
(@topbar-right-btn-width - @topbar-icon-width)
) / 2
);
margin: 0 ((@topbar-right-btn-gap - (@topbar-right-btn-width - @topbar-icon-width)) / 2);
padding: 4px;
cursor: pointer;
background-color: white;
Expand All @@ -28,6 +22,11 @@
&:hover {
background-color: var(--blue-1);
}

&:disabled {
cursor: wait;
opacity: 0.5;
}
}

.flat-color-scheme-dark {
Expand Down
12 changes: 9 additions & 3 deletions packages/flat-pages/src/utils/use-classroom-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ import { RouteNameType, usePushHistory } from "../utils/routes";
import { errorTips, useSafePromise } from "flat-components";
import { FlatServices } from "@netless/flat-services";

export type useClassRoomStoreConfig = Omit<ClassroomStoreConfig, "rtc" | "rtm" | "whiteboard">;
export type useClassRoomStoreConfig = Omit<
ClassroomStoreConfig,
"rtc" | "rtm" | "whiteboard" | "recording"
>;

export function useClassroomStore(config: useClassRoomStoreConfig): ClassroomStore | undefined {
const [classroomStore, setClassroomStore] = useState<ClassroomStore>();
Expand All @@ -29,14 +32,16 @@ export function useClassroomStore(config: useClassRoomStoreConfig): ClassroomSto
flatServices.requestService("videoChat"),
flatServices.requestService("textChat"),
flatServices.requestService("whiteboard"),
flatServices.requestService("recording"),
]),
).then(([videoChat, textChat, whiteboard]) => {
if (!isUnmounted && videoChat && textChat && whiteboard) {
).then(([videoChat, textChat, whiteboard, recording]) => {
if (!isUnmounted && videoChat && textChat && whiteboard && recording) {
classroomStore = new ClassroomStore({
...config,
rtc: videoChat,
rtm: textChat,
whiteboard,
recording,
});
setClassroomStore(classroomStore);
sp(classroomStore.init()).catch(e => {
Expand All @@ -56,6 +61,7 @@ export function useClassroomStore(config: useClassRoomStoreConfig): ClassroomSto
flatServices.shutdownService("videoChat");
flatServices.shutdownService("textChat");
flatServices.shutdownService("whiteboard");
flatServices.shutdownService("recording");
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
Expand Down
2 changes: 2 additions & 0 deletions packages/flat-services/src/flat-services.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { IServiceFile, IServiceFileCatalog } from "./services/file";
import { IServiceRecording } from "./services/recording";
import { IServiceTextChat } from "./services/text-chat";
import { IService } from "./services/typing";
import { IServiceVideoChat } from "./services/video-chat";
Expand All @@ -9,6 +10,7 @@ export type FlatServicesCatalog = IServiceFileCatalog & {
videoChat: IServiceVideoChat;
textChat: IServiceTextChat;
whiteboard: IServiceWhiteboard;
recording: IServiceRecording;
};

export type FlatServiceID = Extract<keyof FlatServicesCatalog, string>;
Expand Down
1 change: 1 addition & 0 deletions packages/flat-services/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export * from "./toaster";
export * from "./services/video-chat";
export * from "./services/text-chat";
export * from "./services/whiteboard";
export * from "./services/recording";
export * from "./services/file";

export * from "./providers/provider-file";
Expand Down
3 changes: 3 additions & 0 deletions packages/flat-services/src/services/recording/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# recording

Recording service is responsible for recording video chat and whiteboard.
7 changes: 7 additions & 0 deletions packages/flat-services/src/services/recording/events.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import type { Remitter } from "remitter";

export interface IServiceRecordingEventData {}

export type IServiceRecordingEventName = Extract<keyof IServiceRecordingEventData, string>;

export type IServiceRecordingEvents = Remitter<IServiceRecordingEventData>;
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
export * from "./constants";
export * from "./recording";
43 changes: 43 additions & 0 deletions packages/flat-services/src/services/recording/recording.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import type { RoomType } from "@netless/flat-server-api";
import type { ReadonlyVal } from "value-enhancer";
import type { IServiceRecordingEvents } from "./events";

import { Remitter } from "remitter";
import { SideEffectManager } from "side-effect-manager";
import { IService } from "../typing";

export interface IServiceRecording$Val {
readonly isRecording$: ReadonlyVal<boolean>;
}

export interface IServiceRecordingJoinRoomConfig {
roomID: string;
classroomType: RoomType;
}

export abstract class IServiceRecording implements IService {
public readonly sideEffect = new SideEffectManager();

public readonly events: IServiceRecordingEvents = new Remitter();

public abstract readonly $Val: IServiceRecording$Val;

public abstract readonly roomID: string | null;

public abstract readonly isRecording: boolean;

public abstract joinRoom(config: IServiceRecordingJoinRoomConfig): Promise<void>;

public abstract leaveRoom(): Promise<void>;

/** Use with try-catch. */
public abstract startRecording(): Promise<void>;

/** Use with try-catch. */
public abstract stopRecording(): Promise<void>;

public async destroy(): Promise<void> {
this.events.destroy();
this.sideEffect.flushAll();
}
}
2 changes: 2 additions & 0 deletions packages/flat-services/src/services/whiteboard/whiteboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ export abstract class IServiceWhiteboard {

public abstract joinRoom(config: IServiceWhiteboardJoinRoomConfig): Promise<void>;

public abstract leaveRoom(): Promise<void>;

public abstract render(el: HTMLElement): void;

public abstract setTheme(theme: "light" | "dark"): void;
Expand Down
24 changes: 22 additions & 2 deletions packages/flat-stores/src/classroom-store/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { globalStore } from "../global-store";
import { ClassModeType, RoomStatusLoadingType } from "./constants";
import { ChatStore } from "./chat-store";
import {
IServiceRecording,
IServiceTextChat,
IServiceVideoChat,
IServiceVideoChatMode,
Expand All @@ -37,6 +38,7 @@ export interface ClassroomStoreConfig {
rtc: IServiceVideoChat;
rtm: IServiceTextChat;
whiteboard: IServiceWhiteboard;
recording: IServiceRecording;
}

export type DeviceStateStorageState = Record<string, { camera: boolean; mic: boolean }>;
Expand Down Expand Up @@ -94,6 +96,7 @@ export class ClassroomStore {
public readonly rtm: IServiceTextChat;
public readonly chatStore: ChatStore;
public readonly whiteboardStore: WhiteboardStore;
public readonly recording: IServiceRecording;

public constructor(config: ClassroomStoreConfig) {
if (!globalStore.userUUID) {
Expand All @@ -108,6 +111,8 @@ export class ClassroomStore {
this.classMode = ClassModeType.Lecture;
this.rtc = config.rtc;
this.rtm = config.rtm;
this.recording = config.recording;

this.chatStore = new ChatStore({
roomUUID: this.roomUUID,
ownerUUID: this.ownerUUID,
Expand Down Expand Up @@ -139,6 +144,14 @@ export class ClassroomStore {
onStageUsersStorage: false,
});

this.sideEffect.addDisposer(
this.recording.$Val.isRecording$.subscribe(isRecording => {
runInAction(() => {
this.isRecording = isRecording;
});
}),
);

this.sideEffect.addDisposer(
reaction(
() => this.isRecording,
Expand Down Expand Up @@ -436,6 +449,13 @@ export class ClassroomStore {
);
}
}

if (this.isCreator) {
await this.recording.joinRoom({
roomID: this.roomUUID,
classroomType: this.roomType,
});
}
}

public async destroy(): Promise<void> {
Expand Down Expand Up @@ -669,11 +689,11 @@ export class ClassroomStore {
};

private async startRecording(): Promise<void> {
// @TODO add cloud recording
await this.recording.startRecording();
}

private async stopRecording(): Promise<void> {
// @TODO add cloud recording
await this.recording.stopRecording();
}

private async initRTC(): Promise<void> {
Expand Down
Loading