使用微吼云JS SDK,只需简单几步,就能快速接入互动直播服务。

跟随本文的步骤,即使你对Javascript语言不熟悉,也完全可以做到。

其中,一、二步为准备工作,第三步为代码接入,下面,就分步来说明。

一.接入前准备

  1. 注册微吼开发者账号

  2. 创建应用 获取AppID

  3. 获取 互动房间ID: inavId

    可以通过 【测试工具】 或 【API】 获得

  4. 获取直播间包含看直播权限的access_token

    可以通过 【测试工具】 或 【API】 获得

时序图

注:虚线框部分请根据自身产品需求决定流程是否进行。

二.引入sdk文件

接下来,我们正式接入sdk: 将下面sdk引入代码,插入页面的head标签里。

<script type="text/javascript" src="https://static.vhallyun.com/jssdk/vhallILSSDK.js"></script>
<script src="https://static.vhallyun.com/jssdk/vhall-jssdk-interaction-1.0.0.js"></script>
<script src="https://static.vhallyun.com/jssdk/vhall-jssdk-base-1.0.0.js"></script>

注意:

  1. 直接用本地网页(file协议,地址栏以file:///开头)是调试不了的,需要运行在Server上(https或http协议,地址栏以https:// 或http:// 开头)才能正常调试。
  1. 上面两个文件都需要引用,而且顺序需要保持与上面一致。
  1. 建议直接复制上面代码

三.代码对接

至此,你已完成所有准备工作,距离完成,只差以下几步:

1.创建互动容器

在需要显示互动画面的位置,加入互动容器,也就是放一个div,然后给它取个名字,比如: my-interaction 。之后互动回显画面都会在这个容器里渲染,容器的大小控制您可以使用div的属性进行控制,示例代码如下:

  <div id="my-interaction"></div>

2.注册ready事件

接下来,在页面里写javascript代码,调用sdk提供的接口,注册sdk ready事件,接口调用方法如下:

/**
 * 注册ready事件
 */
Vhall.ready(function(){
    //to do
})

注意:所有文档相关逻辑需要写在此事件里。

3.初始化SDK配置

接下来需要传入相关参数,初始化配置:

 /**
  * 初始化配置
  */
 Vhall.config({
     appId :'',//应用 ID ,必填
     accountId :'',//第三方用户唯一标识,必填
     token:'',//token必填
 })     

4.初始化互动主持端

调用此方法后,主持端就能看到互动的画面了。

    /**
     * 初始化文档对象
     */
    var  interaction = new VhallInteraction({
        inavId:"", //互动房间id,必填
        videoNode:"my-interaction", //互动直播显示容器,必填
        //成功回调,非必填
        success: function(result){
          //TODO
        },
        //失败回调,非必填
        fail: function(reason){
          //TODO
        }
    });
    

5.初始化互动观众端

调用此方法后,观众端就能看到互动的画面了。

    /**
     * 初始化文档对象
     */
    var  interaction = new VhallInteractionGuest({
        inavId:"", //互动房间id,必填
        videoNode:"my-interaction", //互动直播显示容器,必填
        //成功回调,非必填
        success: function(result){
          //TODO
        },
        //失败回调,非必填
        fail: function(reason){
          //TODO
        }
    });
    

参数说明:

参数名称 参数说明 是否必填
inavId 互动房间id
videoNode 互动直播显示容器
success 初始化成功回调
fail 初始化失败回调

完整例子代码


<html>
  <head>
    <meta charset="UTF-8">
    <title>互动直播demo</title>
    <style>
      body{
        padding-top: 20px;
      }
      #enterDiv{
        width:520px;
        height:100px;
        margin:160px auto 20px auto;
      }
      .btn1{
        height:80px;
        width:250px;
        font-size:20px;
        font-family: 黑体,serif;
        position: relative;
      }
      #roomContainerTable td{
        padding: 1px 2px;
      }
      .streamdiv{
        width: 320px; height: 240px;float:left;padding-bottom:30px;
      }
      .stream_btn{
        position: absolute;
        bottom:0;
      }
      .online{
        background: greenyellow;
      }
      .offline{
        background: darkred;
      }
      select{
        margin-left: 6px;
      }
      label{
        line-height: 30px;
      }
      .inputs{
        width:100%;
        text-align: center;
      }
      .actions{
        width: 100%;
        text-align:center;
        clear: both;
        margin-top:20px;
      }
      input[type=button],button{
        min-width: 80px;
        height: 34px;
        padding: 7px 10px;
        border: 1px solid #d2d2d2;
        border-radius: 4px;
        outline: none;
      }
      button{
        min-width:50px;
        height: 22px;
        padding: 2px 4px;
      }
      input[type=text]{
        height: 34px;
        width: 128px;
        padding: 10px 8px;
        border: 1px solid #d2d2d2;
        border-radius: 4px;
        outline: none;
      }


      .confs-title{
        display: inline-block;
        text-align: right;
      }
      .confs-title .confs-title-item{
        height: 60px;
      }
      .confs-info{
        display: inline-block;
        width: 500px;
        margin-left: 10px;
      }
      .confs-info .confs-info-item{
        height: 60px;
      }
      .action-box{
        text-align: center;
      }
      .btn-small{
        width: 50px !important;
        height: 26px;
        padding: 2px 6px;
      }
      .btn-white,.btn-white:hover,.btn-white:visited,.btn-white:active{
        background-color: #fff;
        color:#666;
        border:1px solid #666;
        border-radius: 3px;
      }
      .settings{
        display: none;
        position: absolute;
        border: 1px solid #d2d2d2;
        padding-top: 40px;
        padding-left: 40px;
        padding-right: 40px;
        padding-bottom: 40px;
        text-align: center;
        width: auto;
        vertical-align: middle;
        margin-top: -432px;
        margin-left: 498px;
        background-color: #fff;
        border-radius: 5px;
      }
      .settings .confs-info{
        text-align: left;
        width: 200px;
      }
      .settings-action-btn{
        margin-top: 0px;
      }
      .settings-action-btn div{
        width: 30%;
        display: inline-block;
        text-align: center;
      }
      .settings-action-btn button{
          margin-top: 0px;
      }
      select{
        max-width: 180px;
        height: 34px;
        padding: 6px 12px;
      }
    </style>
  </head>

  <body>

    <div class="inputs">
      <input id="appId" type="text" name="appId" value="277ed4af" placeholder="这里填写appId">
      <input id="inavId" type="text" name="inavId" value="inav_8ff374db" placeholder="这里填写互动房间ID">
      <input onclick="init()" type="button"  value="开始互动">
    </div>
    <div id="my-interaction" style="width: 853px;height: 480px;margin: 0 auto;border: 1px solid #d2d2d2;margin-top:20px;">
    </div>
    <div style="margin-top: 10px;text-align: center;">
      <div id="settings" class="settings">
        
      </div>
      <button onclick="setSettings();">设置</button>
    </div>
    <div class="actions">
      <!-- <button onclick="leave();">申请上麦</button> -->
      <input type="button" value="下麦" onclick="leave();">
      <input type="button" value="上麦" onclick="join();">
      <input type="button" value="关闭声音" onclick="muteAudio(this);">
      <input type="button" value="关闭画面" onclick="muteVideo(this);">
      <input type="button" value="打开旁路直播" onclick="setBroadCast(true);">
      <input type="button" value="关闭旁路直播" onclick="setBroadCast(false);">
      <input type="button" value="退出房间" onclick="window.interaction.exit();">
    </div>
    <table style="width: 500px;margin: 0 auto;margin-top: 30px;">
      <thead>
        <tr>
          <td colspan="3" style="text-align: center;height: 50px;font-size: 20px;">用户列表</td>
        </tr>
        <tr>
          <td>用户Id</td>
          <td>状态</td>
          <td>操作</td>
        </tr>
      </thead>
      <tbody id="user-list">
      </tbody>
    </table>

    <table style="width: 500px;margin: 0 auto;margin-top: 30px;">
      <thead>
        <tr>
          <td colspan="3" style="text-align: center;height: 50px;font-size: 20px;">被踢用户列表</td>
        </tr>
        <tr>
          <td>用户Id</td>
          <td>状态</td>
          <td>操作</td>
        </tr>
      </thead>
      <tbody id="black-list">
      </tbody>
    </table>

  </body>
  <script type="text/javascript" src="//code.jquery.com/jquery-1.10.2.min.js"></script>
<script type="text/javascript" src="https://static.vhallyun.com/jssdk/vhallILSSDK.js"></script>
<script src="https://static.vhallyun.com/jssdk/vhall-jssdk-interaction-1.0.0.js"></script>
<script src="https://static.vhallyun.com/jssdk/vhall-jssdk-base-1.0.0.js"></script>
  <script type="text/javascript" src="http://res.layui.com/layui/release/layer/dist/layer.js?v=3111"></script>
  <script>

    var alert = function(msg){
      layer.msg(msg,{
        time:2000
      });
    }

    var users = [
    {userId:'100026',username:'张三'},
    {userId:'100027',username:'李四'},
    {userId:'100028',username:'王五'},
    {userId:'100029',username:'赵四'},
    {userId:'100030',username:'小沈阳'},
    {userId:'100031',username:'郭德纲'},
    {userId:'100032',username:'于谦'},
    {userId:'100033',username:'岳云鹏'},
    {userId:'100034',username:'孙悦'},
    {userId:'100035',username:'范伟'},
    {userId:'100036',username:'冯巩'},
    {userId:'100037',username:'潘长江'},
    ]

    var us = {
      100026:'张三',
      100027:'李四',
      100028:'王五',
      100029:'赵四',
      100030:'小沈阳',
      100031:'郭德纲',
      100032:'于谦',
      100033:'岳云鹏',
      100034:'孙悦',
      100035:'范伟',
      100036:'冯巩',
      100037:'潘长江',
      Master:'Master'
    }
  </script>
  <script type="text/javascript">
      window.interaction = {};
      //获取URL传参
      function getParameterByName(name) {
          name = name.replace(/[\[]/, '\\\[').replace(/[\]]/, '\\\]');
          var regex = new RegExp('[\\?&]' + name + '=([^&#]*)'),
              results = regex.exec(location.search);
          return results === null ? '' : decodeURIComponent(results[1].replace(/\+/g, ' '));
      }

      window.onload = function () {


      }

      function invite(userId){

        window.interaction.invite({
          userId: userId,
          consent: function(userId){
            // alert('恭喜你,你邀请'+ userId +'上麦, Ta答应啦!');
          },
          reject: function(userId){
            alert('非常遗憾,你邀请'+ userId +'上麦,被Ta拒绝了!');
          },
          fail: function(userId){
            alert('非常遗憾,你的邀请没有送达!');
          }
        });

      }

      //下麦
      function leave(){
        window.interaction.unpublish();
      }

      //上麦
      function join(){
        window.interaction.publish();
      }

      //踢出
      function delUser(userId){
        window.interaction.deleteUser({
          userId: userId,
          success:function(res){
            // alert('恭喜你,成功把'+ userId +'踢出!');
          },
          fail: function(reason){
            alert(reason);
          }
        });
      }

      //取消踢出(移除黑名单?)
      function unDeleteUser(userId){
        window.interaction.unDeleteUser({
          userId:userId,
          success: function(res){
            showBlackList();
          },
          fail: function(reason){

          }
        });
      }

      function statusMapping(v){
        var status = {
          '1':'推流中',
          '2':'观看中',
          '3':'受邀中',
          '4':'申请中',
          '5':'被踢出'
        }
        return status[v];
      }

      function switchButton(status,userId){
          var buttons = '';
          switch(status){
            case 1:
              buttons += '<button onclick="delUser(\''+ userId +'\');">踢出</button>'
            break;
            case 2:
              buttons += '<button onclick="invite(\''+userId +'\');">邀请</button>'
              buttons += '<button onclick="delUser(\''+ userId +'\');">踢出</button>'
            break;
            case 3:
               buttons += '<button onclick="delUser(\''+ userId +'\');">踢出</button>'
            break;

            case 4:
              buttons += '<button onclick="window.interaction.consentApply(\''+userId +'\');">批准</button>';
              buttons += '<button onclick="window.interaction.rejectApply(\''+userId +'\');">拒绝</button>';
            break;

            case 5:
              buttons += '<button onclick="window.interaction.unDeleteUser(\''+ userId +'\');">取消踢出</button>'
            break

            default:
          }
          return buttons;
      }

      function showUserList(){
        window.interaction.getUsersList({
          success: function(users){
              var sHTML = '';
              for(var i = 0; i < users.length; i++){
                sHTML += '<tr>\
                  <td>'+  users[i].third_party_user_id +'</td>\
                  <td>'+ statusMapping(users[i].status) +'</td>\
                  <td>'+ switchButton(users[i].status,users[i].third_party_user_id) +'</td>\
                </tr>';
              }
              $('#user-list').html(sHTML);
          },
          update: showUserList
        })
      }

      function showBlackList(){
        window.interaction.getBlackList({
          success: function(list){

            var sHTML = '';
            for(var i = 0; i < list.length; i++){
              sHTML += '<tr>\
                <td>'+  list[i] +'</td>\
                <td>被踢出</td>\
                <td><button onclick="unDeleteUser(\''+ list[i] +'\');">取消踢出</button></td>\
              </tr>';
            }
            $('#black-list').html(sHTML);

          },
          fail: function(reason){

          },
          update: showBlackList
        });
      }

      function setBroadCast(b){
          layer.prompt({title: '请输入直播房间ID',value:'lss_2de8530c', formType: 3}, function(roomId, index){
            if(roomId){
              if(b){
                window.interaction.startBroadCast(roomId);
              }else{
                window.interaction.stopBroadCast(roomId);
              }
            }
            layer.close(index);
          });
      }

      function init(){
        if(window.interaction.getStreamId && window.interaction.getStreamId()){
          alert('你已经在互动!');
          return
        }
        /**
         *  注册ready事件
         */
         Vhall.ready(function(){

           //TODO
           window.interaction = new VhallInteraction({
              inavId:$('#inavId').val(),
              videoNode:"my-interaction",
              conf:{
                resolution:'180'
              }
           });

           window.interaction.onEnter(function(userId){
              alert('用户[' + userId + ']进入房间');
           });

           window.interaction.onQuit(function(userId){
              alert('用户[' + userId + ']离开房间');
           });

           /**
            * 监听用户申请上麦事件,处理方式一,调对话框,把选择权给用户
            * @param  {object} event 回调事件参数,包含一个属性userId,和两个方法:consent 、 reject
            */
           window.interaction.onApply(function(event){
              layer.confirm('用户:[' + event.userId + ']申请上麦,同意吗?',{
                btn: ['同意','拒绝','忽略']
              },function(index){
                event.consent();
                layer.close(index);
              },function(){
                event.reject();
              });
           }); 

            //监听用户申请上麦事件,处理方式二, 直接上麦
           // window.interaction.onApply(function(event){
           //      event.consent();
           // });

           //显示用户列表
           showUserList();
           //显示黑名单列表(被踢出用户列表)
           showBlackList();
           
         });
         
        /**
         * 初始化SDK配置
         */
          Vhall.config({
            appId : $('#appId').val(),//应用 ID ,必填
            accountId :'Master',//第三方用户唯一标识,必填
            token:'vhall',//token必填
          });  
      }

      function muteAudio(obj){

        window.interaction.muteAudio();
        console.info(window.interaction.isAudioMuted());
        if(window.interaction.isAudioMuted()){
          obj.value = '打开声音';
        }else{
          obj.value = '关闭声音';
        }
        
      }

      function muteVideo(obj){
        window.interaction.muteVideo();
        console.info(window.interaction.isVideoMuted());
        if(window.interaction.isVideoMuted()){
          obj.value = '打开画面';
        }else{
          obj.value = '关闭画面';
        }
      }

      function start(){
        if(window.interaction){
          window.interaction.exit();
          setTimeout(function(){
             init();
           },3000);
         
        }
      }

      function setSettings(){

        window.interaction.getDevices(function(devices){
          var mics = devices.mics,
              cameras = devices.cameras;
              var html = '\
                      <div class="confs-title">\
                        <div class="confs-title-item">摄像头:</div>\
                        <div class="confs-title-item">麦克风:</div>\
                        <div class="confs-title-item">分辨率:</div>\
                        <div class="confs-title-item">帧率:</div>\
                      </div>\
                      <div class="confs-info">\
                        <div class="confs-info-item">\
                          <select class="form-control" id="camera"  >\
                            {{cameras}}\
                            <option value="">不使用摄像头</option>\
                          </select>\
                        </div>\
                        <div class="confs-info-item">\
                          <select class="form-control" id="mic"  >\
                            {{mics}}\
                            <option value="">不使用麦克风</option>\
                          </select>\
                        </div>\
                        <div class="confs-info-item">\
                          <select class="form-control" id="sizes"  >\
                            {{sizes}}\
                          </select>\
                        </div>\
                        <div class="confs-info-item">\
                          <select class="form-control" id="rates" >\
                            {{rates}}\
                          </select>\
                        </div>\
                      </div>\
                      <div class="settings-action-btn">\
                        <div><button id="btn-settings-ok" class="btn btn-primary btn-small">确定</button></div>\
                        <div><button id="btn-settings-cancel" class="btn-small btn-white">取消</button></div>\
                      </div>';

              var camerasOption = '', 
                  micsOption = '' ,
                  sizesOption = '',
                  ratesOption = '',
                  selected = '';
              var sizes = window.interaction.getVideoSize(),
                  rates =window.interaction.getVideoFrameRate();
              for(var i = 0; i < cameras.length; i++){
                if(i==0){
                  selected = 'selected="selected"';
                }
                camerasOption += '<option  value="'+ cameras[i].deviceId +'">'+ cameras[i].label +'</option>';
              }
              for(var j = 0; j < mics.length; j++){
                if(i==0){
                  selected = 'selected="selected"';
                }
                micsOption += '<option  value="'+ mics[j].deviceId +'">'+ mics[j].label +'</option>';
              }
              for(var x = 0; x < sizes.length; x++){
                if(i==0){
                  selected = 'selected="selected"';
                }
                sizesOption += '<option value="'+ JSON.stringify( sizes[x].size ) +'">'+ sizes[x].discription +'</option>';
              }
              for(var y = 0; y < rates.length; y++){
                if(i==0){
                  selected = 'selected="selected"';
                }
                ratesOption += '<option value="'+ JSON.stringify( rates[y].rate )+'">'+ rates[y].discription +'</option>';
              }
              html = html.replace(/{{cameras}}/g,camerasOption);
              html = html.replace(/{{mics}}/g,micsOption);
              html = html.replace(/{{sizes}}/g,sizesOption);
              html = html.replace(/{{rates}}/g,ratesOption);
              var isEmpty = $('#settings').html().trim().length == 0;
              if(isEmpty){
                 $('#settings').html(html);
              }
              $('#settings').show();
              $('#btn-settings-ok').off('click');
              $('#btn-settings-ok').on('click',function(){
                changeSettings();
                $('#settings').hide();
              });
              //设置按钮
              $('#btn-settings-cancel').off('click');
              $('#btn-settings-cancel').on('click',function(){
                $('#settings').hide();
              });

        });
      }


      function changeSettings(){
        var conf = window.interaction.getSetting();
        var v = $('#camera').val();
        var a = $('#mic').val();
        conf.video = v ? { deviceId: v } : false;
        conf.audio = a ? { deviceId: a } : false;
        conf.videoSize =  JSON.parse($('#sizes').val());
        conf.videoFrameRate =  JSON.parse($('#rates').val());
        console.dir(conf);
        window.interaction.changeSetting({
          conf:conf
        });
      }

  </script>
</html>

其他相关文档