Electron
本文以实现音视频通话为例,结合 SDK API 和示例代码,介绍如何快速接入。
导入SDK
可以通过 2 种方式来导入 SDK。
- 方式1:NPM 安装
- 简介页面请查看:npmjs.com 网站。
- 通过命令行工具执行
npm install @pano.video/panortc-electron-sdk
命令即可获取 SDK 包。 - 通过代码
require('@pano.video/panortc-electron-sdk')
导入 SDK。
- 方式2:导入 JS 文件
- 请到 下载中心,根据需要下载相应平台的 SDK 包(Win64/Win32/macOS),解压后得到 SDK 文件夹,将其复制到你的项目中。
- 通过
<script>
标签导入 SDK 文件夹内的 js/panortc.js 文件。
初始化
通过 new RtcEngine()
创建 RtcEngine
实例,再通过 initialize(appId, options)
方法初始化。
const rtcEngine = new RtcEngine(); // 下文均使用 rtcEngine 作为 RtcEngine 实例名
rtcEngine.initialize(appId, {}); // options 参数如果传入空对象,SDK 将使用默认值
请登录 Pano控制台,点击左侧导航 应用管理 ,查看应用ID(即
appId
)。
注册通知
通过 RtcEngine
实例的 on
方法注册回调通知,通过 removeListener
或 removeAllListeners
方法移除通知。
注意:必须尽早注册通知,以免错过某些通知。
function joinChannelConfirmCB(data){
// 处理自己加入频道的通知
}
function leaveChannelIndicationCB(data){
// 处理自己被动离开频道的通知
}
function userJoinCB(data){
// 处理其他用户加入频道的通知
}
function userLeaveCB(data){
// 其他用户离开频道的通知
}
// 注册各种通知
rtcEngine.on('channelJoinConfirm', joinChannelConfirmCB);
rtcEngine.on('channelLeaveIndication', leaveChannelIndicationCB);
rtcEngine.on('userJoinIndication', userJoinCB);
rtcEngine.on('userLeaveIndication', userLeaveCB);
// 移除通知
// 方式一:使用 removeListener 方法,格式为:removeListener(event, cb),其中 cb 表示特定的单个回调函数
// [注意] 通过匿名函数或箭头函数注册的通知函数,无法使用 off 方法移除,请使用下文 removeAllListeners 方法
rtcEngine.removeListener('channelJoinConfirm', joinChannelConfirmCB);
// 方式二:使用 removeAllListeners 方法移除指定通知类型的所有监听器,格式为:removeAllListeners(event)
rtcEngine.removeAllListeners('channelJoinConfirm');
// 方式三:使用 removeAllListeners 方法移除所有的监听器,格式为:removeAllListeners()
rtcEngine.removeAllListeners();
以上仅为部分通知示例,完整的通知列表,请查看 panortc.js 文件中
_init()
方法内的各种on
回调。
获取视频采集设备
通过 RtcEngine
实例的 videoDeviceMgr()
方法获取视频设备管理器(RtcVideoDeviceManager
),再通过其 getCaptureDeviceList()
方法获取视频采集设备。
let videoCaptureDevices = rtcEngine.videoDeviceMgr().getCaptureDeviceList();
// 结果数组中,每个元素包含 deviceName 和 deviceId 属性
// 请保存以备后续用于 选择设备、本地预览 等
console.log(videoCaptureDevices);
本地预览
通过 RtcEngine
实例的 videoDeviceMgr()
方法获取视频设备管理器(RtcVideoDeviceManager
),再通过其 startPreview(deviceId, view, options)
方法开启本地摄像头预览。
let selectedCamera = videoCaptureDevices[0].deviceId;
let localView = document.getElementById('localView');
// 可以通过 CSS 控制其大小、位置和缩放模式
localView.setAttribute('style', 'width: 320px; height: 180px; object-fill: contain;');
let options = {
// profile: VideoProfileType.HD720P, // 预览分辨率,默认值由系统自动决定
// mirror: true // 是否镜像,默认值 false
}
rtcEngine.videoDeviceMgr().startPreview(selectedCamera, localView, options);
如果你有多个摄像头,需要切换预览时:
- 先通过
RtcVideoDeviceManager
的stopPreview(deviceId)
方法停止当前预览;- 重新调用
startPreview
方法传入新的deviceId
等参数来显示新的摄像头预览。
加入频道
加入频道
通过 RtcEngine
实例的 joinChannel(token, channelId, userId, options)
方法加入频道。
let option = {
// channelMode 频道模式:Mode_1v1 一对一模式,Mode_Meeting 会议模式
// 如果有 Web 端参与,或者需要进行直播/录制,请设置为 ChannelMode.Mode_Meeting
channelMode: ChannelMode.Mode_Meeting,
// serviceFlags 频道标志:Electron SDK 仅支持 kChannelServiceMedia (音视频)
serviceFlags: kChannelServiceMedia,
// 如果 subscribeAudioAll 配置为 true,SDK 会自动订阅音频
// 如果配置为 false,需要开发者自行订阅音频
subscribeAudioAll: true,
userName: 'Test'
}
rtcEngine.joinChannel(token, channelId, userId, option);
自己加入频道的通知
调用 joinChannel
方法后,将触发 channelJoinConfirm
通知。
rtcEngine.on('channelJoinConfirm', result => {
if (result == QResult.OK) {
// 加入频道成功
}else{
// 加入频道失败
}
}
其他用户加入频道的通知
其他用户加入频道时,将触发 userJoinIndication
通知。
rtcEngine.on('userJoinIndication', (userId, userName) => {
// 可将其加入到与会者列表中
}
倒计时通知
加入频道后,如果存在倒计时限制,将触发 channelCountDown
通知。
rtcEngine.on('channelCountDown', remain => {
// 请保存 remain 用于展示倒计时,此回调仅在加入频道后回调一次,单位为秒
}
- 已实名认证,并且使用正式token,Pano不限制频道时长
- 未实名认证,或者使用临时token,最大频道时长为 30 分钟
操作视频
发送本地视频
加入频道成功后:
- 可以通过
RtcEngine
实例的videoDeviceMgr()
方法获取视频设备管理器(RtcVideoDeviceManager
),再通过其setDevice(deviceId)
方法设置需要使用的视频采集设备; - 通过
RtcEngine
实例的startVideo(view, options)
方法发送本地视频。
// 调用 startVideo 方法后,其他用户才能看到你的画面
// 可以通过 options.profile 指定发送分辨率,SDK 将尝试发送此分辨率
// 实际发送分辨率受硬件参数、浏览器环境、订阅情况、网络状态等因素综合影响
// 如果 startVideo 接口需要和 startPreview (本地预览)接口复用同一个 View,请先停止预览
selectedCamera = videoCaptureDevices[0].deviceId;
// rtcEngine.videoDeviceMgr().stopPreview(selectedCamera); // 如需复用 View,请先停止预览
rtcEngine.videoDeviceMgr().setDevice(selectedCamera); // 如果不指定,SDK 将使用系统默认设备来发送视频
localView = document.getElementById('localView');
options = {
profile: VideoProfileType.HD720P, // 发送分辨率,默认值 VideoProfileType.Low
// mirror: true // 是否镜像,默认值 false
}
rtcEngine.startVideo(localView, options);
如果你有多个摄像头,需要切换发送时,调用
RtcVideoDeviceManager
实例的setDevice(deviceId)
方法传入新的摄像头 ID 即可。
发送本地视频会触发 videoStartResult
通知。
rtcEngine.on('videoStartResult', result => {
console.info(`videoStartResult: ${result}`)
})
停止发送本地视频
通过 RtcEngine
实例的 stopVideo()
方法停止发送本地视频。
rtcEngine.stopVideo(); // 调用此方法后,其他用户将看不到你的画面
其他用户开启视频的通知
当其他用户发送视频时,将触发 userVideoStart
通知。
rtcEngine.on('userVideoStart', (userId, maxProfile) => {
// maxProfile 表示该用户的最大可发送分辨率
// 取决于 摄像头支持的最大分辨率 和 设置的发送分辨率 这两个值中的较小值
}
订阅其他用户的视频
通过 RtcEngine
实例的 subscribeVideo(userId, view, options)
方法订阅其他用户的视频。
// 请在收到其他用户的 userVideoStart 通知后,再调用订阅
let remoteView = document.getElementById('remoteView');
let options = {
// 可以根据显示窗口的大小来决定订阅分辨率,比如大窗口订阅高分辨率,小窗口订阅低分辨率
profile: maxProfile, // 订阅分辨率,如果不传此项,默认值为 VideoProfileType.Low
// mirror: false // 是否镜像,默认值 false
}
rtcEngine.subscribeVideo(userId, remoteView, options);
- Pano采用订阅模式来接收视频,参与者之间需要相互订阅,才可以看到彼此的视频画面。
- 默认 正式token 最多可以订阅 10 路视频,临时token 最多可以订阅 3 路视频。
- 如果订阅失败,会触发
userVideoSubscribe
通知。
视频首帧的通知
当自己发送或收到其他用户第一个视频帧时,将触发 firstVideoFrameRendered
通知。
rtcEngine.on('firstVideoFrameRendered', userId => {
// // 第一个视频帧通知,可以开始显示视频画面
});
取消订阅其他用户的视频
通过 RtcEngine
实例的 unsubscribeVideo(userId)
方法取消订阅其他用户的视频。
// 调用此方法后,你将看不到该用户的画面
rtcEngine.unsubscribeVideo(userId);
操作声音
发送本地声音
通过 RtcEngine
实例的 startAudio()
方法发送本地声音。
rtcEngine.startAudio(); // 调用此方法后,其他用户才能听到你的声音;请在加入频道成功后再调用
调用此方法,会触发
audioStartResult
回调。
停止发送本地声音
通过 RtcEngine
实例的 stopAudio()
方法停止发送本地声音。
// 调用此方法后,其他用户将听不到你的声音
// 不影响你接收其他用户的声音
// 可以调用 startAudio 重新发送
rtcEngine.stopAudio();
静音麦克风
通过 RtcEngine
实例的 muteAudio()
方法静音本地麦克风。
rtcEngine.muteAudio(); // 调用此方法后,其他用户将听不到你的麦克风的声音
停止发送本地声音(
stopAudio
) 和 静音本地麦克风(muteAudio
) 这两个接口都可以将自己静音(不让其他用户听到你的声音)。它们的区别在于:
1 "停止发送本地声音"会断开音频通道连接(同时停止发送麦克风和伴音的声音,会取消其他用户订阅你的声音,如需重建连接需要消耗时间)
2 "静音本地麦克风"会发送静音包(不影响伴音发送,不影响订阅关系,静音包数据量很小,临时静音建议使用此方式,取消静音能够迅速恢复发送声音)
取消静音麦克风
通过 RtcEngine
实例的 unmuteAudio()
方法取消静音本地麦克风。
rtcEngine.unmuteAudio(); // 静音麦克风后,需要取消静音,其他用户才能听到你的麦克风的声音
其他用户开启声音的通知
当其他用户发送声音时,将触发 userAudioStart
通知。
rtcEngine.on('userAudioStart', userId => {
console.info(`userAudioStart, userId: ${userId}`)
}
订阅其他用户的声音
- 如果在 加入频道 时配置了
subscribeAudioAll: true
,SDK 会自动订阅其他所有用户的声音,开发者无需手工操作。 - 如果配置了
subscribeAudioAll: false
,开发者可以在收到 其他用户开启声音的通知 后,通过RtcEngine
实例的subscribeAudio(userId)
方法订阅其声音。
rtcEngine.on('userAudioStart', userId => {
rtcEngine.subscribeAudio(userId); // 可以在此时订阅该用户的声音
});
- 如果希望在通话过程中,不收听某位与会者,或者不收听所有其他与会者,请在加入频道时,设置不自动订阅音频;随后按需订阅或取消订阅某位或所有其他与会者。
- 如果订阅失败,会触发
userAudioSubscribe
通知。
取消订阅其他用户的声音
可以通过 RtcEngine
实例的 unsubscribeAudio(userId)
方法取消订阅其他用户的声音。
如果在 加入频道 时配置
subscribeAudioAll: true
,SDK 将自动订阅声音,开发者无法主动取消订阅。
当配置 subscribeAudioAll: false
时,典型的需要取消订阅声音的场景例如:
- 不需要再听到某位用户的声音,可以主动取消订阅其声音;
- 收到其他用户停止发送声音的通知时,应取消订阅其声音。
rtcEngine.on('userAudioStop', userId => {
// 收到其他用户停止发送声音的通知,如果配置了"subscribeAudioAll: false",此时应取消订阅其声音
rtcEngine.unsubscribeAudio(userId);
});
离开频道
离开频道
通过 RtcEngine
实例的 leaveChannel()
方法离开频道。
rtcEngine.leaveChannel();
注意:调用此接口主动离开频道,自己不会收到
channelLeaveIndication
回调。
其他用户离开频道的通知
其他用户离开频道后,将触发 userLeaveIndication
通知。
rtcEngine.on('userLeaveIndication', (userId, reason) => {
// 可将其从与会者列表中移除
};
使用框架
如果使用 VUE、React 等框架进行开发,需要使用 native-ext-loader 等插件来打包,可以参考 PanoVideoDemo 的 vue.config.js 文件中的配置。
反馈问题
我们强烈建议您集成反馈功能,以便用户遇到问题时,可以提交信息给我们分析排查,具体请 点此查看。
示例代码
为方便开发者了解丰富的接口使用方式,我们还提供示例代码,请体验参考: