本文介绍的是在wed端如何集成即构音视频SDK,以实现在wed端一对一,一对多及多人实时视频通话的功能。

一、SDK集成指引

1、安装

请从 jZego-RTC-SDK <https://storage.zego.im/downloads/jZego-rtc-SDK.zip> 下载 SDK。
npm下载包支持typescript语言(推荐):

npm i webrtc-zego

2、集成SDK

可使用script直接引入
<script src="jZego-rtc-1.0.1.js"></script>
或者
import {ZegoClient} from 'webrtc-zego'或 var ZegoClient = require('webrtc-zego'
).ZegoClient
API 说明请参考:Web SDK API 说明
<https://www.zego.im/html/document/#Live_Room/API_Instructions:web>。

3、兼容性说明

由于不同的浏览器对于 Web 的支持各不相同,目前 SDK 支持的浏览器的版本如下:


二、功能实现流程

1、实现流程

以下是简单的SDK调用流程,详细API接口请参考接口文档

1.1 初始化SDK
// 声明变量 var zg; // 初始化实例 zg = new ZegoClient(); // 配置必要参数 zg.config({ appid:
appid,// 必填,应用id,由即构分配 idName: idName, // 必填,用户自定义id,全局唯一 nickName: nickName,
// 必填,用户自定义昵称 remoteLogLevel: 1, // 上传日志最低级别,建议跟 logLevel 一致 logLevel: 1, //
日志级别,debug:0,info:1,warn:2,error:3,report:99,disable:100(数字越大,日志越少),建议选择 1
server: server // 必填,接入服务器地址,由即构分配 logUrl: logUrl // 必填,logServer 地址,由即构分配 });
1.2 获取登录 token

登录 token 的获取详见后文 3 安全方案 中的 3.1 房间登录安全。

源码片段如下:
// 获取登录 token function loadLoginToken() { var xmlhttp; xmlhttp = new
XMLHttpRequest(); xmlhttp.onreadystatechange =function() { if
(xmlhttp.readyState ==4) { if (xmlhttp.status == 200) { trace("login token
success:" + xmlhttp.responseText); loginToken = xmlhttp.responseText;
doLogin(); }else { trace("login token failed"); alert("获取登录信息失败"); } } };
//从开发者后台获取token xmlhttp.open("GET", loginTokenUrl + "?app_id=" + appid +
"&id_name=" + idName, true); xmlhttp.send(); }
1.3 登录房间

登录房间成功是后续信令操作的前提。源码片段如下,仅供参考:
zg.login(roomId, 2, loginToken, function(streamList) { //登录成功处理逻辑 }, function
(err) { alert("login error: " + err.msg); });
1.4 枚举设备

SDK提供接口可以枚举当前的麦克风,摄像头,扬声器设备。源代码片段如下,仅供参考:
zg.enumDevices(function(deviceInfo) { if (deviceInfo.microphones) { for (var i
=0; i < deviceInfo.microphones.length; i++) { trace("microphone: " +
deviceInfo.microphones[i].label); } }if (deviceInfo.cameras) { for (var j = 0;
j < deviceInfo.cameras.length; j++) { trace("camera: " +
deviceInfo.cameras[i].label); } } });
1.5 本地预览

在开播前可以预览当前画面,可以指定麦克风和摄像头的设备Id,也可以使用默认设备。源代码片段如下,仅供参考:
function doPreview(audioInput, videoInput) { var avConstraints = { audio: true
, audioInput: audioInput, video:true, videoInput: videoInput, videoQuality:
videoQuality, horizontal:true }; //WebRTC可以共用相同设备,所以预览时必须指定开播的streamId
zg.startPreview( localVideo, avConstraints,function() { trace("preview success"
); doPublish(); },function(error) { alert("start device error " , error); }); }
*
使用默认设备时,audioInput和videoInput参数不用填


推纯音频或纯视频时,只需将对应的video或audio设为false,然后在播放拉流接口中传入第四个播放模式参数,例:zg.startPlayingStream(streamId,
video,null,{playType:’audio’});

1.6 开始直播

开始直播前必须先开始预览。源代码片段如下,仅供参考:
function doPublish() { var result = zg.startPublishingStream(publishStreamId,
localVideo);if (!result) { alert("publish " + publishStreamId + " return " +
result); } }
1.7 直播状态回调

直播开始,直播失败,重试直播都通过此回调通知。源代码如下,仅供参考:
zg.onPublishStateUpdate = function(type, streamid, error) { if (type == 0) {
trace("publish " + streamid + " success"); } else if (type == 2) { trace(
"publish " + streamid + " retry"); } else { // trace("publish " + streamid +
"error " + error.code); alert("publish " + streamid + " error " + error.msg); }
};
1.8 开始拉流

指定播放流的video标签,画面会渲染在指定的video标签里。源代码如下,仅供参考:
function doPlay(streamid) { trace("play " + streamid); var remoteVideo =
document.createElement("video"); remoteVideo.setAttribute("autoplay", "");
remoteVideo.setAttribute("webkit-playsinline", ""); var videos = util.getById(
"videos"); videos.appendChild(remoteVideo); remoteVideoMap[streamid] =
remoteVideo;var result = zg.startPlayingStream(streamid, remoteVideo); if
(!result) { alert("play " + streamid + " return " + result); } }
1.9 拉流状态回调

拉流开始,拉流失败,拉流重试都通过此回调通知。源代码如下,仅供参考:
zg.onPlayStateUpdate = function(type, streamid, error) { if (type == 0) {
trace("play " + streamid + " success"); } else if (type == 2) { trace("play " +
streamid +" retry"); } else { // trace("publish " + streamid + "error " + error
.code); alert("play " + streamid + " error " + error.msg); } };
2、屏幕共享

2.1 使用说明

*
web屏幕共享功能,目前只支持桌面端(例如window和mac)的chrome和火狐浏览器,其中chrome需要下载即构共享插件
<https://storage.zego.im/downloads/jZego-screen-extention.zip>

分享功能只能获取到系统扬声器声音,外部麦克风需另外推流(栗子:电脑播放音乐可以采集到,对着电脑说话声音采集不到)

当同时推多路流时,建议音频只推一路,防止回音

2.2 插件安装

*
解压即构共享插件;

打开你的 Chrome 浏览器,点击屏幕右上方的扩展按钮,选择 更多工具 > 扩展程序, 打开开发者模式 > 加载已解压的扩展程序 >
选择 解压的 即构共享插件文件夹,即可完成安装。

2.3 方法调用

2.4推流示例(chrome)
zg.startScreenShotChrome(function (suc,mediastream) { previewVideo.srcObject
= mediastream;//本地预览 // 与正常推流一样,需要先调用sdk预览接口,成功后再推流 , // 需要注意的是
mediaStreamConstraints.externalCapture = true (必须) zg.startPreview(localVideo,
mediaStreamConstraints,function() { zg.startPublishingStream(streamid,
localVideo, extraInfo); }, error) })
3 安全方案

3.1 房间登录安全

3.1.1 基本流程

*
JS与业务后台建立通信,获取 Token 信息。

JS调用 ZegoClient.login 登录 Zego 服务器,传入 Token 信息,验证通过后,完成登录。

ZegoClient 会保持与 Zego 服务器的长连接,处理发送或接收的消息。

JS调用 ZegoClient.logout 登出 Zego 服务器。

请注意:
生成 Token 信息需要业务后台自行开发。

3.1.2 login_token 信息

login_token 信息为标准 json 格式,具体为:
{ "ver": 1, "hash": xxxxx, "nonce": xxxxx, "expired": xxxxx, }


请注意:

login_token 传输过程中,会经过 base64 加密。

每次登录都要重新获取 login_token。

业务方开发的JS需要和业务后台建立一种安全通讯和鉴权机制,业务方使用自有的账户体系或第三方认证体系的登录完成后,业务方JS和业务后台交互获取该
login_token, AppSecret 是存储在业务后台的。

3.2 login_token 生成示例代码

go 语言 login_token 生成示例代码如下:
func makeTokenSample(appid uint32, app_key string, idname string, expired_add
int64) (retstring, err error){ nonce := UniqueId() expired := time.Now().Unix()
+ expired_add //单位:秒 app_key = strings.Replace(app_key, "0x","",-1) app_key =
strings.Replace(app_key,",", "", -1) if len(app_key) < 32 { return "",
fmt.Errorf("app_key wrong") } app_key_32 := app_key[0:32] source := fmt.Sprintf(
"%d%s%s%s%d",appid,app_key_32,idname,nonce,expired) sum := GetMd5String(source)
token := tokenInfo{} token.Ver = 1 token.Hash = sum token.Nonce = nonce token
.Expired = expired buf, err := json.Marshal(token) if err != nil { return "",
err } encodeString := base64.StdEncoding.EncodeToString(buf)return
encodeString, nil }
php 语言 login_token 生成示例代码如下:
public function getToken(int $app_id, string $app_key, string $idname, int
$expired_add) { $nonce = uniqid(); $expired = time() + $expired_add; //单位:秒
$app_key = str_replace("0x", "", $app_key); $app_key = str_replace(",", "",
$app_key); if(strlen($app_key) < 32) { return false; } $app_key_32 = substr(
$app_key, 0, 32); $source = $app_id.$app_key_32.$idname.$nonce.$expired; $sum =
md5($source); $tokenInfo = [ 'ver' => 1, 'hash' => $sum, 'nonce' => $nonce,
'expired' => $expired, ]; $token = base64_encode(json_encode($tokenInfo));
return $token; }
java 语言 login_token 生成示例代码如下:
package demo; import org.json.JSONObject; import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException; import java.util.Date; import
java.util.UUID;import org.apache.commons.codec.binary.Base64; public class
ZegouUtils { public static void main(String[] args) { String appid =
"0000000000"; //即构分配的appId String appKey =
"0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00"
;//即构分配的appKey String idName = "xxxxxxx"; //业务系统用户唯一标识 String Token =
getZeGouToken(appid,appKey,idName); System.out.println("--Token--:"+Token); }
/** * 拉流端获取登录token * @param appId 即构分配的appId * @param appKey 即构分配的appKey *
@param idName 业务系统用户唯一标识 * @return */ public static String getZeGouToken(String
appId,String appKey,String idName){ String nonce=
UUID.randomUUID().toString().replaceAll("-", ""); long time=new
Date().getTime()/1000+30*60; String appKey32=new String(appKey.replace("0x", ""
).replace(",", "").substring(0, 32)); System.out.println("appKey:"+time+" "
+appKey32+" "+nonce); if(appKey32.length()<32){ System.out.println("private key
erro!!!!"); return null; } String sourece=
getPwd(appId+appKey32+idName+nonce+time); System.out.println("hash:"+sourece);
JSONObject json=new JSONObject(); json.put("ver", 1); json.put("hash",
sourece); json.put("nonce", nonce); json.put("expired",time); //unix时间戳,单位为秒
org.apache.commons.codec.binary.Base64 base64 =new
org.apache.commons.codec.binary.Base64(); System.out.println("json"
+json.toString());return base64.encodeAsString(json.toString().getBytes()); }
/** * 获取MD5加密 * @param pwd 需要加密的字符串 * @return String字符串 加密后的字符串 */ public static
StringgetPwd(String pwd) { try { // 创建加密对象 MessageDigest digest =
MessageDigest.getInstance("md5"); // 调用加密对象的方法,加密的动作已经完成 byte[] bs =
digest.digest(pwd.getBytes());// 接下来,我们要对加密后的结果,进行优化,按照mysql的优化思路走 //
mysql的优化思路: // 第一步,将数据全部转换成正数: String hexString = ""; for (byte b : bs) { //
第一步,将数据全部转换成正数: int temp = b & 255; // 第二步,将所有的数据转换成16进制的形式 //
注意:转换的时候注意if正数>=0&&<16,那么如果使用Integer.toHexString(),可能会造成缺少位数 // 因此,需要对temp进行判断
if (temp < 16 && temp >= 0) { // 手动补上一个“0” hexString = hexString + "0" +
Integer.toHexString(temp); }else { hexString = hexString +
Integer.toHexString(temp); } }return hexString; } catch
(NoSuchAlgorithmException e) {// TODO Auto-generated catch block
e.printStackTrace(); }return ""; } }
4、常见错误

4.1 登陆房间时,控制台输出返回ZegoClient.Error.Timeout

解决方案: 请检查 初始化配置 ZegoClient.config 里面每个参数的类型是否正确,一般情况下都是类型不正确引起的问题。


4.2 登陆房间时,控制台输出返回result=1000001002

原因: 观众角色不允许创建房间,也就是这个房间不存在。

解决方案:

1)在ZegoClient.config里面的option.audienceCreateRoom设置为TRUE

2)在ZegoClient.login里面将role设置为1,主播角色。

4.3 登陆房间时,控制台输出返回token Error的报错

原因:计算token的时候,算法不对引起,可通过这个链接:http://sig-wstoken.zego.im:8181/tokenindex
<http://sig-wstoken.zego.im:8181/tokenindex> 来验证是否正确:

1) 首先验证 hash 字段是否有错,这里要注意 id_name 是string类型,不是数值类型; expired 是 uninx
的时间戳,不是北京时间。

2) login_token由业务侧后台生成后,将json里面的字段 经过base64加密 后再下发给web端。

友情链接
KaDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:[email protected]
QQ群:637538335
关注微信