# 实现音视频互动 (/zh-CN/realtime-media/rtc/get-started/quick-start/mini-program)

> For AI agents: see the complete documentation index at [llms.txt](/llms.txt).

本文介绍如何建立一个简单的项目并使用声网小程序 SDK 实现基础的视频通话。
## 前提条件 [#前提条件-6]

开始前，请确保你的开发环境满足如下条件：

- 一个经过企业认证的微信小程序账号。在调试小程序 Demo 过程中，需要使用 live-pusher 和 live-player 组件。只有特定行业的认证企业账号才可以使用这两个组件。详见[小程序官网文档](https://developers.weixin.qq.com/miniprogram/dev/component/live-player.html)。
- 下载并安装最新版本的[微信开发者工具](https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html)。
- 参考[开通 RTC 服务](/zh-CN/realtime-media/rtc/build/setup-and-access/enable-service)在控制台创建项目、获取 App ID 和临时 Token，并[开通小程序服务](/zh-CN/realtime-media/rtc/build/setup-and-access/enable-service#mini-program-service)。

  :::warning[注意]
  临时 Token 的有效期是 24 小时。Token 过期会导致鉴权失败或无法加入频道。
  :::

- 至少一台安装有微信 App 的移动设备。

:::info[信息]
在集成微信小程序组件之前，声网建议你先阅读[微信小程序官方文档](https://developers.weixin.qq.com/miniprogram/dev/framework/)。
:::

## 准备开发环境 [#准备开发环境]

### 1. 获取小程序组件权限 [#1-获取小程序组件权限]

在[微信公众平台](https://mp.weixin.qq.com/)的小程序**开发**选项中，切换到**接口设置**页签，打开**实时播放音视频流**和**实时录制音视频流**的开关。

![打开音视频开关](https://web-cdn.agora.io/docs-files/1605069073929)

### 2. 配置服务器域名 [#2-配置服务器域名]

在小程序的开发设置里，将如下域名配到服务器域名里，其中 **request 合法域名**区域填入以 https 开头的域名；**socket 合法域名**区域填入以 wss 开头的域名。

如果你使用的 SDK 为 **v2.5.3** 或更高版本，你需要在 **request 合法域名**及 **socket 合法域名**中添加以下域名：

 ```shell
wss://miniapp.agoraio.cn
https://uap-ap-web-1.agora.io
https://uap-ap-web-2.agoraio.cn
https://uap-ap-web-3.agora.io
https://uap-ap-web-4.agoraio.cn
https://report-ad.agoralab.co
https://rest-argus-ad.agoralab.co
```


![添加域名](https://web-cdn.agora.io/docs-files/1638759333663)


如果你使用的 SDK 为 v2.4.6 或更低版本，你需要在 request 合法域名及 socket 合法域名中添加以下域名：

```shell
wss://miniapp.agoraio.cn
https://miniapp-1.agoraio.cn
https://miniapp-2.agoraio.cn
https://miniapp-3.agoraio.cn
https://miniapp-4.agoraio.cn
```

### 3. 创建小程序 [#3-创建小程序]

参考如下步骤创建一个新的小程序。

1. 打开**微信开发者工具**，然后按照屏幕提示扫码登录。
2. 完成登录后，点击小程序界面的 **+**。
3. 在弹出的**新建项目**界面中，依次填入小程序的**项目名称**、本地存储**目录**、小程序 **AppID**，然后点击**新建**。

成功创建小程序后，微信开发者工具的左侧会显示当前小程序的界面。你还可以点击**真机调试**，并扫描生成的二维码，在手机上进行体验。

### 4. 添加微信小程序组件 [#4-添加微信小程序组件]

在微信小程序中实现音视频功能，需要使用微信的 live-player 组件和 live-pusher 组件。详见[微信小程序 API 说明](https://developers.weixin.qq.com/miniprogram/dev/api/)。

- live-player 组件

  该组件用于实现微信小程序的实时音视频播放功能。开发者在创建该组件后，还需要在 js 文件中调用 API 接口对应的组件来实现该功能。声网小程序中，创建 `live-player` 的示例代码如下：

	```javascript
	<live-player
	  id="player"
	  src="{{rtmp 播放地址}}"
	  mode="RTC"
	  bindstatechange="playerStateChange"
	  object-fit="fillCrop" />
	```

- live-pusher 组件

   该组件用于实现微信小程序的实时音视频录制功能。开发者在创建该组件后，还需要在 js 文件中调用 API 接口对应的组件来实现该功能。声网小程序中，创建 `live-pusher` 的示例代码如下：

	```javascript
	<live-pusher
	  url="{{rtmp 推流地址}}"
	  mode="RTC"
	  bindstatechange="recorderStateChange" />
	```

<a id="integrate"></a>
### 5. 集成 SDK [#5-集成-sdk]

你可以通过下载压缩包或 npm 任一种方式集成小程序 SDK。

<Tabs defaultValue="download" groupId="integrate" persist>
<TabsList>
  <TabsTrigger value="download">下载压缩包</TabsTrigger>
  <TabsTrigger value="npm">通过 npm 集成</TabsTrigger>
</TabsList>

<TabsContent value="download">

1. 下载[声网小程序 SDK](/zh-CN/realtime-media/rtc/reference/downloads) 并解压。
2. 将 SDK 包中的 **Agora_Miniapp_SDK_for_WeChat.js** 文件复制到你的小程序项目文件夹中。
3. 使用 `require` 将小程序 SDK 导入到你的项目中：

		```javascript
		// ..Agora_Miniapp_SDK_for_WeChat.js 为你的 js 文件本地路径
		const AgoraMiniappSDK = require('..Agora_Miniapp_SDK_for_WeChat.js');
		```

</TabsContent>

<TabsContent value="npm">

如果你使用 v2.6.0 或更高版本的小程序 SDK 以及 1.02.1808300 或更高版本的[微信开发者工具](https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html)，可通过 npm 安装小程序 SDK。

1. 初始化项目。在你的项目根目录打开终端，运行以下命令：

   ```shell
   npm init
   ```

   完成后，打开你的项目文件夹中的 `package.json` 文件。在 `dependencies` 字段中添加 `agora-miniapp-sdk` 及版本号，设为 `latest` 即使用最新版本。

   ```json
   {
      "name": "premium-miniapp",
      "version": "1.0.0",
      "description": "",
      "main": "app.js",
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1"
      },
      "dependencies": {
        "agora-miniapp-sdk": "latest"
      },
      // 添加其他业务逻辑
   }
   ```

2. 安装依赖。在你的项目根目录打开终端，运行以下命令：

   ```shell
   npm install
   ```

3. 构建 npm。在微信开发者工具中，从菜单栏选择**工具** > **构建 npm**。

<DocsImage alt="构建 npm" src="https://web-cdn.agora.io/docs-files/1675665358033" displayWidth="30%" />

4. 导入 SDK。使用 `require` 将小程序 SDK 导入到你的项目中：

   ```javascript
   const AgoraMiniappSDK = require("agora-miniapp-sdk");
   ```

</TabsContent>
</Tabs>

## 实现音视频互动 [#实现音视频互动]

完成上述步骤后，你可以参考下图中的业务流程图，在你的项目中实现通话功能。

![小程序通话流程](https://web-cdn.agora.io/docs-files/1675997572227)

:::info[信息]
-2301 和 -1307 是微信小程序 `live-player` 和 `live-pusher` 组件的状态码，表示网络断连，需要自行重启。详见微信小程序 [live-player](https://developers.weixin.qq.com/miniprogram/dev/component/live-player.html) 和 [live-pusher](https://developers.weixin.qq.com/miniprogram/dev/component/live-pusher.html) 组件文档。
:::

### 1. 初始化客户端对象 [#1-初始化客户端对象]

调用 [`client.init`](/zh-CN/api-reference/rtc/mini-program/classes/client#init) 方法创建并初始化一个用于控制通话的客户端对象。你需要将 `APPID` 替换为你的声网项目的 App ID。详见[获取 App ID](/zh-CN/realtime-media/rtc/build/setup-and-access/enable-service)。

```javascript
// Callback 形式调用
let client = new AgoraMiniappSDK.Client();

client.init(APPID () => {
  Utils.log(`client init success`);
}, e => {
  Utils.log(`client init failed: ${e} ${e.code} ${e.reason}`);
  reject(e)
});

// Promise 形式调用
let client = new AgoraMiniappSDK.Client();
await client.init(APPID)
```

### 2. 加入频道 [#2-加入频道]

调用 [`client.join`](/zh-CN/api-reference/rtc/mini-program/classes/client#join) 方法加入频道。

在 `client.join` 中你需要将 `yourToken` 替换成你自己生成的 Token。并填入想要加入的频道名以及用户 `uid`。在测试阶段，你可以直接在控制台[生成临时 Token](/zh-CN/realtime-media/rtc/build/setup-and-access/enable-service)。在生产环境，我们推荐你在自己的服务端生成 Token，详见在[服务端生成 Token](/zh-CN/realtime-media/rtc/build/setup-and-access/token-authentication)。

```javascript
// Callback 形式调用
client.join(yourToken, channel, uid, () => {
  Utils.log(`client join channel success`);
}, e => {
  Utils.log(`client join channel failed: ${e.code} ${e.reason}`);
  reject(e)
});

// Promise 形式调用
await client.join(yourToken, channel, uid)
```

### 3. 发布本地流 [#3-发布本地流]

成功加入频道后，就能调用 [`client.publish`](/zh-CN/api-reference/rtc/mini-program/classes/client#publish) 方法将本地音视频流发布到频道中。成功发布后，SDK 会返回该路音视频流的 URL。

```javascript
// Callback 形式调用
client.publish(url => {
  Utils.log(`client publish success`);
  resolve(url);
}, e => {
  Utils.log(`client publish failed: ${e.code} ${e.reason}`);
  reject(e)
});

// Promise 形式调用
const url = await client.publish()
```

### 4. 订阅远端流 [#4-订阅远端流]

当远端流发布到频道时，会触发 `stream-added` 事件，我们需要通过 [`client.on`](/zh-CN/api-reference/rtc/mini-program/classes/client#on) 监听该事件并在回调中订阅新加入的远端流。

```javascript
// Callback 形式调用
client.on("stream-added", e => {
  client.subscribe(uid => {
    Utils.log(`stream ${uid} subscribed successful`);
  }, e => {
    Utils.log(`stream subscribed failed ${e} ${e.code} ${e.reason}`);
  });
});

// Promise 形式调用
client.on("stream-added", async e => {
  const { url, rotation } = await client.subscribe(uid)
});
```

当远端用户取消发布流或退出频道时，关闭及移除对应的流。

```javascript
client.on("stream-removed", e => {
  console.log(`stream-removed: ${JSON.stringify(e)}`)
  let uid = e.uid[0];
  console.log(`stream ${uid} removed`);
  this.removeMedia(uid);
});
```

### 5. 更多功能 [#5-更多功能]

在实际使用中，你还可以根据使用场景实现如下功能。

**重连**

如果你的项目中有切换到后台的场景需求，声网推荐调用 [`client.rejoin`](/zh-CN/api-reference/rtc/mini-program/classes/client#rejoin) 方法做好重连机制。你需要在该方法中传入当前频道内所有用户的 `uid` 作为额外参数。其他参数的设置与 `join` 方法相同。

```javascript
// Callback 形式调用
client.rejoin(yourToken, channel, uid, uids, () => {
  Utils.log(`client join channel success`);
}, e => {
  Utils.log(`client join channel failed: ${e.code} ${e.reason}`);
});

// Promise 形式调用
await client.rejoin(yourToken, channel, uid, uids)
```

### 完整示例代码 [#完整示例代码]

你可以直接参考如下示例代码，在项目中实现想要的功能。

```javascript tab="以下为 callback 形式调用的完整示例代码"
// 以下为 callback 形式调用的完整示例代码
let client = new AgoraMiniappSDK.client();

this.client = client;
// 初始化客户端
client.init(APPID, () => {
  Utils.log(`client init success`);
  // 加入频道
  client.join(yourToken, channel, uid, () => {
    Utils.log(`client join channel success`);
    // 发布本地流
    if (this.isBroadcaster()) {
      client.publish(url => {
        Utils.log(`client publish success`);
        resolve(url);
      }, e => {
        Utils.log(`client publish failed: ${e.code} ${e.reason}`);
        reject(e)
      });
    } else {
      resolve();
    }
  }, e => {
    Utils.log(`client join channel failed: ${e.code} ${e.reason}`);
    reject(e)
  })
}, e => {
  Utils.log(`client init failed: ${e} ${e.code} ${e.reason}`);
  reject(e)
});
```

```javascript tab="以下为 promise 形式调用的完整示例代码"
// 以下为 promise 形式调用的完整示例代码
try {
  let client = new AgoraMiniappSDK.client();
  // 初始化客户端
  await client.init(APPID)
  // 设置角色
  this.role = "broadcaster"
  await client.setRole(this.role)
  // 加入频道
  await client.join(yourToken, channel, uid)
  if (this.isBroadcaster()) {
    // 发布本地流
    const url = await client.publish()
  }
} catch (e) {
  console.error(e)
}
```

## 运行项目 [#运行项目]

为保证运行效果，我们建议你在真机上运行项目。完成开发后，点击**微信开发者工具**界面的**真机调试**。扫描生成的二维码，即可在手机端运行和调试项目。

## 参考信息 [#参考信息-6]

### 与 Native 互通 [#与-native-互通]

频道中有小程序 SDK 和 Native SDK 时，可以选择如下一种方式实现互通：

- Native 端在直播模式下，将用户角色设置为 `AgoraClientRoleBroadcaster` = 1：主播，实现互通
- Native 端在直播模式下，不设置用户角色为主播，也可以接收到小程序端的流，实现互通

小程序和 Native 互通时，Native 端视频画面可能出现上下颠倒。该问题可能是由于 Native SDK 中的 `setVideoEncoderConfiguration` 设置的方向模式 `orientationMode` 为 `ORIENTATION_MODE.ORIENTATION_MODE_ADAPTIVE` 导致的。解决方法是，将方向模式改成 `ORIENTATION_MODE.ORIENTATION_MODE_FIXED_PORTRAIT` 就可以解决问题。

### 与 Web 互通 [#与-web-互通]

小程序和 Web 互通时，可能出现 Web 端可以看到小程序的视频，但小程序看不到 Web 端的视频。该问题可能是由于编解码格式不被支持导致的。

Web 与小程序互通时，小程序端只支持 H264 模式的编码，不支持 VP8。将 Web SDK 的 `index.html` 文件修改为如下设置即可：

```javascript
client = AgoraRtc.createClient({mode: "live", codec: "h264"});
```

### 示例项目 [#示例项目-6]

声网在 GitHub 上提供一个开源的小程序实时音视频示例项目，你可以下载体验或参考源代码。

<Cards>
  <Card title="Agora-Miniapp-Tutorial" href="https://github.com/AgoraIO/Agora-Miniapp-Tutorial" />
</Cards>

### 相关文档 [#相关文档-5]

使用微信小程序 SDK 开发过程中，你还可以参考如下文档：

* [跑通小程序示例项目](/zh-CN/realtime-media/rtc/get-started/run-demo)
* [小程序 SDK 常见问题集](/zh-CN/reference/faq/integration/mini_program)：例如日志功能，通用问题，错误排查。
* [SDK 错误码和警告码](/zh-CN/realtime-media/rtc/reference/error-code)














