微信小程序视频直播开发实现流程[亲测有效] -金沙1005

微信小程序视频直播开发实现流程[亲测有效]微信小程序开发需要基于微信提供的开发者工具与sdk。如果开发者对小程序开发流程不熟悉,建议先系统学习:微信小程序开发官方文档。由于微信官方文档比较详细,本文对小程序开发流程中的框架说明、api调用、组件使用等,不再赘述,而是重点介绍如何使用zegosdk开发出支持音视频直播的微信小程序。sdk集成指引详见:微信小程序sdk集成指引sdk提供的api说明详见:微信小程序s…

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

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

sdk 集成指引详见:

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

    {
  
  {item.streamid}}

微信小程序视频直播开发实现流程[亲测有效]

为防止网络爬虫,请关注公众号回复”口令”

激活idea 激活clion
datagrip dataspell
dotcover dotmemory
dottrace goland
phpstorm pycharm
resharper reshac
rider rubymine
webstorm 全家桶

请注意:

  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

    {
  
  {ispublishing ? "我("   publishstreamid   ")": ""}}

请注意:

  • 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(数字越大,日志越少),建议选择 1
  server: 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.js
zg.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 对应的拉流 url
    var 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 的源不存在,创建新 player
    if (!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 = {};
  //混流输出流id
  mixconfig.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 = 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 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 block
            e.printstacktrace();
        }
        return "";
    }
}

5、状态码

5.1 推流状态码

onpublishstateupdate statecode 含义如下:
在这里插入图片描述
其他 4 位错误码均为小程序框架的报错,请参考:小程序官方文档

5.2 拉流状态码

onplaystateupdate statecode 含义如下:
在这里插入图片描述
其他 4 位错误码均为小程序框架的报错,请参考:小程序官方文档

6、常见错误

6.1 登录房间时,控制台输出返回 zegoclient.error.timeout

金沙1005的解决方案: 请检查 初始化配置 zegoclient.config 里面每个参数的类型是否正确,一般情况下都是类型不正确引起的问题。
在这里插入图片描述
6.2 登录房间时,控制台输出返回 result=1000001002

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

金沙1005的解决方案:

1)在 zegoclient.config 里面的 option.audiencecreateroom 设置为 true

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

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

原因:计算 token 的时候,算法不对引起,可通过这个链接: 来验证是否正确:

  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 分配给开发者的 ,需要在微信公众平台进行“合法域名”配置后,小程序才能正常访问。

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

请开发者将 zego 分配的请求域名,按照协议分类,填到指定的 request合法域名 或者 socket合法域名 中。例如:
在这里插入图片描述

js555888金沙老品牌的版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由思创斯整理,转载请注明出处:https://ispacesoft.com/131505.html

(0)

相关推荐

  • 微信小程序实现返回顶部怎么设置_微信签到小程序两种方法一,使用view形式的回到顶部htmlcssdata:{floorstatus:false},/*返回顶部*/.gotop{height:80rpx;width:80rpx;position:fixed;

  • 微信小程序实现视频试看功能[通俗易懂]我的思路是在页面上那个video元素上面绑定bindtimeupdate事件然后监控视频的实时播放进度,到达一定的播放时间后进行暂停处理,并把自己实现写好的<cover-view></cover-view>放上去,等待用户拉起微信支付成功后在success里面在把写好的<cover-view></cover-view>去掉,继…

  • 微信小程序tabbar在顶部微信小程序tabbar在顶部

    2022年12月25日
  • 小程序webview跳转外部域名_微信小程序只能请求https安全域名需登陆测试号管理页面来配置,具体的https证书要求请参照官方文档去制作并配置好。小程序默认请求是443端口,如果需指定端口号,域名后直接跟端口号即可,如图:js里面url写法如下即可: …

    2022年10月13日
  • 微信小程序图片上传和裁剪本篇博客用于解决微信小程序图片裁剪问题图片裁剪常用于头像选择和图片合成等。图片裁剪金沙1005的解决方案:  目前网络上知名的微信小程序图片裁剪插件是we-cropper(文末有链接)  操作步骤:下载好we-cropper文件夹,拷贝到小程序目录,可以放在pages列表中。  第一步:wxml中引入插件的wxml,使用模板,编写按钮绑定事件。  第二步,js中引入插件的js,设置参数,初始化对象。  请看下方操作:  wxml中:

    2022年11月19日
  • 微信小程序下拉刷新函数_微信小程序下拉刷新组件代码片段:/***页面相关事件处理函数–监听用户下拉动作*/onpulldownrefresh:function(){console.log(1111);//在当前页面显示导航条加载动画wx.shownavigationbarloading();//显示loading提示框。需主动调用wx.hideloading才能关闭提示框wx.showloading({tit.

    2022年12月13日
  • laravel8 微信小程序生成二维码[通俗易懂]首先生成access_tokenpublicfunctiongetaccesstoken(){$url=”https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=”.self::appid.”&secret=”.self::secret;$res=(newc)->get;

  • 微信小程序生成二维码功能_个人怎么做微信小程序微信官方文档:https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/qr-code.html本工具采用接口a。1.httputil工具publicclasshttputil{privatestaticloggerlogger=loggerfactory.getlogg…

发表回复

您的电子邮箱地址不会被公开。

联系金沙1005

关注“java架构师必看”公众号

回复4,添加站长微信。

附言:ispacesoft.com网而来。

关注微信
网站地图