h5端如何使用webrtc

1.无意中接触到webrtc,了解到的就是直播过程中延迟很短,控制在1-2s左右,开发过程中发现关于webrtc的参考案例很少,就把demo贴出来,也顺便把遇到的问题和如何解决的也贴出来。

<!DOCTYPE html>
<html>
<head>
  <title>CDN Demo</title>
  <meta charset="utf-8">
  <meta content="width=device-width, initial-scale=1" name="viewport">
  <link href='https://cloud.webrtc.qq.com/httpdemo/css/bootstrap.css' rel="stylesheet">
  <link href='https://cloud.webrtc.qq.com/httpdemo/css/style.css' rel='stylesheet'>
  <style>
      #remote-video-wrap div{max-width:800px; display: inline-block; padding:10px;}
      #remote-video-wrap video{max-width:800px; display: inline-block; padding:10px} 
  </style>
</head>
<body>
    <div id="input-container" class="container">
    
        <div class="login-box">
          <div class="form-group">
              <label for="streamurl">拉流地址:</label>
              <input class="form-control" id="streamurl" type="text" value="webrtc://xxxxxx" /> //webrtc类型的流地址
          </div>
          <button  style="float: left;margin:10px;" type="button" onclick="pullStream()" id="pullFun">拉流</button>
          <button  style="float: left;margin:10px;" type="button" onclick="stopStream()">停止拉流</button>
          <!-- <button  style="float: left;margin:10px;" type="button" onclick="refreshStream()">刷新</button>
          <button  style="float: left;margin:10px;" type="button" onclick="opennewpage()">打开新的页面</button> -->
          <!-- <a href="https://local.rtc.qq.com/live/" target="_top">打开新的页面</a> -->
        </div>
      </div>
    

    <div id="video-section" style="float:left;margin:195px 0px 0px 75px;">
            <div id="remote-video-wrap">
    
            </div>
        </div>
      </div>

      <script>
        window._tx_webrtc_enable  = true;
        // delete window.RTCPeerConnection;
        // delete window.webkitRTCPeerConnection;
        // delete window.RTCIceGatherer;
      </script>

  <script src="https://unpkg.com/flyio/dist/fly.min.js"></script>
  <script src="https://cloud.webrtc.qq.com/httpdemo/js/jquery.min.js"></script>
  <script src="https://cloud.webrtc.qq.com/httpdemo/js/adapter.js"></script>  //很有必要 兼容浏览器
  <script src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>  //用于ios端视频不能自动播放
  <script>
      
function getStreamId(url){
    //var url = "webrtc://domain/path/stream_id[?txSecret=xxx&txTime=xxx]";
    var parseStreamid = /^(?:webrtc:\/\/)(?:[0-9.\-A-Za-z_]+)(?:\/)(?:[0-9.\-A-Za-z_]+)(?:\/)([^?#]*)(?:\?*)(?:[^?#]*)/;
    var result = parseStreamid.exec(url);
    if(result)
        return result[1];
    return null;
}

function createVideoElement(id) {
    var videoDiv = document.createElement("div");
    videoDiv.innerHTML = `<video id="${id}" autoplay unmuted playsinline controls></video>`; //width="480" height="320"
    document.querySelector("#remote-video-wrap").appendChild(videoDiv);
    
    return document.getElementById(id);
}

function onAddStream(e){
    console.log(`onAddStream, streamId:${e.streamId}`, e.stream);
    var streamId = e.streamId;
    var video = document.getElementById(streamId);
    if(!video){
        video = createVideoElement(streamId);
    }

    video.srcObject = e.stream;
    //video.muted = true
    video.autoplay = true
    video.playsinline = true
    var playPromise = video.play();
    if(playPromise){
        playPromise.then(() => {
            //此处监听到webrtc流地址可以播放 
            console.log(`play ok!`);
        }).catch(() => {
            //此处可做其他类型的流地址切换
            //webrtc地址不可播放
            console.log(`play failed!`);
        });
    }
}

var streamUrl;
var svrSig;
var peerConnection;

function pullStream(){

    var clientInfo = "clientinfo_test";
    var sessionId = "sessionId_Test";
    streamUrl = $("#streamurl").val();
    var streamId = getStreamId(streamUrl);
    var video = document.getElementById(streamId);
    if(!video){
        video = createVideoElement(streamId);
    }

    var config = {
        iceServers: [],
        bundlePolicy: "max-bundle",
        rtcpMuxPolicy: "require",
        tcpCandidatePolicy: "disable",
        IceTransportsType: "nohost",
        sdpSemantics: 'unified-plan'
    };

    var optional = {
        optional: [{
            DtlsSrtpKeyAgreement: true
        }]
    };

    var offerSdpOption = {
        offerToReceiveAudio: true,
        offerToReceiveVideo: true,
        voiceActivityDetection: false
      };

    peerConnection = new RTCPeerConnection(config, optional);
    peerConnection.onicecandidate = function(e) {
        console.log("peerConnection.onicecandidate:", e);
    };
    peerConnection.onaddstream = function(e) {
        console.log("peerConnection.onaddstream");
    };
    peerConnection.onremovestream = function(e) {
        console.log("peerConnection.onremovestream");
    };
    peerConnection.ontrack = function(e) {
        console.log("peerConnection.ontrack, kind:" + e.track.kind + ",track.id:" + e.track.id);

        var track = e.track;
        if(!peerConnection.stream){
            peerConnection.streamId = streamId;
            peerConnection.stream = new MediaStream();
            peerConnection.stream.addTrack(track);

            onAddStream(peerConnection);
        } else{
            peerConnection.stream.addTrack(track);
            console.log("track.lenght:" + peerConnection.stream.getTracks().length);
        }
    };
    peerConnection.onconnectionstatechange = function(e) {
        console.log("onconnectionstatechange", e);
    }
    peerConnection.oniceconnectionstatechange = function(e) {
        console.log("peerConnection.oniceconnectionstatechange: " + JSON.stringify(e), e);
    };
    peerConnection.onicegatheringstatechange = function(e) {
        console.log("peerConnection.onicegatheringstatechange : " + e.target.iceGatheringState, e);
    };
    peerConnection.onsignalingstatechange = function(e) {
        console.log("peerConnection.onsignalingstatechange : " + peerConnection.signalingState, e);
    };
    peerConnection.onnegotiationneeded = function(e) {
        console.log("peerConnection.onnegotiationneeded", e);
    };


    peerConnection.createOffer(offerSdpOption).then(function(offer) {
        peerConnection.setLocalDescription(offer);
        var url = "https://webrtc.liveplay.myqcloud.com/webrtc/v1/pullstream"; 
        var reqBody = {
            streamurl: streamUrl,
            sessionid:  sessionId,
            clientinfo: clientInfo,
            localsdp: offer
        };

         $.ajax({
             type: "post",
             url: url,
             data: JSON.stringify(reqBody),
             //contentType: "application/json; charset=utf-8",
             dataType: "json",
             success: pullStreamRes,
             crossDomain: true
         });
        //fly.interceptors.request.use((request) => {
         //   request.headers['Content-Type'] ='application/json';
         //   request.headers['Access-Control-Allow-Origin'] ='*';
         //   request.headers['Access-Control-Allow-Credentials'] ='true';
        //})
        //fly.post(url, JSON.stringify(reqBody)).then(pullStreamRes).catch(function(error){
         //   console.log("fly post err:", error);
        //});

        function pullStreamRes(data){
            console.log("pullStreamRes:", data);
        //    data = data.data;
            var errCode = data.errcode;
            var errMsg = data.errmsg;
            if(errCode != 0){
                console.log(`pull stream failed!errCode:${errCode}, errmsg:${errMsg}`);
                return;
            }

            var remoteSdp = data.remotesdp;
            svrSig = data.svrsig;

            console.log(`svrSig:${svrSig}`);

            peerConnection.setRemoteDescription(
                new RTCSessionDescription(remoteSdp),
                function(){
                    console.log("setRemoteSdp succ!");
                },
                function(e){
                    console.log("setRemoteSdp failed, exception = " + e.message);
                }
            );
        }
    }).catch(function(reason) {
        console.log('create offer failed : reason = ' + reason);
      });
}


function stopStream(){
    var url = "https://webrtc.liveplay.myqcloud.com/webrtc/v1/stopstream";
    var reqBody = {
        streamurl: streamUrl,
        svrsig:  svrSig
    };

     $.ajax({
         type: "post",
         url: url,
         data: JSON.stringify(reqBody),
         //contentType: "application/json; charset=utf-8",
         dataType: "json",
         success: stopStreamRes,
        crossDomain: true
     });

    //fly.interceptors.request.use((request) => {
    //    request.headers['Content-Type'] ='application/json';
    //    request.headers['Access-Control-Allow-Origin'] ='*';
    //    request.headers['Access-Control-Allow-Credentials'] ='true';
    //})
   // fly.post(url, JSON.stringify(reqBody)).then(stopStreamRes).catch(function(error){
    //    console.log("fly post err:", error);
    //});

    function stopStreamRes(data){
        console.log(`stopStreamRes:`, data);
        //data = data.data;
        var errCode = data.errcode;
        var errMsg = data.errmsg;
        if(errCode != 0){
            console.log(`pull stream failed!errCode:${errCode}, errmsg:${errMsg}`);
        }

        peerConnection.close();
        var streamId = getStreamId(streamUrl);
        var videoNode = document.getElementById(streamId);
        if (videoNode) {
            document.getElementById(streamId).parentElement.removeChild(videoNode);
            console.log(`RemoveStream, streamUrl:${streamUrl}`);
        } else{
            console.log(`RemoveStream, streamUrl:${streamUrl} not exist`);
        }
    }
    
}

//此处用来调取微信console面板  用于开发审查(很有必要)
function createVConsole() {
    var scriptEle = document.createElement("script");
    scriptEle.src = '//sqimg.qq.com/expert_qq/vConsole/vconsole.min.js';
    document.body.appendChild(scriptEle)
    scriptEle.onload = function(){
        window.vConsole = new VConsole();
    }
};

createVConsole();

//此处作用:因ios端视频禁止自动播放  故写此代码用来调取视频播放
let video = document.querySelectorAll("video")[0];
  document.addEventListener("WeixinJSBridgeReady", function () {
    pullStream();  //拉流(相当于手动操作拉流按钮,因实际项目中没有此按钮来手动拉流)
     video.play();
}, false);
  </script>
  </body>
</html>

2.遇到的问题
2.1 问题:ios微信浏览器播放器不能自动播放 导致stream监听事件提示play failed,因业务中需区分webrtc能不能播放,不能播放则切换至其他流地址进行播放
解决方案:引入jweixin-1.0.0.js 监听WeixinJSBridgeReady触发事件即可(参考网络案例,还有其他方式,此处只提供一种,如不能解决,欢迎留言。)
2.2 ios微信浏览器一开始不能播放webrtc,但是在微信开发者工具则正常播放
解决方案:引入adapter.js即可解决浏览器兼容性问题

上一篇:vue中 $event 的用法--获取当前父元素,子元素,兄弟元素


下一篇:NMEA报文解析程序(c语言)- 数据包判断