[English](./README.md) | 简体中文

# @ray-js/video-streams-sdk

[![latest](https://img.shields.io/npm/v/@ray-js/video-streams-sdk/latest.svg)](https://www.npmjs.com/package/@ray-js/video-streams-sdk) [![download](https://img.shields.io/npm/dt/@ray-js/video-streams-sdk.svg)](https://www.npmjs.com/package/@ray-js/video-streams-sdk)

> H5 上支持 webrtc 拉流以及 websocket 拉流

## 安装

```sh
$ npm install @ray-js/video-streams-sdk
// 或者
$ yarn add @ray-js/video-streams-sdk
```

## 开发

```sh
# 实时编译 SDK
yarn dev
# 编译 SDK
yarn build
```

## 工具类

```jsx
import { Utils } from '@ray-js/video-streams-sdk';
```

### 图片 URL 解密

`base64Decode`

`请求参数`

| 参数名 | 类型   | 描述                                                         | 是否必传 |
| :----- | :----- | :----------------------------------------------------------- | -------- |
| url    | string | 加密的首帧图片 URL，如果是从涂鸦云端获取的图片，需要进行解密 | true     |

`请求示例`

```jsx
Utils.base64Decode(
  'aHR0cHM6Ly9lbmNyeXB0LXBpYy50dXlhY24uY29tL3YxL2FwaS9waWNzP3BpY0tleT1hYzdhOWUzZTM2MzI5YmVlY2YxNDI3MTA5ZTxxxxx'
);

// return: https://xxxxxxxxxxx
```

## 接口类

> 以下接口建议在服务端请求，可以相对的减少客户端拉流的时间。

```jsx
import { API } from '@ray-js/video-streams-sdk';
```

### 获取访问令牌

`getToken`

`请求参数`

| 参数名 | 类型      | 描述                                   | 是否必传 |
| :----- | :-------- | :------------------------------------- | -------- |
| params | `IParams` | 身份验证信息                           | true     |
| ctx    | Object    | 服务端登录的上下文信息，客户端可以不传 | false    |

`IParams`

| 参数名   | 类型   | 描述                                    | 是否必传 |
| :------- | :----- | :-------------------------------------- | -------- |
| accessId | string | 小程序的 clientId，可通过小程序接口获取 | true     |
| ticket   | string | 身份票据，可通过小程序接口获取          | true     |

`返回参数`

| 参数名        | 类型   | 描述           |
| :------------ | :----- | :------------- |
| access_token  | string | 用户的身份令牌 |
| refresh_token | string | 用户的刷新令牌 |

`请求示例`

```jsx

// 1. Server 端，getInitialProps 为 next 提供的方法
async getInitialProps(ctx){
  const { result } = await API.getToken({ accessId, ticket }, ctx);
}

// 2. Client 端
const { result } = await API.getToken({ accessId, ticket });
```

### 获取 MQTT 建立连接的配置参数

`getMqttConfig`

`请求参数`

| 参数名 | 类型      | 描述                                   | 是否必传 |
| :----- | :-------- | :------------------------------------- | -------- |
| params | `IParams` | 身份信息                               | true     |
| ctx    | Object    | 服务端登录的上下文信息，客户端可以不传 | false    |

`IParams`

| 参数名       | 类型   | 描述                       | 是否必传 |
| :----------- | :----- | :------------------------- | -------- |
| accessToken  | string | 用户的身份令牌，服务端必传 | true     |
| refreshToken | string | 用户的刷新令牌，服务端必传 | true     |
| schema       | string | 微信小程序的 `Schema`      | true     |

`请求示例`

```jsx

// 1. Server 端，getInitialProps 为 next 提供的方法
async getInitialProps(ctx){
  const { result } = await API.getMqttConfig({ accessToken, refreshToken, schema }, ctx);
}

// 2. Client 端
const { result } = await API.getMqttConfig({});
```

`返回示例`

```jsx
// 该结果为 webrtc 协议的请求参数字段 mqttConfigResponse
{
  password: 'xxxxxxxxxx',
  topics: [],
  url: 'wss://xxxxxxx',
  username: 'xxxxxx'
}
```

### 获取 WebRtc 协议建立连接的配置参数

`getWebRTCConfig`

`请求参数`

| 参数名 | 类型      | 描述                                   | 是否必传 |
| :----- | :-------- | :------------------------------------- | -------- |
| params | `IParams` | 身份信息 和 设备 ID                    | true     |
| ctx    | Object    | 服务端登录的上下文信息，客户端可以不传 | false    |

`IParams`

| 参数名       | 类型   | 描述                       | 是否必传 |
| :----------- | :----- | :------------------------- | -------- |
| deviceId     | string | 设备 ID                    | true     |
| accessToken  | string | 用户的身份令牌，服务端必传 | true     |
| refreshToken | string | 用户的刷新令牌，服务端必传 | true     |
| schema       | string | 微信小程序的 `Schema`      | true     |

`请求示例`

```jsx

// 1. Server 端，getInitialProps 为 next 提供的方法
async getInitialProps(ctx){
  const { result } = await API.getWebRTCConfig({ deviceId, accessToken, refreshToken, schema }, ctx);
}

// 2. Client 端
const { result } = await API.getWebRTCConfig({ deviceId });
```

`返回示例`

```jsx
// 该结果为 webrtc 协议的请求参数字段 p2pConfigResponse
{
  auth: 'xxxxxxxxxx',
  audio_attributes: [],
  gateway_id: '',
  id: 'xxxxxx',
  moto_id: 'xxxxx',
  p2p_config: [],
  skill: ''
}
```

## 实时视频（WebRTC 协议）

> 提供音视频自动拉流（仅限 H264 以及 H265 设备，不支持 Mjpeg 设备的视频播放）以及对讲。

`WebRtcVideo`

```jsx
import { WebRtcVideo } from '@ray-js/video-streams-sdk';
```

### 初始化

`请求参数`

| 参数名             | 类型             | 描述                                                                                                                               | 是否必传 |
| :----------------- | :--------------- | :--------------------------------------------------------------------------------------------------------------------------------- | -------- |
| video              | HTMLVideoElement | `<video>` 标签的实例                                                                                                               | true     |
| url                | string           | 门锁实时视频的媒体链接 URL                                                                                                         | true     |
| mqttConfigResponse | Object           | MQTT 协议建立连接的配置参数，`API.getMqttConfig` 方法的返回值                                                                      | true     |
| p2pConfigResponse  | Object           | WebRtc 协议建立连接的配置参数，`API.getWebRTCConfig` 方法的返回值                                                                  | true     |
| codecType          | string           | 设备的视频协议类型，默认值为 '2'，'4' 表示 H265 协议设备， '2' 表示 H264 协议设备                                                  | false    |
| isMuted            | boolean          | 是否开启静音，默认不开启                                                                                                           | false    |
| angle              | number           | 设备的旋转角度，默认值为 0                                                                                                         | false    |
| isOnlySupportSpeak | boolean          | 是否仅开启对讲功能，默认不是，当设备为 Mjpeg 协议设备时，可使用该能力对讲，因为 WebRtc 协议不支持 Mjpeg 设备的视频播放，但支持对讲 | false    |
| isCarryAudio       | boolean          | 是否支持音频播放，默认支持                                                                                                         | false    |
| videoWidth         | number           | 预设的视频播放器的宽度，默认为屏幕的宽度                                                                                           | false    |
| videoHeight        | number           | 预设的视频播放器的高度，默认为屏幕的高度                                                                                           | false    |

`请求示例`

```jsx
// 获取 video
const video = document.getElementById('video');

const WebRtcVideoRef = new WebRtcVideo({
  url: 'https://xxxxxxxx',
  video,
  codecType: '2',
  mqttConfigResponse,
  mqttConfigResponse,
  angle: 90,
});
```

### 事件监听

`onStatusChange`

`请求参数`

| 参数名   | 类型                    | 描述           | 是否必传 |
| :------- | :---------------------- | :------------- | -------- |
| callback | (message, data) => void | 监听的回调事件 | true     |

`IMessage`

- videoStyle： 适配出的视频播放器的宽高
- speed：视频的速率，单位为 KB/s
- connectStatus： 接口的连接状态
  - unLink：接口未连接
  - linked：连接成功
  - linkFail：连接失败
  - busy：服务器繁忙
  - fail：加载/播放失败
- speakStatus： 对讲的状态
  - start：打开对讲
  - success：对讲成功
  - inUse：对讲被占用
  - stop：关闭对讲
  - nonSupport：手机设备不支持对讲
- streamStatus：出流的状态
  - success：出流成功
  - nonSupport：手机设备不支持 WebRtc

`请求示例`

```jsx
const handleStatusChange = (message, data) => {
  // message: 事件名称
  // data: 值
};

WebRtcVideoRef.onStatusChange(handleStatusChange);
```

### 开始对讲

`startSpeak`

`请求参数`

| 参数名 | 类型   | 描述                                                                                                    | 是否必传 |
| :----- | :----- | :------------------------------------------------------------------------------------------------------ | -------- |
| type   | string | 变声的类型<ul><li>original: 原声</li><li>female: 女声</li><li>robot: 机器人</li><li>man: 男声</li></ul> | true     |

```jsx
WebRtcVideoRef.startSpeak('female');
```

### 关闭对讲

`stopSpeak`

```jsx
WebRtcVideoRef.stopSpeak();
```

### 设置静音与否

`setVideoVoice`

`请求参数`

| 参数名  | 类型 | 描述     | 是否必传 |
| :------ | :--- | :------- | -------- |
| isMuted | bool | 是否静音 | true     |

```jsx
WebRtcVideoRef.setVideoVoice(true);
```

### 重连

`reconnectVideo`

```jsx
WebRtcVideoRef.reconnectVideo();
```

### 关闭实时视频

`stopVideo`

```jsx
WebRtcVideoRef.stopVideo();
```

## 实时视频（WebSocket 协议）

`WebSocketVideo`

> 提供音视频自动拉流以及对讲，存在对讲丢字等情况，通常用在 Mjpeg 协议设备音视频的播放，搭配 WebRtc 能力的对讲功能。

```jsx
import { WebSocketVideo } from '@ray-js/video-streams-sdk';
```

### 初始化

`请求参数`

| 参数名       | 类型              | 描述                                                           | 是否必传 |
| :----------- | :---------------- | :------------------------------------------------------------- | -------- |
| video        | HTMLCanvasElement | `<canvas>` 标签的实例                                          | true     |
| url          | string            | 门锁实时视频的媒体链接 URL，从微信小程序的 `getLockMediaStream |
| ` 方法中获取 | true              |
| expiration   | string            | 生效时间，从微信小程序的 `getLockMediaStream                   |
| ` 方法中获取 | true              |
| signInfo     | string            | 注册信息，从微信小程序的 `getLockMediaStream                   |
| ` 方法中获取 | true              |
| isMuted      | boolean           | 是否开启静音，默认开启静音                                     | false    |
| angle        | number            | 设备的旋转角度，默认值为 0                                     | false    |
| isCarryAudio | boolean           | 是否支持音频播放，默认支持                                     | false    |
| videoWidth   | number            | 预设的视频播放器的宽度，默认为屏幕的宽度                       | false    |
| videoHeight  | number            | 预设的视频播放器的高度，默认为屏幕的高度                       | false    |

`请求示例`

```jsx
// 获取 canvas
const canvas = document.getElementById('canvas');

const WebSocketVideoRef = new WebSocketVideo({
  url: 'https://xxxxxxxx',
  canvas,
  expiration: '1726020430',
  signInfo: 'xxxxxxxxx',
  angle: 90,
});
```

### 事件监听

`onStatusChange`

`请求参数`

| 参数名   | 类型                    | 描述           | 是否必传 |
| :------- | :---------------------- | :------------- | -------- |
| callback | (message, data) => void | 监听的回调事件 | true     |

`IMessage`

- speed：视频的速率，单位为 KB/s
- connectStatus： 接口的连接状态
  - unLink：接口未连接
  - linked：连接成功
  - linkFail：连接失败
- speakStatus： 对讲的状态
  - start：打开对讲
  - success：对讲成功
  - inUse：对讲被占用
  - stop：关闭对讲
  - nonSupport：手机设备不支持对讲
- streamStatus：出流的状态
  - success：出流成功
  - fail：出流失败

`请求示例`

```jsx
const handleStatusChange = (message, data) => {
  // message: 事件名称
  // data: 值
};

WebSocketVideoRef.onStatusChange(handleStatusChange);
```

### 开始对讲

`startSpeak`

`请求参数`

| 参数名 | 类型   | 描述                                                                                                    | 是否必传 |
| :----- | :----- | :------------------------------------------------------------------------------------------------------ | -------- |
| type   | string | 变声的类型<ul><li>original: 原声</li><li>female: 女声</li><li>robot: 机器人</li><li>man: 男声</li></ul> | true     |

```jsx
WebSocketVideoRef.startSpeak('female');
```

### 关闭对讲

`stopSpeak`

```jsx
WebSocketVideoRef.stopSpeak();
```

### 设置静音与否

`setVideoVoice`

`请求参数`

| 参数名  | 类型 | 描述     | 是否必传 |
| :------ | :--- | :------- | -------- |
| isMuted | bool | 是否静音 | true     |

```jsx
WebSocketVideoRef.setVideoVoice(true);
```

### 重连

`reconnectVideo`

```jsx
WebSocketVideoRef.reconnectVideo();
```

### 关闭实时视频

`stopVideo`

```jsx
WebSocketVideoRef.stopVideo();
```

## 日志回放

`RecordVideo`

```jsx
import { RecordVideo } from '@ray-js/video-streams-sdk';
```

### 初始化

`请求参数`

| 参数名       | 类型              | 描述                               | 是否必传 |
| :----------- | :---------------- | :--------------------------------- | -------- |
| canvas       | HTMLCanvasElement | `<canvas>` 画布标签的实例          | true     |
| url          | string            | 门锁日志信息的媒体链接 URL         | true     |
| deviceWidth  | number            | 门锁设备的宽度                     | true     |
| deviceHeight | number            | 门锁设备的高度                     | true     |
| mediaKey     | string            | 门锁日志信息的媒体密钥             | true     |
| angle        | number            | 设备的旋转角度，默认值为 0         | false    |
| canvasWidth  | number            | 预设的画布的宽度，默认为屏幕的宽度 | false    |
| canvasHeight | number            | 预设的画布的高度，默认为屏幕的高度 | false    |

`请求示例`

```jsx
// 获取 canvas
const canvas = document.getElementById('canvas');

const RecordVideoRef = new RecordVideo({
  url: 'https://xxxxxxxx',
  canvas,
  deviceWidth: 1280,
  deviceHeight: 720,
  mediaKey: '9ged77k5sntq4fct',
  angle: 90,
});
```

### 监听事件

`onStatusChange`

`请求参数`

| 参数名   | 类型                    | 描述           | 是否必传 |
| :------- | :---------------------- | :------------- | -------- |
| callback | (message, data) => void | 监听的回调事件 | true     |

`IMessage`

- canvasSize： 适配出的画布的宽高
- status：回放视频播放的状态，值有如下
  - ready：资源加载完成
  - playing：播放中
  - pause：暂停
  - end：结束
  - fail：加载/播放失败
- durations：回放视频的总时长，单位为秒
- currentDuration：视频播放的当前进度，单位为秒

`请求示例`

```jsx
const handleStatusChange = (message, data) => {
  // message: 事件名称
  // data: 值
};

RecordVideoRef.onStatusChange(handleStatusChange);
```

### 播放视频

`startVideo`

`请求示例`

```jsx
RecordVideoRef.startVideo();
```

### 暂停视频

`pauseVideo`

`请求示例`

```jsx
RecordVideoRef.pauseVideo();
```

### 关闭视频

`stopVideo`

`请求示例`

```jsx
RecordVideoRef.stopVideo();
```