React Native
本文以实现音视频通话为例,结合 SDK API 和示例代码,介绍如何快速接入。
使用 Pano React Native SDK,请注意以下要求:
- React Native 版本 >=0.60
- iOS 系统版本 >=9.0,Android 系统版本 >=4.4
- Pano React Native SDK 不支持模拟器调试,请使用真机。
导入SDK
通过 NPM 安装SDK。
- 简介页面请查看:npmjs 网站。
- 通过命令行工具执行
npm install @pano.video/panortc-react-native-sdk
命令即可获取 SDK 包。 - 通过代码
import RtcEngineKit from '@pano.video/panortc-react-native-sdk';
导入 SDK。
防止混淆
如果你的项目需要混淆,请在 android/app/proguard-rules.pro 文件中配置以下内容防止混淆 Pano SDK。
-keep class com.pano.**{*;}
-keep class video.pano.**{*;}
配置权限
配置 Android 权限
在 android/app/src/main/AndroidManifest.xml 文件的 manifest
根元素内添加:
<uses-permission android:name="android.permission.RECORD_AUDIO" /> <!-- 音频需要此权限 -->
<uses-permission android:name="android.permission.CAMERA" /> <!-- 视频需要此权限 -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" /> <!-- 音频需要此权限 -->
<uses-feature android:name="android.hardware.camera" /> <!-- 视频需要此配置 -->
<uses-feature android:name="android.hardware.camera.autofocus" /> <!-- 视频需要此配置 -->
配置 iOS 权限
在 iOS/项目名称/Info.plist 的 dict
标签内添加:
<key>NSMicrophoneUsageDescription</key>
<string>请修改为 App 需要使用麦克风的提示</string>
<key>NSCameraUsageDescription</key>
<string>请修改为 App 需要使用摄像头的提示</string>
申请 Android 权限
在需要使用 Pano SDK 进行音视频通话的地方配置:
/* 请先导入组件: import { Platform, PermissionsAndroid } from 'react-native';
关于 PermissionsAndroid 的用法,可以参考:
- 中文:https://reactnative.cn/docs/permissionsandroid
- English: https://reactnative.dev/docs/permissionsandroid
*/
if (Platform.OS === 'android') {
await PermissionsAndroid.requestMultiple([
PermissionsAndroid.PERMISSIONS.RECORD_AUDIO, //音频需要
PermissionsAndroid.PERMISSIONS.CAMERA, // 视频需要
]);
}
屏幕常亮
通话过程中,通常需要屏幕常亮以防止系统锁屏。开发者如需实现屏幕常亮,可以使用第三方package,例如:react-native-keep-awake,等。
- 在适当的时机(例如下文将提到的"自己加入频道成功"后)调用:
activateKeepAwake();
启用屏幕常亮; - 在离开频道时,调用
deactivateKeepAwake();
取消屏幕常亮; - 此类 package 由第三方提供,与 Pano 无关,Pano 不对其功能提供保证和支持,开发者可以自行通过其他合适的方式实现屏幕常亮。
初始化
通过 RtcEngineKit.create(config: RtcEngineConfig)
方法初始化实例。
// 需要导入 RtcEngineKit 和 RtcEngineConfig,后文类似内容请自行导入,不再赘述
// import RtcEngineKit, { RtcEngineConfig } from '@pano.video/panortc-react-native-sdk';
const appId = '...'; // 替换为你的应用ID
let engineConfig = new RtcEngineConfig(appId);
let engine = await RtcEngineKit.create(engineConfig);
- 请登录 Pano控制台,点击左侧导航 应用管理 ,查看应用ID(即
appId
)。
注册通知
通过 RtcEngineKit
实例的 addListener
方法来处理 Pano SDK 返回的通知。
注意:必须尽早注册通知,以免错过某些通知。
engine?.addListener('onChannelJoinConfirm', result => {
// 自己加入频道的通知
})
engine?.addListener('onChannelLeaveIndication', result => {
// 自己被动离开频道的通知
})
engine?.addListener('onChannelCountDown', result => {
// 频道倒计时通知
})
完整的回调方法列表,请查看
RtcEngineEventHandler
文件。
加入频道
加入频道
通过 RtcEngineKit
实例的 joinChannel
方法加入频道。
let token = '请替换为实际的token';
let channelId = '请替换为实际的channelId';
let userId = '请替换为实际的userId';
let userName = '请替换为实际的userName';
/* serviceFlags 频道标志:
ChannelService.Media 音视频
ChannelService.Whiteboard 白板
ChannelService.Message 消息
*/
let serviceFlags = [ChannelService.Media, ChannelService.Whiteboard, ChannelService.Message];
// ChannelMode: 频道模式,OneOnOne 一对一模式 / Meeting 会议模式
// 如果有 Web 端参与,或者需要进行直播/录制,请设置为 ChannelMode.Meeting
let channelConfig = new RtcChannelConfig(
ChannelMode.Meeting,
serviceFlags,
true, // subscribeAudioAll: 自动订阅音频,可以配置为 false 来主动订阅音频(关闭自动订阅)
userName // 用户名,可选参数,可为空,建议配置以区分不同用户
);
let result = engine?.joinChannel(token, channelId, userId, channelConfig);
if (result != ResultCode.OK) {
// 调用失败,请根据 ResultCode 进行处理
}
自己加入频道的通知
调用 joinChannel
方法后,将触发 onChannelJoinConfirm
通知。
engine?.addListener('onChannelJoinConfirm', result => {
// result 表示自己加入频道的结果
})
joinChannel
(加入频道) 接口返回的ResultCode
仅表示调用该接口的结果,而onChannelJoinConfirm
(自己加入频道的通知) 返回的result
表示和服务器交互后的结果。
也就是说当onChannelJoinConfirm
返回ResultCode.OK
才表示加入频道成功。
其他用户加入频道的通知
其他用户加入频道后,将触发 onUserJoinIndication
通知。
engine?.addListener('onUserJoinIndication', (userId, userName) => {
// 其他用户加入频道的通知。userId 和 userName 都是该用户在 joinChannel 时传入的
// 此时可以将其加入到与会者列表中
})
倒计时通知
加入频道后,如果存在倒计时限制,将触发 onChannelCountDown
通知。
engine?.addListener('onChannelCountDown', remain => {
// 频道倒计时通知,单位:秒;请保存用于展示倒计时,此回调仅在加入频道后回调一次
})
- 已实名认证,并且使用正式token,Pano不限制频道时长
- 未实名认证,或者使用临时token,最大频道时长为 30 分钟
操作视频
发送本地视频
通过 RtcEngineKit
实例的 startVideo
方法发送本地视频。
private localViewRef = React.createRef<RtcSurfaceView>(); // UI 布局中需要创建对应的 RtcSurfaceView
let rtcRenderConfig = new RtcRenderConfig(
VideoProfileType.HD720P, // 分辨率:1280 x 720,实际使用请按需配置
false, // sourceMirror: 采集是否镜像
VideoScalingMode.Fit,
false // mirror: 渲染是否镜像
);
/* VideoProfileType 和 sourceMirror 会同时影响发送和渲染,VideoScalingMode 和 mirror 只影响渲染不影响发送
sourceMirror 和 mirror 只要其中一个为 true,本地渲染即为镜像模式
*/
/* 调用 startVideo 方法后,其他用户才能看到你的画面;请在 onChannelJoinConfirm 回调加入频道成功后再调用
config 参数是可选的,不配置将使用默认值
*/
engine?.startVideo(this.localViewRef, rtcRenderConfig).then(result => { ... });
startVideo
设置的分辨率(VideoProfileType
)表示期望的发送分辨率,实际过程中可能会因硬件支持情况、网络情况和订阅情况触发 SDK 自动调整而降低(后文会介绍订阅)。
切换摄像头
通过 RtcEngineKit
实例的 isFrontCamera
方法判断是否是前置摄像头,switchCamera
方法切换摄像头。
engine?.switchCamera(); // 此方法将切换发送出去的摄像头画面
停止发送本地视频
通过 RtcEngineKit
实例的 stopVideo
方法停止发送本地视频。
engine?.stopVideo(); // 调用此方法后,其他用户将看不到你的画面
其他用户开启视频的通知
当其他用户发送视频时,将触发 onUserVideoStart
通知。
engine?.addListener('onUserVideoStart', (userId, maxProfile) => {
// maxProfile 表示该用户的最大可发送分辨率
// 取决于 摄像头支持的最大分辨率 和 设置的发送分辨率 这两个值中的较小值
})
订阅其他用户的视频
通过 RtcEngineKit
实例的 subscribeVideo
方法订阅其他用户的视频。
// 请在收到其他用户的 onUserVideoStart 通知后,再调用订阅
// 返回 ResultCode.OK 表示接口调用成功,否则表示失败
private remoteViewRef = React.createRef<RtcSurfaceView>(); // UI 布局中需要创建对应的 RtcSurfaceView
let rtcRenderConfig = new RtcRenderConfig(
// 可以根据显示窗口的大小来决定订阅分辨率,比如大窗口订阅高分辨率,小窗口订阅低分辨率
// 此处示例订阅 1280 x 720,实际使用请按需配置
VideoProfileType.HD720P,
VideoScalingMode.Fit,
false // mirror: 渲染是否镜像
);
engine?.subscribeVideo(userId, this.remoteViewRef);
- Pano采用订阅模式来接收视频,参与者之间需要相互订阅,才可以看到彼此的视频画面。
- 默认 正式token 最多可以订阅 10 路视频,临时token 最多可以订阅 3 路视频。
- 如果订阅失败,会触发
onUserVideoSubscribe
通知。
视频首帧的通知
当自己发送或收到其他用户第一个视频帧时,将触发 onFirstVideoFrameRendered
通知。
engine?.addListener('onFirstVideoFrameRendered', userId => {
// 第一个视频帧通知,可以开始显示视频画面
});
取消订阅其他用户的视频
通过 RtcEngineKit
实例的 unsubscribeVideo
方法取消订阅其他用户的视频。
engine?.unsubscribeVideo(userId); // 调用此方法后,你将看不到该用户的画面
当其他用户停止视频或者离开频道的时候,将被自动取消订阅。
操作声音
发送本地声音
通过 RtcEngineKit
实例的 startAudio
方法发送本地声音。
engine?.startAudio(); // 调用此方法后,其他用户才能听到你的声音;请在加入频道成功后再调用
停止发送本地声音
通过 RtcEngineKit
实例的 stopAudio
方法停止发送本地声音。
// 调用此方法后,其他用户将听不到你的声音
// 不影响你接收其他用户的声音
// 可以调用 startAudio 重新发送
engine?.stopAudio();
静音麦克风
通过 RtcEngineKit
实例的 muteAudio
方法静音本地麦克风。
engine?.muteAudio(); // 调用此方法后,其他用户将听不到你的麦克风的声音
停止发送本地声音(
stopAudio
) 和 静音本地麦克风(muteAudio
) 这两个接口都可以将自己静音(不让其他用户听到你的声音)。它们的区别在于:
1 "停止发送本地声音"会断开音频通道连接(同时停止发送麦克风和伴音的声音,会取消其他用户订阅你的声音,如需重建连接需要消耗时间)
2 "静音本地麦克风"会发送静音包(不影响伴音发送,不影响订阅关系,静音包数据量很小,临时静音建议使用此方式,取消静音能够迅速恢复发送声音)
取消静音麦克风
通过 RtcEngineKit
实例的 unmuteAudio
方法取消静音本地麦克风。
engine?.unmuteAudio(); // 静音麦克风后,需要取消静音,其他用户才能听到你的麦克风的声音
其他用户开启声音的通知
当其他用户发送声音时,将触发 onUserAudioStart
通知。
engine?.addListener('onUserAudioStart', userId => {
// 其他用户开启声音的通知
});
订阅其他用户的声音
如果在 joinChannel
(加入频道)时,配置了自动订阅音频(channelConfig
的 subscribeAudioAll
参数配置为 true
),则开发者无需再主动订阅其他用户的声音。否则,需要通过 RtcEngineKit
实例的 subscribeAudio
方法订阅其他用户的声音。
// 如果 加入频道 时配置了自动订阅音频,则无需调用此接口
// 请在收到其他用户的 onUserAudioStart 通知后,再调用订阅
engine?.subscribeAudio(userId);
- 如果希望在通话过程中,不收听某位与会者,或者不收听所有其他与会者,请在加入频道时,设置不自动订阅音频;随后按需订阅或取消订阅某位或所有其他与会者。
- 如果订阅失败,会触发
onUserAudioSubscribe
通知。
收到其他用户声音的通知
当收到其他用户的声音时,将触发 onFirstAudioDataReceived
通知。
engine?.addListener('onFirstAudioDataReceived', userId => {
// 收到其他用户的首个声音数据包
});
取消订阅其他用户的声音
通过 RtcEngineKit
实例的 unsubscribeAudio
方法取消订阅其他用户的声音。
engine?.unsubscribeAudio(userId); // 调用此方法后,你将听不到该用户的声音
当其他用户停止声音或者离开频道的时候,将被自动取消订阅。
离开频道
离开频道
通过 RtcEngineKit
实例的 leaveChannel
方法离开频道。
engine?.leaveChannel();
注意:调用此接口主动离开频道,自己不会收到
onChannelLeaveIndication
回调。
其他用户离开频道的通知
其他用户离开频道后,将触发 onUserLeaveIndication
通知。
engine?.addListener('onUserLeaveIndication', (userId, reason) => {
// 可将其从与会者列表中移除
});
释放资源
通过 destroy
方法销毁 RtcEngineKit
实例。
engine?.destroy();
反馈问题
我们强烈建议您集成反馈功能,以便用户遇到问题时,可以提交信息给我们分析排查,具体请 点此查看。
示例代码
为方便开发者了解丰富的接口使用方式,我们还提供示例代码,请体验参考: