Webrtc远程视频流无法正常工作 [英] Webrtc Remote video stream not working

查看:1103
本文介绍了Webrtc远程视频流无法正常工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在设置remoteDescription时,我在firefox中遇到以下错误:

While setting the remoteDescription , I am getting below error in firefox :

DOMException [InvalidStateError:无法在状态has-local-offer中设置远程商品
代码:11
nsresult:0x8053000b
位置: http:// localhost:8080 / resources / assets / js / test-online.js:111]

DOMException [InvalidStateError: "Cannot set remote offer in state have-local-offer" code: 11 nsresult: 0x8053000b location: http://localhost:8080/resources/assets/js/test-online.js:111]

请在下面找到我的test-online.js代码

var localVideo;
var remoteVideo;
var peerConnection;
var serverConnection;
var peerConnectionConfig = {'iceServers': [{'url': 'stun:stun.services.mozilla.com'}, {'url': 'stun:stun.l.google.com:19302'}]};
pageReady();
var offerOptions = {
          offerToReceiveAudio: 1,
          offerToReceiveVideo: 1
        };

var sdpConstraints = {'mandatory': {
      'OfferToReceiveAudio':true,
      'OfferToReceiveVideo':true }};

function pageReady() {
    localVideo = document.getElementById('localVideo');
    remoteVideo = document.getElementById('remoteVideo');

    localVideo.addEventListener('loadedmetadata', function() {
          trace('Local video videoWidth: ' + this.videoWidth +
            'px,  videoHeight: ' + this.videoHeight + 'px');
    });

    remoteVideo.addEventListener('loadedmetadata', function() {
          trace('Remote video videoWidth: ' + this.videoWidth +
            'px,  videoHeight: ' + this.videoHeight + 'px');
    });

    remoteVideo.onresize = function() {
          trace('Remote video size changed to ' +
            remoteVideo.videoWidth + 'x' + remoteVideo.videoHeight);
          // We'll use the first onsize callback as an indication that video has started
          // playing out.
          if (startTime) {
            var elapsedTime = window.performance.now() - startTime;
            trace('Setup time: ' + elapsedTime.toFixed(3) + 'ms');
            startTime = null;
          }
    };

    serverConnection = new SockJS("/onlineHandler");

    serverConnection.onopen = function() {
        console.log("Opening server connection");
     };
     serverConnection.onmessage = gotMessageFromServer;
     serverConnection.onclose = function() {
         console.log("Closing server connection");
     };
   //serverConnection.onmessage = gotMessageFromServer;

    var constraints = {
        video: true,
        audio: true,
    };

    navigator.mediaDevices.getUserMedia(constraints)
      .then(getUserMediaSuccess)
      .catch(function(e) {
        alert('getUserMedia() error: ' + e.name);
      });
}

function getUserMediaSuccess(stream) {
      trace('Received local stream');
      localVideo.srcObject = stream;
      localStream = stream;
}

function start(isCaller) {
    trace('Starting call');
      startTime = window.performance.now();
      var videoTracks = localStream.getVideoTracks();
      var audioTracks = localStream.getAudioTracks();
      if (videoTracks.length > 0) {
        trace('Using video device: ' + videoTracks[0].label);
      }
      if (audioTracks.length > 0) {
        trace('Using audio device: ' + audioTracks[0].label);
      }

    peerConnection = new RTCPeerConnection(peerConnectionConfig);
    peerConnection.onicecandidate = gotIceCandidate;
    peerConnection.oniceconnectionstatechange = onIceStateChange;
    peerConnection.onaddStream = gotRemoteStream;
    peerConnection.addStream(localStream);

    if(isCaller) {
        peerConnection.createOffer(gotDescription, errorHandler , offerOptions);
    }
}

function gotMessageFromServer(message) {
   /* if(!peerConnection) start(false);

    var signal = JSON.parse(message.data);
//    console.log("Got Message from server :" + message.data);
    if(signal.sdp) {;
        console.log("hi in sdp" + message.data);
        peerConnection.setRemoteDescription(new RTCSessionDescription(signal.sdp), function() {
            console.log("Creating answer :");
        if (peerConnection.remoteDescription.type == 'offer')
            peerConnection.createAnswer(gotDescription, errorHandler);
        }, errorHandler);
    } else if(signal.ice) {
        peerConnection.addIceCandidate(new RTCIceCandidate(signal.ice));
    }*/
    var signal = JSON.parse(message.data);
    if (signal.type === 'offer') {
        peerConnection.setRemoteDescription(new RTCSessionDescription(signal),doAnswer,errorHandler);
      } else if (signal.type === 'answer') {
          peerConnection.setRemoteDescription(new RTCSessionDescription(signal),doNothing, errorHandler);
      } else if (signal.type === 'candidate') {
        var candidate = new RTCIceCandidate({
          sdpMLineIndex:signal.label,
          candidate: signal.candidate
        });
        peerConnection.addIceCandidate(candidate);
      } else if (signal === 'bye' && isStarted) {
        handleRemoteHangup();
      }
}
function doNothing(){

}

function doAnswer() {
      console.log('Sending answer to peer.');
      peerConnection.createAnswer(gotDescription, errorHandler, sdpConstraints);
    }

function handleRemoteHangup() {
//  console.log('Session terminated.');
  // stop();
  // isInitiator = false;
}

function gotIceCandidate(event) {
    if(event.candidate != null) {

        var message ={
                  type: 'candidate',
                  label: event.candidate.sdpMLineIndex,
                  id: event.candidate.sdpMid,
                  candidate: event.candidate.candidate};

       // serverConnection.send(JSON.stringify({'ice': event.candidate}));
         serverConnection.send(JSON.stringify(message));
    }
}

function onIceStateChange(event) {
      if (peerConnection) {
        trace(' ICE state: ' + peerConnection.iceConnectionState);
        console.log('ICE state change event: ', event);
      }
    }

function gotDescription(description) {
   // trace('Offer from peerConnection\n' + description.sdp);
      description.sdp = preferOpus(description.sdp);
     // pc.setLocalDescription(description);
      console.log('setLocalAndSendMessage sending message' , description);
   // trace('peerConnection setLocalDescription start');
    peerConnection.setLocalDescription(
            description, 
            function () {
                serverConnection.send(JSON.stringify(description));
            }, 
            onSetSessionDescriptionError
    );
}

function preferOpus(sdp) {
      var sdpLines = sdp.split('\r\n');
      var mLineIndex;
      // Search for m line.
      for (var i = 0; i < sdpLines.length; i++) {
          if (sdpLines[i].search('m=audio') !== -1) {
            mLineIndex = i;
            break;
          }
      }
      if (mLineIndex === null) {
        return sdp;
      }

      // If Opus is available, set it as the default in m line.
      for (i = 0; i < sdpLines.length; i++) {
        if (sdpLines[i].search('opus/48000') !== -1) {
          var opusPayload = extractSdp(sdpLines[i], /:(\d+) opus\/48000/i);
          if (opusPayload) {
            sdpLines[mLineIndex] = setDefaultCodec(sdpLines[mLineIndex], opusPayload);
          }
          break;
        }
      }

      // Remove CN in m line and sdp.
      sdpLines = removeCN(sdpLines, mLineIndex);

      sdp = sdpLines.join('\r\n');
      return sdp;
    }

    function extractSdp(sdpLine, pattern) {
      var result = sdpLine.match(pattern);
      return result && result.length === 2 ? result[1] : null;
    }

    // Set the selected codec to the first in m line.
    function setDefaultCodec(mLine, payload) {
      var elements = mLine.split(' ');
      var newLine = [];
      var index = 0;
      for (var i = 0; i < elements.length; i++) {
        if (index === 3) { // Format of media starts from the fourth.
          newLine[index++] = payload; // Put target payload to the first.
        }
        if (elements[i] !== payload) {
          newLine[index++] = elements[i];
        }
      }
      return newLine.join(' ');
    }

    // Strip CN from sdp before CN constraints is ready.
    function removeCN(sdpLines, mLineIndex) {
      var mLineElements = sdpLines[mLineIndex].split(' ');
      // Scan from end for the convenience of removing an item.
      for (var i = sdpLines.length-1; i >= 0; i--) {
        var payload = extractSdp(sdpLines[i], /a=rtpmap:(\d+) CN\/\d+/i);
        if (payload) {
          var cnPos = mLineElements.indexOf(payload);
          if (cnPos !== -1) {
            // Remove CN payload from m line.
            mLineElements.splice(cnPos, 1);
          }
          // Remove CN line in sdp
          sdpLines.splice(i, 1);
        }
      }

      sdpLines[mLineIndex] = mLineElements.join(' ');
      return sdpLines;
    }


function onSetSessionDescriptionError(error) {
  trace('Failed to set session description: ' + error.toString());
}

function gotRemoteStream(event) {
     remoteVideo.srcObject = event.stream;
     trace('Received remote stream');
}

function errorHandler(error) {
    console.log(error);
}

我的html代码如下:

    <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
    <%@ taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<html lang="en">
<head>
<link
    href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css"
    rel="stylesheet">
    <!-- Meta tag to not followed by search engine. -->
    <meta name="robots" content="noindex,nofollow,nosnippet,noodp,noarchive">
    <meta name="keywords" content="JavaScript, WebRTC" />
    <meta name="description" content="WebRTC codelab" />
    <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1">

    <style>
        video {
            filter: hue-rotate(180deg) saturate(200%);
            -moz-filter:  hue-rotate(180deg) saturate(200%);
            -webkit-filter: hue-rotate(180deg) saturate(200%); 
            /*-webkit-filter: grayscale(0.3) hue-rotate(360deg) saturate(10) opacity(0.7) sepia(0.5); */
        }
    </style>
</head>
<body>


    <div id='videos'>
                <video id='localVideo' autoplay muted></video>
                <video id='remoteVideo' autoplay></video>
            </div>

       <input type="button" id="start" onclick="start(true)" value="Start Video"></input>
    <script src="//cdn.jsdelivr.net/sockjs/1.0.0/sockjs.min.js"></script>
     <script
        src="${pageContext.request.contextPath}/resources/assets/js/jquery-2.1.1.min.js"></script>
     <script
        src="${pageContext.request.contextPath}/resources/assets/js/bootstrap.min.js"></script>
     <script src ="${pageContext.request.contextPath}/resources/assets/js/adapter-0.2.10.js"></script>
     <script src="${pageContext.request.contextPath}/resources/assets/js/test-online.js"></script>
</body>
</html>

我无法理解我在这里做错了什么。我仍然是webrtc领域的新手juts想在我的代码中运行这个基本的东西。

I am not able to understand what I am doing wrong here.I am still a novice in webrtc field juts want to run this basic thing in my code.

推荐答案

offer-answer交换是状态机,有些方法是在某些州禁止使用。

The offer-answer exchange is a state machine, and some methods are disallowed in certain states.

调用 setLocalDescription (或 setRemoteDescription )将信令状态更改为have-local-offer(或have-remote-offer) 。

Calling setLocalDescription (or setRemoteDescription) changes the signaling state to "have-local-offer" (or "have-remote-offer").

此时,应用程序的工作是将状态恢复为 stable 关闭,如在规范中描述

At that point, it is the application's job to bring the state back to stable or closed, as described in the spec.

例如,应用程序负责处理眩光(这是双方同时发送报价的地方)。

For instance, it is the application's responsibility to handle glare (which is where both sides send an offer at the same time).

还有 bu在Firefox中,它不允许您在<$中再次调用 createOffer setLocalDescription c $ c> have-local-offer ,反之亦然(上面链接的规范中的状态图中的小箍)。但是你的错误消息听起来并不像你那样。

There is also a bug in Firefox that it doesn't allow you to call createOffer or setLocalDescription again once in have-local-offer and vice versa for the answer (the little hoops in the state diagram in the spec linked above). But it doesn't sound from your error message like you're hitting that.

这篇关于Webrtc远程视频流无法正常工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆