微信小程序开发需要基于微信提供的开发者工具与 SDK。如果开发者对小程序开发流程不熟悉,建议先系统学习:微信小程序开发官方文档。

由于微信官方文档比较详细,本文对小程序开发流程中的框架说明、API 调用、组件使用等,不再赘述,而是重点介绍如何使用 ZEGO SDK 开发出支持音视频直播的微信小程序。

SDK 集成指引详见:微信小程序 SDK集成指引

SDK 提供的 API 说明详见:微信小程序 SDK API 说明

小程序开发主要用到 web 开发知识( js、html、css )。

1、组件说明

微信小程序中的推拉流功能,需要用到微信提供的 live-player live-pusher 标签。其他的常规组件同原生 App 开发类似,此处不一一介绍。

1.1 live-player

live-player 是微信提供的支持实时音视频播放的组件,官方介绍详见组件介绍。

开发者创建组件成功后,需要在 js 文件中,调用 API 操作对应的组件来实现需求,微信官方 API 详见 API 说明。

即构音视频云小程序中,创建 live-player 的演示源码如下:

ZegoLive/pages/liveroom/room/room.wxml<live-playerautoplaywx:if="{{item.playUrl}}"id="{{item.streamID}}"mode="RTC"object-fit="fillCrop"min-cache="0.1"max-cache="0.3"src="{{item.playUrl}}"debug="{{pushConfig.showLog}}"bindstatechange="onPlayStateChange"bindnetstatus="onPlayNetStateChange"binderror="error"><cover-view class='character' style='padding: 0 5px;'>{{item.streamID}}</cover-view>
</live-player>

请注意:

  1. live 模式主要用于直播类场景,比如赛事直播、在线教育、远程培训等等。该模式下,小程序内部的模块会优先保证观看体验的流畅,通过调整min-cache 和 max-cache 属性,您可以调节观众(播放)端所感受到的时间延迟的大小,文档下面会详细介绍这两个参数。

  2. RTC 则主要用于双向视频通话或多人视频通话场景,比如金融开会、在线客服、车险定损、培训会议 等等。在此模式下,对 min-cache 和 max-cache 的设置不会起作用,因为小程序内部会自动将延迟控制在一个很低的水平(500ms 左右)。

1.2 live-pusher

live-pusher 是微信提供的支持实时音视频录制的组件,官方介绍详见:组件介绍

开发者创建组件成功后,需要在 js 文件中,调用 API 操作对应的组件来实现需求,官方 API 详见:API 说明

即构音视频云小程序中,创建 live-pusher 的演示源码如下:

ZegoLive/pages/liveroom/room/room.wxml<live-pusherwx:if="{{pushUrl}}"id="video-livePusher"mode="RTC"url="{{pushUrl}}"min-bitrate="{{pushConfig.minBitrate}}"max-bitrate="{{pushConfig.maxBitrate}}"aspect="{{pushConfig.aspect}}"beauty="{{pushConfig.isBeauty}}"muted="{{pushConfig.isMute}}"background-mute="true"debug="{{pushConfig.showLog}}"bindstatechange="onPushStateChange"bindnetstatus="onPushNetStateChange"><cover-view class='character' style='padding: 0 5px;'>{{isPublishing ? "我(" + publishStreamID + ")": ""}}</cover-view>
</live-pusher>

请注意:

  • SD、HD 和 FHD 主要用于直播类场景,比如赛事直播、在线教育、远程培训等等。SD、HD 和 FHD
    分别对应三种默认的清晰度。该模式下,小程序会更加注重清晰度和观看的流畅性,不会过分强调低延迟,也不会为了延迟牺牲画质和流畅性。
  • RTC 则主要用于双向视频通话或多人视频通话场景,比如金融开会、在线客服、车险定损、培训会议
    等等。该模式下,小程序会更加注重降低点到点的时延,也会优先保证声音的质量,在必要的时候会对画面清晰度和画面的流畅性进行一定的缩水。

2、实现流程

2.1 推流 API 调用流程图

详细讲解请参考 2.6 小节。

2.2 拉流 API 调用流程图

2.3 初始化 SDK

ZegoLive/pages/liveroom/room/room.js// 声明变量
var ZegoSDK = require("../../../js/jZego-wx-1.0.2.js");
var zg;// 初始化实例
zg = new ZegoSDK.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(数字越大,日志越少),建议选择 1server: server        // 必填,接入服务器地址,由即构分配logUrl: logUrl        // 必填,logServer 地址,由即构分配
});

2.4 获取登录 token

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

即构小程序中演示源码片段如下:

ZegoLive/pages/liveroom/room/room.js// 获取登录 token
getLoginToken: function () {var self = this;const requestTask = wx.request({url: 'xxxx', // 该接口由开发者后台自行实现,开发者的 Token 从各自后台获取data: {app_id: self.data.appID,id_name: self.data.userID,},header: {'content-type': 'text/plain'},success: function (res) {console.log(">>>[liveroom-room] get login token success. token is: " + res.data);if (res.statusCode != 200) {return;}zg.setUserStateUpdate(true);self.loginRoom(res.data, self);},fail: function (e) {console.log(">>>[liveroom-room] get login token fail, error is: ")console.log(e);}});
},

2.5 登录房间

登录房间成功是后续所有操作的前提。即构音视频云小程序中演示源码片段如下,仅供参考:

ZegoLive/pages/liveroom/room/room.jszg.login(self.data.roomID, self.data.loginType == "anchor" ? 1 : 2, token, function (streamList) {// 登录成功处理console.log('>>>[liveroom-room] login succeeded');
}, function (err) {// 登录失败处理console.log('>>>[liveroom-room] login failed, error is: ', err);
});

登录错误码列表如下:

2.6 单主播直播

单主播直播时,一个房间内仅有一个主播,主播不会与观众进行互动。

2.6.1 开始推流

主播登录房间成功后,根据业务逻辑准备推流。使用 SDK 推流播放需要遵循如下步骤:

  • 触发推流

  • 调用 SDK 的 startPublishingStream 获取 streamID 对应的推流地址

  • 在 SDK 的回调 onStreamUrlUpdate 中获推流地址

  • 调用微信小程序的 wx.createLivePusherContext 创建 live-pusher ,将步骤 3 中获取的推流地址设置为
    live-pusher 的 url,然后调用 live-pusher 的 start() 录制视频

演示源码片段如下,仅供参考:

ZegoLive/pages/liveroom/room/room.js// 1/2. 主播登录房间成功后触发推流,调用 SDK 的 startPublishingStream 获取 streamID 对应的推流地址
zg.login(self.data.roomID, self.data.loginType == "anchor" ? 1 : 2, token, function (streamList) {// 主播登录成功即推流if (self.data.loginType == 'anchor') {console.log('>>>[liveroom-room] anchor startPublishingStream, publishStreamID: ' + self.data.publishStreamID); zg.setPreferPublishSourceType(1); // 0:推流到 CDN,观众拉流延迟在 2 秒左右;1:推流到 ZEGO 服务器,延迟在 400ms 左右zg.startPublishingStream(self.data.publishStreamID, '');}
}, function (err) {console.log('>>>[liveroom-room] login failed, error is: ', err);
});// 3. 在 SDK 的回调 onStreamUrlUpdate 中获取推流地址
// type: {play: 0, publish: 1};
zg.onStreamUrlUpdate = function (streamid, url, type) {console.log(">>>[liveroom-room] zg onStreamUrlUpdate, streamId: " + streamid + ', type: ' + (type == 0 ? 'play' : 'publish') + ', url: ' + url);...
};// 4. 调用微信小程序的 wx.createLivePusherContext 创建 live-pusher ,将步骤 3 中获取的推流流地址设置为 live-player 的 url,然后调用 live-pusher 的 start 录制视频
setPushUrl: function (url) {console.log('>>>[liveroom-room] setPushUrl: ', url);var self = this;...self.setData({pushUrl: url,pusherVideoContext : wx.createLivePusherContext("video-livePusher", self),}, function () {self.data.pusherVideoContext.stop();self.data.pusherVideoContext.start();});
},

2.6.2 开始拉流

观众登录房间成功后,根据业务逻辑准备拉流。使用 SDK 拉流播放需要遵循如下步骤:

  • 触发拉流

  • 调用 SDK 的 startPlayingStream 获取 streamID 对应的播放地址

  • 在 SDK 的回调 onStreamUrlUpdate 中获取拉流地址

  • 调用微信小程序的 wx.createLivePlayerContext 创建 live-player ,将步骤 3 中获取的推流地址设置为
    live-player 的 src,然后调用 live-player 的 play() 播放视频。此步骤也可以设置 live-player
    为 autoplay,此时播放器会自动播放,无需再手动调用 play()。

演示源码片段如下,仅供参考:

ZegoLive/pages/liveroom/room/room.js// 1. 登录后拉流
zg.login(self.data.roomID, self.data.loginType == "anchor" ? 1 : 2, token, function (streamList) {// 房间内已经有流,拉流self.startPlayingStreamList(streamList);
}, function (err) {console.log('>>>[liveroom-room] login failed, error is: ', err);
});// 2. 通过 SDK 获取 streamID 对应的播放地址
startPlayingStreamList: function (streamList) {var self = this;...// 设置拉流目标地址,可选,0:auto;1:从 bgp 拉流zg.setPreferPlaySourceType(1); // 获取每个 streamID 对应的拉流 urlvar playStreamList = self.data.playStreamList;for (var i = 0; i < streamList.length; i++) {var streamID = streamList[i].stream_id;// 调用 SDK 的 startPlayingStream 获取 streamID 对应的播放地址zg.startPlayingStream(streamID);}
},// 3. 在 SDK 的回调 onStreamUrlUpdate 中获取拉流地址
// type: {play: 0, publish: 1};
zg.onStreamUrlUpdate = function (streamid, url, type) {console.log(">>>[liveroom-room] zg onStreamUrlUpdate, streamId: " + streamid + ', type: ' + (type == 0 ? 'play' : 'publish') + ', url: ' + url);...
};// 4. 调用微信小程序的 wx.createLivePlayerContext 创建 live-player ,将步骤 3 中获取的拉流地址设置为 live-player 的 src,然后调用 live-player 的 play() 播放视频。此步骤也可以设置 live-player 为 autoplay,此时播放器会自动播放,无需再手动调用 play()
setPlayUrl: function (streamid, url, self) {...// 相同 streamid 的源不存在,创建新 playerif (!isStreamRepeated) {streamInfo['streamID'] = streamid;streamInfo['playUrl'] = url;streamInfo['playContext'] = wx.createLivePlayerContext(streamid, self);self.data.playStreamList.push(streamInfo);}...self.setData({playStreamList: self.data.playStreamList,}, function(){});
},

2.6.3 拉流、推流事件处理

微信小程序会在 live-player 和 live-pusher 的 bindstatechange 绑定的方法中通知出推拉流状态事件,开发者需要:

在 bindstatechange 绑定的回调函数中,调用 SDK 提供的 API updatePlayerState 将推流事件透传给 SDK

在 SDK 提供的 onPlayStateUpdate onPublishStateUpdate 回调中处理播推、拉流的开始、失败状态

演示源码片段如下,仅供参考:

ZegoLive/pages/liveroom/room/room.js// live-player 绑定的拉流事件
onPlayStateChange(e) {// 透传拉流事件给 SDK,type 0 拉流zg.updatePlayerState(e.currentTarget.id, e, 0);
},// 服务端主动推过来的 流的播放状态, 视频播放状态通知;type: { start:0, stop:1};
zg.onPlayStateUpdate = function (updatedType, streamID) {console.log(">>>[liveroom-room] zg onPlayStateUpdate, " + (updatedType == 0 ? 'start ' : 'stop ') + streamID);
};
// live-pusher 绑定推流事件
onPushStateChange(e) {// 透传推流事件给 SDK,type 1 推流zg.updatePlayerState(this.data.publishStreamID, e, 1);
},// 推流后,服务器主动推过来的,流状态更新;type: { start: 0, stop: 1 },主动停止推流没有回调,其他情况均回调
zg.onPublishStateUpdate = function (type, streamid, error) {console.log('>>>[liveroom-room] zg onPublishStateUpdate, streamid: ' + streamid + ', type: ' + (type == 0 ? 'start' : 'stop') + ', error: ' + error);
};

另外,小程序会在 live-player 和 live-pusher 的 bindnetstatus 绑定的方法中通知出推拉流网络事件,开发者也需要在对应的小程序回调中,调用 updatePlayerNetStatus 将推流事件透传给 SDK。

演示源码片段如下,仅供参考:

// live-player 绑定网络状态事件
onPlayNetStateChange(e) {// 透传网络状态事件给 SDK,type 0 拉流zg.updatePlayerNetStatus(e.currentTarget.id, e, 0);
},// SDK 拉流网络质量回调
zg.onPlayQualityUpdate = function (streamId, streamQuality) {...
},
// live-pusher 绑定网络状态事件
onPushNetStateChange(e) {//透传网络状态事件给 SDK,type 1 推流zg.updatePlayerNetStatus(this.data.publishStreamID, e, 1);
},// SDK 推流网络质量回调
zg.onPublishQualityUpdate = function (streamId, streamQuality) {...
},

2.6.4 停止推、拉流

停止推拉流,开发者需要:

调用 SDK 提供的 stopPublishingStream(streamid) stopPlayingStream(streamid) 清空推、拉流状态

调用 live-pusher 和 live-player 提供的 stop() 停止推、拉流

请注意,上述第 1 点一定要处理,否则可能导致 SDK 状态异常!

演示源码片段如下,仅供参考:

// 停止拉流
zg.stopPlayingStream(this.data.playStreamList[i]['streamID']);
this.data.playStreamList[i]['playContext'] && this.data.playStreamList[i]['playContext'].stop();// 停止推流
zg.stopPublishingStream(this.data.publishStreamID);
this.data.pusherVideoContext.stop();

2.7 多主播直播

多主播直播是主播与观众连麦,使观众也成为主播的互动功能。视频会议也可通过该模式实现。多主播直播较单主播直播多出了连麦信令交互过程。推流、拉流流程同单主播基本一致,本节不再赘述。

2.7.1 连麦交互

观众申请连麦交互的主要步骤是:

  • 观众申请连麦,SDK 接口: requestJoinLive

  • 主播收到观众的申请连麦,SDK 接口: onRecvJoinLiveRequest

  • 主播同意/拒绝连麦,SDK 接口: respondJoinLive

  • 观众或主播结束连麦,SDK 接口: endJoinLive

主播邀请连麦交互的主要步骤是:

  • 主播邀请观众连麦,SDK 接口: inviteJoinLive

  • 观众收到主播的邀请连麦,SDK 接口: onRecvJoinLiveRequest

  • 观众同意/拒绝连麦,SDK 接口: respondJoinLive

  • 主播或观众结束连麦,SDK 接口: endJoinLive

开发者可按需调用 SDK 连麦相关 API。即构音视频云小程序中演示源码片段如下,仅供参考:

ZegoLive/pages/liveroom/room/room.js// 观众请求连麦
requestJoinLive: function () {var self = this;// 观众正在连麦时点击,则结束连麦if (self.data.isPublishing) {zg.endJoinLive(self.data.anchorID, function(result, userID, userName) {console.log('>>>[liveroom-room] endJoinLive, result: ' + result);}, null);// 停止推流zg.stopPublishingStream(this.data.publishStreamID);this.setData({isPublishing: false,publishTitle : "未推流",});this.data.pusherVideoContext.stop();return;}// 观众未连麦,点击开始推流console.log('>>>[liveroom-room] audience requestJoinLive');zg.requestJoinLive(this.data.anchorID, null, null, function(result, userID, userName) {console.log('>>>[liveroom-room] requestJoinLive, result: ' + result);if (result == false) {wx.showToast({title: '主播拒绝连麦',icon: 'none',duration: 2000})} else {wx.showToast({title: '主播同意连麦,准备推流',icon: 'none',duration: 2000});// 主播同意连麦后,观众开始推流console.log('>>>[liveroom-room] startPublishingStream, userID: ' + userID + ', publishStreamID: ' + self.data.publishStreamID);zg.setPreferPublishSourceType(1); // 0:推流到 CDN,观众拉流延迟在 2 秒左右;1:推流到 ZEGO 服务器,延迟在 400ms 左右zg.startPublishingStream(self.data.publishStreamID, '');}
},// 收到连麦请求
zg.onRecvJoinLiveRequest = function(requestId, fromUserId, fromUsername, roomId) {console.log('>>>[liveroom-room] onRecvJoinLiveRequest, roomId: ' + roomId + 'requestUserId: ' + fromUserId + ', requestUsername: ' + fromUsername);var content = '观众 ' + fromUsername + ' 请求连麦,是否允许?';wx.showModal({title: '提示',content: content,success: function(res) {if (res.confirm) {console.log('>>>[liveroom-room] onRecvJoinLiveRequest accept join live');zg.respondJoinLive(requestId, true); // true:同意;false:拒绝 } else if (res.cancel) {console.log('>>>[liveroom-room] onRecvJoinLiveRequest refuse join live');zg.respondJoinLive(requestId, false); // true:同意;false:拒绝 }}});
};

2.8 混流

混流可以把多路直播的流根据配置信息,输出成一路流。开发者可按需调用 SDK 混流相关 API。演示源码片段如下,仅供参考:

//更新混流配置
updateMixStream: function () {console.log('>>>[liveroom-room] updateMixStream');var self = this;if (self.data.loginType !== 'anchor') {return;}var width = 360;var height = 640;var mixConfig = {};//混流输出流IDmixConfig.outputStreamId = "mix-" + self.data.publishStreamID;//混流输出帧率mixConfig.outputFps = 15;//混流输出码率mixConfig.outputBitrate = 800 * 1000;//混流输出分辨率mixConfig.outputWidth = width;mixConfig.outputHeight = height;//混流背景色mixConfig.outputBgColor = 0xc8c8c800;//混流输入流信息mixConfig.streamList = [];var margin = 0;if (self.data.isPublishing) {var streamInfo = {streamId: self.data.publishStreamID,top: margin,left: margin,bottom: height - margin,right: width - margin};mixConfig.streamList.push(streamInfo);}for (var i = 0; i < self.data.playStreamList.length; i++) {var streamId = self.data.playStreamList[i].streamID;var streamInfo = {streamId: streamId,top: 0,left: 0,bottom: 0,right: 0};if (mixConfig.streamList.length == 0) {streamInfo.bottom = height;streamInfo.right = width;}else if (mixConfig.streamList.length == 1) {streamInfo.top = parseInt(height * 2 / 3);streamInfo.left = parseInt(width * 2 / 3);streamInfo.bottom = height;streamInfo.right = width;}else if (mixConfig.streamList.length == 2) {streamInfo.top = parseInt(height * 2 / 3);streamInfo.left = 0;streamInfo.bottom = height;streamInfo.right = parseInt(width / 3);}mixConfig.streamList.push(streamInfo);}zg.updateMixStream(mixConfig, function(mixStreamId, mixStreamInfo) {console.log(">>>[liveroom-room] updateMixStream success");var rtmpUrls = mixStreamInfo["rtmpUrls"];for (var i = 0; i < rtmpUrls.length; i++) {console.log(">>>[liveroom-room] updateMixStream mix Rtmp: " + rtmpUrls[i]);}wx.showModal({title: '提示',content: '混流成功',showCancel: false});}, function(error, info) {console.error(">>>[liveroom-room] updateMixStream error " + error.code);if (info) {for (var i = 0; i < info.length; i++) {console.error(">>>[liveroom-room] input stream not exist " + info[i]);}}wx.showModal({title: '提示',content: '混流失败',showCancel: false});});
},//停止混流
stopMixStream: function () {console.log(">>>[liveroom-room] stopMixStream");var self = this;var mixConfig = {};mixConfig.outputStreamId = "mix-" + self.data.publishStreamID;zg.stopMixStream(mixConfig, undefined, undefined);
},

3、退后台处理

切后台,会停止视频采集,但不会禁用音频采集。开发者可以通过 background-mute 属性来设置是否禁用音频采集。

切后台,会停止视频播放,默认退后台静音。

4、安全方案

4.1 房间登录安全

4.1.1 基本流程

  • 小程序与业务后台建立通信,获取 Token 信息。

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

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

  • 小程序调用 ZegoClient.logout 登出 Zego 服务器。

请注意:

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

4.1.2 login_token 信息

login_token 信息为标准 json 格式,具体为:

{"ver": 1,"hash": xxxxx,"nonce": xxxxx,"expired": xxxxx,
}

字段说明如下:

对于 hash 计算中使用字段的更详细说明:

请注意:

  1. login_token 传输过程中,会经过 base64 加密。每次登录都要重新获取 login_token。

  2. 业务方开发的小程序需要和业务后台建立一种安全通讯和鉴权机制,业务方使用自有的账户体系或第三方认证体系的登录完成后,业务方小程序和业务后台交互获取该

  3. login_token, AppSecret 是存储在业务后台的。

4.2 login_token 生成示例代码

go 语言 login_token 生成示例代码如下:

func makeTokenSample(appid uint32, app_key string, idname string, expired_add int64) (ret string, 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 = 1token.Hash = sumtoken.Nonce = noncetoken.Expired = expiredbuf, 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";  //即构分配的appIdString 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";  //即构分配的appKeyString 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 String getPwd(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 blocke.printStackTrace();}return "";}}

5、状态码

5.1 推流状态码

onPublishStateUpdate stateCode 含义如下:

其他 4 位错误码均为小程序框架的报错,请参考:小程序官方文档

5.2 拉流状态码

onPlayStateUpdate stateCode 含义如下:

其他 4 位错误码均为小程序框架的报错,请参考:小程序官方文档

6、常见错误

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

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

6.2 登录房间时,控制台输出返回 result=1000001002

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

解决方案:

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

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

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

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

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

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

详情请参考: 4.1 房间登录安全

6.4 小程序如何设置分辨率?

微信小程序提供设置清晰度的 mode,无法指定具体的分辨率,码率和帧率,具体可参考:

微信小程序组件 live-pusher

6.5 小程序如何切换摄像头、截图?

微信小程序的 LivePusherContext 里面有提供相关的接口,大家可参考:微信小程序 API LivePusherContext

切换摄像头的示例代码可参考:

7、微信公众平台域名配置

ZEGO 分配给开发者的 URL(包含 HTTPS、WSS 协议),需要在微信公众平台进行“合法域名”配置后,小程序才能正常访问。

微信后台配置地址:微信公众平台 -> 设置 -> 开发设置 -> 服务器域名。

请开发者将 ZEGO 分配的请求域名,按照协议分类,填到指定的 request合法域名 或者 socket合法域名 中。例如:

微信小程序视频直播开发实现流程相关推荐

  1. 微信小程序高级实战开发培训视频

    JEECG社区<微信小程序高级实战开发培训视频> 课      程:  微信小程序高级实战开发培训视频 讲      师:   周俊峰.张加强 开课时间:  2016年12月06日开课 * ...

  2. 基于微信小程序做直播的截图(微信小程序发起视频直播)

    第1部分:大至描述 用微信小程序来发起直播(推流): 用户即可以通过微信直接观看,也可以通过PC端web浏览器观看或通过手机浏览器观看. 第2部分:提示说明 图1,是小程序界面方面的截图(P1图中:截 ...

  3. 即构科技推出小程序视频直播方案,与iOSAndroid APP互通连麦

    2017年12 月 26 日,微信小程序正式对外开放了实时音视频录制及播放能力.符合类目要求(见下方表格)的小程序自助开通后,可自建或使用云服务,实现单向和互动的音视频功能,如视频直播.互动直播.在线 ...

  4. 微信小程序组件库开发记录

    微信小程序组件库开发记录 背景 前言 技术选型 环境搭建 安装 gulp 将`scss`编译为`wxss` 压缩`wxml`,`js`,`json`文件和图片 拷贝文件到另一个目录 删除目录 整合 创 ...

  5. 详细解析黑马微信小程序视频--【思维导图知识范围】

    语言视频选择 收录专辑链接 C 张雪峰推荐选择了计算机专业之后-在大学期间卷起来-[大学生活篇] JAVA 黑马B站视频JAVA部分的知识范围.学习步骤详解 JAVAWEB 黑马B站视频JAVAWEB ...

  6. 微信小程序应该这样开发

    微信小程序应该这样开发 帐号相关流程 注册范围 企业 政府 媒体 其他组织(换句话讲就是不让个人开发者注册) 填写企业信息 不能使用和之前的公众号账户相同的邮箱,也就是说小程序是和微信公众号一个层级的 ...

  7. 另一个小程序 返回的支付结果如何得到_微信小程序商城的开发商家需要注意什么?...

    原标题:微信小程序商城的开发商家需要注意什么? 小程序的应用目前已经成为人们使用较为普遍的平台,无论是用于吃喝玩乐亦或是工具.商业发展等.微信作为小程序的首家推出平台,凭借其自身的10亿流量用户让小程 ...

  8. 微信小程序Taro + React开发实践

    微信小程序Taro + React开发实践 微信小程序原生开发有一套自己的规范和写法,开发体验十分类似Vue,但如果你想减少学习成本,那么Taro框架是一个在此基础上又封装了一层的轮子,从社区热度到开 ...

  9. 微信小程序如何发布?发布流程怎么样

    现如今微信已经是每部手机必装的软件,微信小程序也已经应用到了各个行业生活中是非常广泛的.许多线下实体的店家都想制作微信小程序来进行线上购物模式,那么如何把一个微信小程序搭建起来呢?微信小程序软件代码的 ...

  10. 微信小程序 Notes | 开发常用事例(四)

    前言 那啥,关于小程序整理了几篇笔记,多多少少对个人而言有点作用,下面附上对应的文章链接: 微信小程序 | 开发常用事例(一) 微信小程序 | 开发常用事例(二) 微信小程序 Notes | 开发常用 ...

最新文章

  1. nginx php-fpm display_errors,php5-fpm的display_errors不能使用nginx
  2. 【Vegas原创】Oracle每日export的脚本(Windows版)
  3. Linux 中启用 Shell 脚本的调试模式
  4. queue:queue清空的方法?
  5. 【今晚7点半】:GVoice 千万在线语音传输的那些事
  6. 〔译〕TypeScript 2.0 候选版发布
  7. 挂起某线程命令 Linux,linux 线程挂起恢复的简单示例
  8. 在Completablefuture和Observable之间转换
  9. 民间75个不传之密 ,医院都不知道的秘密
  10. NAACL’21 | 来看如何让模型学会因为所以但是如果
  11. php函数(检查变量、函数、键是否存在)
  12. ArcGIS API For Javascript :如何动态生成 token 加载权限分配的地图服务?
  13. 前端安全 -- XSS攻击
  14. 动态图制作软件设计(三)
  15. html禁止页面动画,如何在页面加载时阻止CSS动画?
  16. VALSE学习(十六): Visual Question Generation and Answering-视觉问题生成和视觉问题
  17. 豆丁网文档免登陆免积分下载工具原理分析
  18. JSONP跨域以及CORS跨域
  19. 手把手教你快速入门知识图谱 - Neo4J教程
  20. HorizontalScrollView实现Gallery

热门文章

  1. 软件安全课程设计:高校科研管理系统
  2. C语言冒泡排序代码示例
  3. SAE SENT单边半字节传输协议里的CRC4与CRC6检验码编程
  4. 懒人分析jQuery源码
  5. 《算法导论》.pdf
  6. 信号检测与估计c语言,清华大学出版社-图书详情-《信号检测与估计(第2版)》...
  7. 轻松掌柜显示不能连接到服务器,轻松掌柜推出在线进销存云端版
  8. 大一计算机word排版试题,Word排版练习题
  9. 计算机组装课上机课干什么,多媒体技术与《计算机组装与维护》课的精彩结合:组装一台多媒体计算机需要哪些部件...
  10. TEncCu::xCheckRDCostMerge2Nx2N