# 支持的平台与 Electron 版本

-   MacOS 支持 x64、arm64架构
-   Windows 支持 x86、x64架构

**<font color=red>Electron 版本要求： 14.0.0~22.3.27</font>**

# 1、接入步骤

## 1.1、安装

**<font color=red>注意: 不同平台依赖包不互通</font>**

**第一步：安装 @electron/remote**

```shell
npm install @electron/remote --global-style --legacy-peer-deps
```

**第二步：安装 plaso-electron-sdk**

```shell
npm install @plasosdk/plaso-electron-sdk --global-style
```

**<font color=red>注意: 不同平台需要单独安装，尤其是MacOS，请分别在Intel芯片和Apple芯片的电脑上安装</font>**

## electron-builder打包特别说明
使用electron-builder打包时，需要对工程的node_modules中的agora-electron-sdk-v4进行特殊处理，该包是在安装@plasosdk/plaso-electron-sdk时动态安装的，因此需要通过配置extraResources单独拷贝。配置入如下
```json
"extraResources": [
    {
        "from": "node_modules/agora-electron-sdk-v4",
        "to": "app/node_modules/agora-electron-sdk-v4",
        "filter": ["**/*"]
    },
    {
        "from": "node_modules/agora-electron-sdk-v4/node_modules",
        "to": "app/node_modules/agora-electron-sdk-v4/node_modules",
        "filter": ["**/*"]
    }
]
```
同时，由于这个包是通过extraResources进行拷贝的，需要在签名脚本中额外配置这个包的路径。

另外在打包MacOS的包时有几个需要额外进行授权的可执行文件。建议通过额外的脚本来执行。下面的可执行文件是在安装@plasosdk/plaso-electron-sdk时动态下载的，因此授权的脚本需要保证是在文件下载之后。
```shell
// 截图会用到
chmod +x node_modules/@plasosdk/plaso-electron-sdk/lib/flameshot  

// 桌面共享会用到
chmod +x node_modules/@plasosdk/plaso-electron-sdk/lib/PlasoALD/PlasoALD.scpt
```

MacOS打包完毕后，建议安装打好的包后自行验证上述的操作时候生效了。
- 检查包内容中node_modules里面的agora-electron-sdk-v4包中是否包含node_modules，包含则说明打包正确。
- 上课测试截图功能是否正常，截图正常说明授权正确。
- 上课测试桌面共享功能，使用屏幕共享，并在浏览器里面播放一段视频，结束课堂后检查回放中能否听到桌面共享那一段播放的视频的声音，能听到说明授权正确。

## 1.2、使用

### 1.2.1、在主进程中使用

需要在主进程加载 `@plasosdk/plaso-electron-sdk` 依赖包

```ts
require('@plasosdk/plaso-electron-sdk');

// electron 版本>=14.0.0 时：需要在主进程里 初始化、启动 remote
const electronVersion = process.versions['electron'];
if (electronVersion && versionComp(electronVersion, '14.0.0') >= 0) {
    const electronStore = require('@electron/remote/main');
    electronStore.initialize();
    // mainWindow: 主进程打开的渲染进程窗口
    electronStore.enable(mainWindow.webContents);
}

// 通过 initRemoteMain方法 传入 remoteMain
const remoteMain = require('@electron/remote/main');
const { initRemoteMain } = require('@plasosdk/plaso-electron-sdk');
initRemoteMain(remoteMain);
```

### 1.2.2、在渲染进程中使用

<a id="open-sdk-window-params"></a>

**打开实时课堂/备课课堂方法入参类型定义**
```ts
interface CreateClassPamras {
    classOptions: Object;
    electronWinOptions?: Electron.BrowserWindowConstructorOptions;
    onClassWindowReadyFn?: (winId: number) => void
    onClassWindowLeaveFn?: (winId: number) => void
    onClassFinishedFn?: (meetingId: string) => void;
    onSaveBoardFn?: (
        params: {
            fileInfo: FileParams[];
            fileName?: string;
        },
        callback: (result: boolean) => void,
    ) => void;
    onOpenResourceCenterFn?: () => void;
    onGetExtFileNameFn?: (...args: any[]) => Promise<string>;
}
```

#### 1.2.3.1、打开实时课堂

```ts
// 代码示例
const PlasoElectronSdk = window.require('@plasosdk/plaso-electron-sdk');
const createLiveClassParams: CreateClassPamras = { classOptions: { query } };
PlasoElectronSdk.createLiveClassWindow(createLiveClassParams);
```

入参详见[实时课堂参数说明](#live-class-params)

#### 1.2.3.2、打开备课课堂

```ts
// 代码示例
const PlasoElectronSdk = window.require('@plasosdk/plaso-electron-sdk');
const createPrepareClassParams: CreateClassPamras = { classOptions: { loginName: 'hello', userName: 'world' } };
PlasoElectronSdk.createPrepareClassWindow(createClassParams);
```

入参详见[备课课堂入参说明](#prepare-class-params)


<a id="live-class-params"></a>
# 2、实时课堂入参说明

## 2.1、参数 classOptions

```
类型：Object
```

### 2.1.1、属性列表

| 参数 | 是否必传 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- | --- |
| query | 是 | string | 无 | 进课堂必传字段，具体拼接逻辑见下文[query 属性说明](#query) |
| displayAvatarUrl | 否 | string | 无 | 用户头像地址 |
| classMembers | 否 | object[] | 无 | 1、课对应的班级用户信息<br />2、初始化课堂参与人<br /><br />3、最多支持 2000 人，需要支持更多学生需要联系伯索平台进行额外申请<br />{<br /><br />/** 唯一标识该用户的 id \*/<br />loginName: string,<br /><br />/** 用户显示的姓名 _/<br />name: string,<br />/\*\* 用户角色，"speaker","assistant","listener","superlistener" 之一 _/<br />upimeRole: string,<br />/** 用户的 id，和云学堂业务强相关，sdk 用户非必要 \*/<br />unique_id: number \| string<br />/** 用户头像图片的 url，非必要 \*/<br />displayAvatarUrl: string,<br />} |
| enableENC | 否 | boolean | true | 是否启用降噪 |
| enableRTC3A | 否 | boolean | true | 是否启用 3A。<br />false：关闭回音消除、关闭降噪、关闭增益控制 |
| supportShowResourceCenter | 否 | boolean | false | true：工具栏显示 资料中心 按钮，但资料中心的逻辑需要用户自己实现 |
| supportSaveBoard | 否 | boolean | false | 是否支持保存板书，依赖于资料中心实现保存和插入板书文件 |
| enableLiveNewShareRegion | 否 | boolean | false | 是否允许区域共享 |
| enableLiveNewShareInTouch | 否 | boolean | false | 是否支持触屏模式下的新桌面共享（左侧新增按钮窗口来切换显示工具栏）<br />建议开启 |
| enableLiveNewShare | 否 | boolean | false | 是否支持新桌面共享<br />开启新桌面共享需要开启 electron 透明窗口,且可能触发 electron 本身存在的长时间透传导致的在应用上鼠标失焦问题 |
| enableLiveSign | 否 | boolean | false | 是否支持签到 |
| residentCamera | 否 | boolean | false | 常驻摄像头：只对学生或游客生效 |
|  |  |  |  |  |

<a id="query"></a>
### 2.1.1、query 属性

**query 属性格式示例**：

```
appId=plaso&appType=liveclassSDK&d_dimension=1280x720&dhost=https%3A%2F%2Fdev.plaso.cn%2F&enableHiliter=true&enableNewClassExam=1&enableVideoMark=true&loginName=t_1&mediaType=video&meetingId=test_1742442362&meetingType=public&signature=A226198904A392579B98987FB4CD5478AB3F5587&upimeTeacherTool=1151&userName=%E8%80%81%E5%B8%881&userType=speaker&validBegin=1742442364&validTime=99999&vendorType=2&videoStream=2
```

#### 2.1.1.1、组成 queryParams 对象

```ts
interface IQueryParams {
    appId: string;
    signature: string;
    validBegin: number;
    validTime: number;
    endTime: number;
    appType: string;
    userType: string;
    meetingType: string;
    mediaType: string;
    meetingId: string;
    loginName: string;
    userName: string;
    d_dimension: string;
    vendorType: number;
    videoStream: number;
    enableNewClassExam: number;
    d_enableReRecording: number;

    topic?: string;
    onlineMode?: number;
    d_enableOMO?: number;
    d_delayEndTimes?: number;
    d_delayEnd?: number;
    d_restrictAssistantPerm?: number;
    d_enableAvatarFreeScale?: number;
    d_enableObjectEraser?: number;
    d_vote?: number;
    d_sharpness?: number;
    isNewMT?: number;
    d_enableDualCamera?: number;
}
```

##### 2.1.1.1.1、必传参数表格说明

| 参数 | 类型 | 说明 |
| --- | --- | --- |
| appId | string | 在申请接入时，伯索平台给予的 appId |
| signature | string | 签名字符串，根据queryParams中除去signature参数的其他参数生成，生成示例参考[根据queryParams对象生成签名字符串](#generate-signature) |
| validBegin | number | 请求课堂**开始生效起始时间**的 Unix Epoch 时间戳，单位秒：（时间戳/1000 再取整） |
| validTime | number | 请求的**签名在课堂的有效时间段**（断网重连后会重新校验签名），单位秒，建议: 24 _ 60 _ 60 s |
| endTime | number | 请求课堂**结束时间**的 Unix Epoch 时间戳，单位秒：（时间戳/1000 再取整） |
| appType | string | 应用类型，必填，目前为固定值：liveclassSDK |
| userType | string | 用户类型，目前有三个值可选： speaker，assistant，listener； <br />speaker：主讲，有控制其他 listener 是否可写可说话的权限；<br />assistant：助教，也有控制权限<br />listener：学生 |
| meetingType | string | 课堂类型，传入值：private。 当选择 private 类型时，每一个进入课堂者，必须提供 loginName，这是唯一标识该用户的 id，相同的 loginName 登录，后进入者会使前一个强制登出 |
| mediaType | string | 媒体类型：audio, video<br />audio: 语音实时课堂<br />video：有头像权限的课堂，含语音权限 |
| meetingId | string | 课堂 ID，唯一标识该课堂；使用 ASSIIC 字符，不得包含/，,空格等；长度在 40 字节以内的字符串 |
| loginName | string | **唯一标识该用户的 id**，不能为空，相同的 loginName 登录，后面一个会使前面一个登出； |
| d_dimension | string | 1280x720 定义界面尺寸为 16:9 界面 |
| userName | string | 登录的用户名，在列表中显示用 |
| vendorType | number | rtc 类型 <br />2：agora |
| videoStream | number | 课堂类型，与 mediaType 需要对应上<br />2：视频课堂<br />1：语音课堂 |
| enableNewClassExam | number | 新版随堂测选择题：1；<br />新版随堂测填空题：2；<br />新版随堂测选择+填空：3，建议：3 |
| d_enableReRecording | number | 主讲、助教都可以重新录制课堂：3 |
|  |  |  |
|  |  |  |

##### 2.1.1.1.2、可选参数表格说明

| 参数 | 类型 | 默认值 | 建议值 | 说明 |
| :-: | :-: | :-: | :-: | :-- |
| topic | string | 无 | 非空 | 显示该课堂的名称 |
| onlineMode | number | 6 | 无 | 上台学生数，1:最大上台 1 个学生，6：最大上台 6 个学生，12：最大上台 12 个学生。默认：6 |
| d_enableOMO | number | 0 | 无 | 是否开启站播模式,1：开启；0：关闭 |
| d_delayEndTimes | number | 0 | 无 | 单节课最大延迟下课次数：1、2、3、4 |
| d_delayEnd | number | 0 | 无 | 单次延时时间，单位秒：5*60、10 * 60、15*60、20 * 60、30\*60 |
| d_restrictAssistantPerm | number | 0 | 无 | 是否开启了：大班课限制助教权限<br />1：开启<br />0：关闭 |
| d_enableAvatarFreeScale | number | 0 | 无 | 开启头像任意比例缩放<br />0:关闭 1:开启，默认关闭 （非录制课堂、非无头像录制模式下，裁剪掉的老师/助教头像也会被录到回放中） |
| d_enableObjectEraser | number | 0 | 无 | 新板书配置，二进制位存储<br />default: 0；默认关闭对象擦<br />7:手写(对象擦);<br /> |
| d_vote | number | 0 | 1 | 0：未开放投票；1：开放投票 |
| d_sharpness | number | 10 | 无 | 头像推流清晰度、桌面共享清晰度<br />**仅 onlineMode 为 1 时生效**：<br />10：标清 20：高清 21: 高清流畅 30：超清 31: 超清流畅 |
| isNewMT | number | 0 | 1 | 是否支持 移动授课模式；<br />建议传 1 |
| d_enableDualCamera | number | 0 | 无 | 是否开启双摄，1：开启，0： 关闭 |
| recordType | number | 无 | 无 | 配置 recordAvartor 设置录制对象，参数说明参考[附录 9.1](#record-type) |
| recordAvator | string | '' | 无 | 传入老师/助教的`loginName`表示录制对应人的头像 |
| recordScreen | string | '' | 无 | 传入'screen'表示录制屏幕（当前仅支持录制老师屏幕）|
|  |  |  |  |  |

<a id="generate-signature"></a>
#### 2.1.1.2、根据 queryParams 对象生成签名字符串

（1）**用户把 queryParams 作为参数传给自己的接口，接口返回值必须返回签名字符串：signature**

（2）获取 signature 后需要把 signature 加到 queryParams 中作为一个参数

```ts
queryParams.signature = signature;
```

（3）**服务端接口生成 signature 规则**如下：

https://open.plaso.cn/doc-6285173?nav=01HEQ5Y5RXKMCPBPF6S8T3VK56

**signKey**：机构申请接入时，伯索平台给予的 key

```ts
/*！----------演示签名代码------------- */

// 业务参数，根据接口文档中定义，自行生成填写
const queryParams = { name: 'test' };

//平台分配给机构的key
const signKey = 'a_secret';

// 业务参数和签名验证混合后排序
const afterSortParam = Object.keys(queryParams).sort();

const res = [];
for (let key of afterSortParam) {
    res.push(`${key}=${queryParams[key]}`);
}

// 排序后连接成字符串
const content = res.join('&');

const crypto = require('crypto');

// 使用分配的signKey来加密生成签名串signature
const signature = crypto.createHmac('sha1', signKey).update(content).digest('hex').toUpperCase();
```

#### 2.1.1.3、生成 query 字符串

（1）获取 完整的 queryParams 后，遍历对象生成 query 字符串

每个参数值用 encodeURIComponent 编码

```ts
// 代码示例：其中 queryParams 对象包含signature
function genQuery(queryParams) {
    const keys = Object.keys(queryParams).sort();
    const res = [];
    for (let key of keys) {
        res.push(key + '=' + encodeURIComponent(queryParams[key]));
    }
    return res.join('&');
}
genQuery(queryParams);
```

<a id="prepare-class-params"></a>
# 3、备课课堂入参说明

## 3.1、参数 classOptions

```
类型：Object
```

### 3.1.1、必传参数

| 参数      | 类型   | 说明                                                                                 |
| --------- | ------ | ------------------------------------------------------------------------------------ |
| loginName | String | **唯一标识该用户的 id**，不能为空，相同的 loginName 登录，后面一个会使前面一个登出； |
| userName  | String | 登录的用户名，在列表中显示用                                                         |
|           |        |                                                                                      |

### 3.1.2、可选参数

| 参数 | 类型 | 说明 |
| --- | --- | --- |
| displayAvatarUrl | String | 用户头像地址 |
| topic | String | 默认值是中文的 “备课课堂” |
| **d_enableObjectEraser** | number | 新板书配置，二进制位存储<br />default: 0；默认关闭对象擦<br />7:手写(对象擦);<br />**注意：该值需要和实时课堂的传值一样** |
|  |  |  |

**注意：**

1、备课课堂直接通过任务栏关闭不会清空本地记录的板书内容，下次进入后会 板书交互会和上次进入的板书 配置一致（即使 d_enableObjectEraser 参数 值变动了）

# 4、打开实时课堂/备课课堂通用参数说明

## 4.1、参数 electronWinOptions 

> **即将弃用**: 不推荐传入，SDK内部默认设置了一些窗口参数，为了保证最佳体验，不要传入此参数。

Electron的窗口参数，详情参考 [Electron官方文档](https://www.electronjs.org/zh/docs/latest/api/browser-window#new-browserwindowoptions)。

```ts
type electronWinOptions = Electron.BrowserWindowConstructiorOptions;
```

## 4.2、参数回调 onClassWindowReadyFn

```ts
// 课堂窗口打开渲染成功后的回调，回调参数为 窗口id
type onClassWindowReadyFn = (winId: number) => void;
```

## 4.3、参数回调 onClassWindowLeaveFn

```ts
// 课堂窗口关闭后的回调，回调参数为 窗口id
type onClassWindowLeaveFn = (winId: number) => void;
```

## 4.4、参数回调 onClassFinishedFn

```ts
// 课堂结束后的回调，回调参数为 课堂的meetingId
type onClassFinishedFn = (meetingId: string) => void;

```

## 4.5、参数回调 onSaveBoardFn

**注意：**

1、**filePath 对应的文件资源，用户保存在自己的云端时，需要把 本次保存的备课文件的 相关资源放在同一特定目录下**

2、**每次保存生成的备课文件 都放在一个新的目录下，不同的备课文件不能共用一个目录**

3、**备课保存的资源文件名 不能更改，info.pb 是固定的文件名**

```ts
// 保存板书方法，具体的保存逻辑由外部实现，取消保存板书时，callback传false, 不然传true

type FileParams = {
    /** 备课相关资源文件的本地地址*/
    filePath: string[];
    /** 备课文件 类型*/
    fileType: 'png' | 'pb';
};

type onSaveBoardFn = (
    params: {
        fileInfo: FileParams[];
        fileName?: string;
    },
    callback: (result: boolean) => void,
) => void;
```

## 4.6、参数回调 onOpenResourceCenterFn

```ts
// 通知外部用户打开自己的资料中心，资料中心的具体ui和逻辑由外部用户自己实现
// 推荐：通过onClassWindowReadyFn回调的winId拿到课堂窗口实例，用户的云盘通过一个BrowserWindow
// 和课堂窗口组成父子窗口，云盘是子窗口，并且云盘窗口打开时保持置顶，这样来保证云盘打开时始终可见并且跟随课堂窗口。
type onOpenResourceCenterFn = () => void;
```

## 4.7、参数回调 onGetExtFileNameFn

```ts
// 通过 insertObject 插入的文件传入 参数 info 时，怎么从info中获取文件的可访问地址的逻辑在用户那，所以需要函数从外部用户获取外部用户传入的文件地址
// 其中info会作为args中的第一个参数回传

type onGetExtFileNameFn = (...args: any[]) => Promise<string>;
```

# 5、API参考

## 5.1、PlasoElectronSdk.initLogConfig

**初始化课堂窗口日志位置**，窗口崩溃时会在同级目录下生成 reports 文件夹存储 dump，**在 调用 createLiveClassWindow 前设置**

**日志默认位置**：

```js
require('path').join(require('electron').app.getPath('userData'), 'P403FileTemp');

// Windows：C:\Users\${userName}\AppData\Roaming\${appName}\P403FileTemp
// Mac：/Users/${userName}/Application\ Support/${appName}/P403FileTemp
```

参数示例：

```ts
// 代码示例
const PlasoElectronSdk = window.require('@plasosdk/plaso-electron-sdk');
const logFilePath = 'C:/Users/userName/Desktop/electronDemo/electron12.0.18_x32/resources/app';
PlasoElectronSdk.initLogConfig(logFilePath);
```

## 5.2、PlasoElectronSdk.getVersion

返回包的版本，格式：x.x.x

```ts
type getVersion = () => string;
```

## 5.3、PlasoElectronSdk.createLiveClassWindow

**创建实时课堂窗口**

```ts
function createLiveClassWindow(params: CreateClassPamras): void;
```
参数详见[打开实时课堂/备课课堂方法入参类型定义](#open-sdk-window-params)

## 5.4、PlasoElectronSdk.createPrepareClassWindow

**创建备课课堂窗口**
```ts
function createLiveClassWindow(params: CreateClassPamras): void;
```
参数详见[打开实时课堂/备课课堂方法入参类型定义](#open-sdk-window-params)

## 5.5、PlasoElectronSdk.insertObject

用户从自己的资料中心往**实时课堂/备课课堂**插入文件

```ts
// 插入的文件类型暴露在PlasoElectronSdk上，PlasoElectronSdk.FILE_TYPE
const PlasoElectronSdk = window.require('@plasosdk/plaso-electron-sdk');
const enum FILE_TYPE {
    PPT,
    IMAGE,
    PDF,
    /** 这种模式需要用户实际传入的是WORD转成的PDF地址 */
    WORD,
    /** 这种模式需要用户实际传入的是EXCEL转成的PDF地址 */
    EXCEL,
    AUDIO,
    VIDEO,
    /** 这种模式传入真实WORD地址 */
    DOC,
    /** 这种模式传入真实EXCEL地址 */
    XLS,
    /** 备课文件 */
    PREPARE_LESSONS,
};
```

```ts
/** 插入外部云盘里的文件，文件需要遵循特定的数据结构 */
/**
 * @typedef {Object} fileDataObj
 * @property {PlasoElectronSdk.FILE_TYPE} type 插入文件的格式,内容参考 PlasoElectronSdk.FILE_TYPE
 * @property {any[]} [info] 具体的文件信息数组，除备课外，内容都由用户自己定义
 * @property {string} [title] 文件名称，需要带后缀
 * @property {string} [url] 文件的可下载地址
 */
/**
 * @param {fileDataObj} fileData 文件数据
 */
type insertObject = (fileData) => void;

// 使用方式
const PlasoElectronSdk = window.require('@plasosdk/plaso-electron-sdk');
PlasoElectronSdk.insertObject(fileData);
```

### 5.5.1、插入备课文件

1、 插入 备课文件 的格式如下,其中 fileLocationPath 为 插入的备课文件资源的地址前缀，比如要本地插入一个备课文件（info.pb）,其完整地址为 C:\Users\xxx\AppData\Roaming\plaso_sdk\prepareLessonsTemp\draft.swap\info.pb，则此时 fileLocationPath = C:\Users\xxx\AppData\Roaming\plaso_sdk\prepareLessonsTemp\draft.swap

```ts
// 备课的fileData格式
const fileData = {
    type: PlasoElectronSdk.FILE_TYPE.PREPARE_LESSONS,
    info: ['pb', , , fileLocationPath],
};
```

**注意**：

1、**保存备课文件时，需要把 info.pb 和其他的图片文件放在同一个目录下，这样才可以通过一个 目录地址获取 备课的所有资源**

### 5.5.2、插入图片

1、**title 需要带有文件后缀名**

```ts
// 图片的fileData格式，不需要info属性
const fileData = {
    type: PlasoElectronSdk.FILE_TYPE.IMAGE,
    title: 'xxxxxx.xxx',
    url: 'xxxxxx',
};
```

### 5.5.3、插入 ppt

```ts
// ppt的fileData格式，不需要info属性
const fileData = {
    type: PlasoElectronSdk.FILE_TYPE.PPT,
    title: 'xxxxxx',
    url: 'xxxxxx',
};
```

### 5.5.4、插入 音视频

1、可以设置**url**属性为 公开可访问的音视频文件全路径，

2、或者设置**info**属性为表示文件信息的数组，可以通过 进课堂时传入的 **getExtFileName** 方法 可以获取文件有效路径

```ts
// audio、video 的fileData格式
const fileData = {
	type: PlasoElectronSdk.FILE_TYPE.AUDIO/.VIDEO,
	title: 'xxxxxx',
	url: 'xxxxxx',
}
或
const fileData = {
	type: PlasoElectronSdk.FILE_TYPE.AUDIO/.VIDEO,
	title: 'xxxxxx',
	info: [xxxxxx],
}
```

### 5.5.5、插入 pdf、word、execl、doc、xls

1、可以设置 **url**属性 为公开可访问的 pdf、word、execl 文件全路径，

2、或者设置 **info**属性 为表示文件信息的数组，可以通过 进课堂时传入的 **getExtFileName** 方法 可以获取文件有效路径

```ts
// pdf、word、execl 的fileData格式，不需要info属性
const fileData = {
	type: PlasoElectronSdk.FILE_TYPE.PDF/.WORD/.EXCEL/.DOC/.XLS,
	title: 'xxxxxx',
	url: 'xxxxxx',
}
或
const fileData = {
	type: PlasoElectronSdk.FILE_TYPE.PDF/.WORD/.EXCEL/.DOC/.XLS,
	title: 'xxxxxx',
	info: [xxxxxx],
}
```

# 6、资料中心

step1、进课堂时，对象 **classOptions.supportShowResourceCenter** 需要是 true

step2、在课堂内点击资料中心后，会触发进课堂时传入的回调函数 **onOpenResourceCenterFn**，此时用户在 onOpenResourceCenterFn 函数内打开自己的云盘

step3、选择号文件后，通过 **PlasoElectronSdk.insertObject** 方法插入文件,方法入参参考 insertObject 说明

step4、insertObject 方法 入参 有 info 时，此时 会触发进课堂时传入的回调函数 **onGetExtFileNameFn** 来获取文件的线上地址

# 7、历史课堂

1、参考文档： [历史课堂接入方式](https://open.plaso.cn/folder-24752679?nav=01HEQ5Y5RXKMCPBPF6S8T3VK56)

2、课堂里插入需要 调用 回调 onGetExtFileNameFn 方法的文件时，对应的历史课堂 则需要自己包装一层，具体逻辑参考 ：**[播放历史课堂-jssdk 集成](https://open.plaso.cn/folder-24752679?nav=01HEQ5Y5RXKMCPBPF6S8T3VK56)**

# 8、注意点

（1）用户的课堂外主窗口销毁时需要销毁课堂窗口

（2）electron 版本>=14.0.0 时：需要在主进程里 启动 remote

```ts
try {
    const electronStore = require('@electron/remote/main');
    electronStore.initialize();
    // mainWindow 预期的渲染进程窗口
    electronStore.enable(mainWindow.webContents);
} catch (error) {
    console.error(
        'Module not found',
        'Please run `npm install @electron/remote` to enable remote module and update electron version to 22.0.0 or higher',
    );
}
```

（3）**基于 此包封装新包时**：注意 @electron/remote 这个包的位置需要 和新包处于同级目录，需要把 和该包同级的@electron/remote 移到新包的同级目录处

（4）确保 仅最后的 node_moudles 的顶层有 @electron/remote

# 9、附录参数说明

<a id="record-type"></a>
## 9.1、RecordType

| 值  | 说明                            |
| --- | ------------------------------- |
| 1   | 无头像录制（仅录制板书）        |
| 2   | 录老师头像（录制老师头像+板书） |
| 3   | 录助教头像（录制助教头像+板书） |
| 4   | 录制课堂（录制整个屏幕和头像）  |
| 5   | 仅录老师头像                    |
