Javascript Webrtc远程视频流不工作

Javascript Webrtc远程视频流不工作,javascript,stream,webrtc,spring-websocket,Javascript,Stream,Webrtc,Spring Websocket,设置remoteDescription时,我在firefox中遇到以下错误: DomeException[InvalidStateError:“无法在具有本地报价的状态下设置远程报价” 代码:11 nsresult:0x8053000b 地点: 请在下面找到我的test-online.js代码 var localVideo; var remoteVideo; var peerConnection; var serverConnection; var peerConnectionConfig =

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

DomeException[InvalidStateError:“无法在具有本地报价的状态下设置远程报价” 代码:11 nsresult:0x8053000b 地点:

请在下面找到我的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);
}
var本地视频;
远程视频;
var-peerConnection;
var服务器连接;
var peerConnectionConfig={'iceServers':[{'url':'stun:stun.services.mozilla.com'},{'url':'stun:stun.l.google.com:19302'};
pageReady();
var报价={
offerToReceiveAudio:1,
offerToReceiveVideo:1
};
var sdpConstraints={'mandatory':{
“OfferToReceiveAudio”:是,
“OfferToReceiveVideo”:true};
函数pageReady(){
localVideo=document.getElementById('localVideo');
remoteVideo=document.getElementById('remoteVideo');
localVideo.addEventListener('loadedmetadata',function(){
跟踪('本地视频宽度:'+此.videoWidth+
'px,videoHeight:'+this.videoHeight+'px');
});
remoteVideo.addEventListener('loadedmetadata',function(){
跟踪(“远程视频视频宽度:”+此.videoWidth+
'px,videoHeight:'+this.videoHeight+'px');
});
remoteVideo.onresize=函数(){
跟踪('远程视频大小更改为'+
remoteVideo.videoWidth+x'+remoteVideo.videoHeight);
//我们将使用第一个onsize回调作为视频已开始的指示
//比赛结束了。
如果(开始时间){
var elapsedTime=window.performance.now()-startTime;
跟踪('设置时间:'+elapsedTime.toFixed(3)+'ms');
startTime=null;
}
};
serverConnection=newsockjs(“/onlineHandler”);
serverConnection.onopen=函数(){
日志(“打开服务器连接”);
};
serverConnection.onmessage=gotMessageFromServer;
serverConnection.onclose=函数(){
日志(“关闭服务器连接”);
};
//serverConnection.onmessage=gotMessageFromServer;
变量约束={
视频:没错,
音频:是的,
};
navigator.mediaDevices.getUserMedia(约束)
。然后(getUserMediaSuccess)
.catch(函数(e){
警报('getUserMedia()错误:'+e.name);
});
}
函数getUserMediaSuccess(流){
跟踪(“接收到的本地流”);
localVideo.srcObject=流;
localStream=stream;
}
功能启动(isCaller){
跟踪(“起始呼叫”);
startTime=window.performance.now();
var videoTracks=localStream.getVideoTracks();
var audioTracks=localStream.getAudioTracks();
如果(videoTracks.length>0){
跟踪(“使用视频设备:”+视频跟踪[0]。标签);
}
如果(audioTracks.length>0){
跟踪(“使用音频设备:”+音频跟踪[0]。标签);
}
peerConnection=新的RTCPeerConnection(peerConnectionConfig);
peerConnection.onicecandidate=gotIceCandidate;
peerConnection.oniceconnectionstatechange=onIceStateChange;
peerConnection.onaddStream=gotmotestream;
peerConnection.addStream(localStream);
if(isCaller){
createOffer(gotDescription、errorHandler、offerOptions);
}
}
函数gotMessageFromServer(消息){
/*如果(!peerConnection)启动(false);
var signal=JSON.parse(message.data);
//log(“从服务器获取消息:“+Message.data”);
if(signal.sdp){;
console.log(“sdp中的hi”+message.data);
setRemoteDescription(新的RTCSessionDescription(signal.sdp),函数(){
log(“创建答案:”);
if(peerConnection.remoteDescription.type=='offer')
createAnswer(gotDescription,errorHandler);
},errorHandler);
}else if(signal.ice){
peerConnection.addIceCandidate(新的RTCICE候选者(signal.ice));
}*/
var signal=JSON.parse(message.data);
如果(signal.type==‘offer’){
setRemoteDescription(新的RTCSessionDescription(信号)、doAnswer、errorHandler);
}else if(signal.type==='answer'){
peerConnection.setRemoteDescription(新的RTCSessionDescription(信号)、doNothing、errorHandler);
}else if(signal.type==='candidate'){
var候选者=新的候选者({
sdpMLineIndex:signal.label,
候选人:信号,候选人
});
peerConnection.addIceCandidate(候选);
}else if(信号==='bye'&&isStarted){
handleRemoteHangup();
}
}
函数doNothing(){
}
函数doAnswer(){
log('向对等方发送应答');
createAnswer(gotDescription、errorHandler、sdpConstraints);
}
函数handleRemoteHangup(){
//log('会话已终止');
//停止();
//isInitiator=false;
}
函数(事件){
if(event.candidate!=null){
var消息={
键入:“候选人”,
标签:event.candidate.sdpMLineIndex,
id:event.candidate.sdpMid,
候选:event.candidate.candidate};
//send(JSON.stringify({'ice':event.candidate}));
send(JSON.stringify(message));
}
}
功能更改(事件){
if(对等连接){
跟踪('ICE状态:'+peerConnection.iceConnectionState);
日志('ICE状态更改事件:',事件);
}
}
功能描述(描述){
//跟踪('来自peerConnection的报价\n'+description.sdp);
description.sdp=preferOpus(description.sdp);
//pc.setLocalDescription(描述);
log('setLocalAndSendMessage发送消息',说明);
//跟踪(“peerConnection setLocalDescription开始”);
peerConnection.setLocalDescription(
描述
函数(){
    <%@ 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>