无法在“ RTCPeerConnection”上执行“ setLocalDescription”

时间:2018-11-18 10:05:12

标签: javascript socket.io webrtc

我已经有一段时间enter image description here这个错误了

一直试图使用异步来等待本地描述更新,但是由于我的代码现在如何工作,它无法将其集成,而且我还听说socket.on已经实现了异步本身。

我还尝试过在vs代码中使用断点来调试效果不佳的代码。

如果有人知道解决方法,将不胜感激。 代码附在下面

'use strict';

var localStream;
var remoteStream;
var isInitiator;
var configuration = {
  iceServers: [
    {
      urls: 'stun:stun.l.google.com:19302'
    }
  ]
};
var pc = new RTCPeerConnection(configuration);

// Define action buttons.
const callButton = document.getElementById('callButton');
const hangupButton = document.getElementById('hangupButton');

/////////////////////////////////////////////

window.room = prompt('Enter room name:');

var socket = io.connect();

if (room !== '') {
  console.log('Message from client: Asking to join room ' + room);
  socket.emit('create or join', room);
}

socket.on('created', function(room) {
  console.log('Created room ' + room);
  isInitiator = true;
  startVideo();
});

socket.on('joined', function(room) {
  console.log('joined: ' + room);
  startVideo();
});

socket.on('log', function(array) {
  console.log.apply(console, array);
});

////////////////////////////////////////////////

function sendMessage(message) {
  socket.emit('message', message);
}

// This client receives a message
socket.on('message', function(message) {
  try {
    if (message.type === 'offer') {
      pc.setRemoteDescription(new RTCSessionDescription(message));
      // const stream = navigator.mediaDevices.getUserMedia({
      //   audio: true,
      //   video: true
      // });
      // stream.getTracks().forEach(track => pc.addTrack(track, localStream));
      pc.setLocalDescription(
        pc.createAnswer(setLocalAndSendMessage, function(err) {
          console
            .log(err.name + ': ' + err.message)
            .then(pc.setLocalDescription);
        })
      );
    } else if (message.type === 'answer') {
      console.log('This is to check if answer was returned');
      pc.setRemoteDescription(new RTCSessionDescription(message));
    } else if (message.type === 'candidate') {
      pc.addIceCandidate(candidate);
    }
  } catch (err) {
    console.error(err);
  }
});

////////////////////////////////////////////////////

const localVideo = document.querySelector('#localVideo');
const remoteVideo = document.querySelector('#remoteVideo');

// Set up initial action buttons status: disable call and hangup.
callButton.disabled = true;
hangupButton.disabled = true;

// Add click event handlers for buttons.
callButton.addEventListener('click', callStart);
hangupButton.addEventListener('click', hangupCall);

function startVideo() {
  navigator.mediaDevices
    .getUserMedia({
      audio: true,
      video: true
    })
    .then(function(mediaStream) {
      localStream = mediaStream;
      localVideo.srcObject = mediaStream;
    })
    .catch(function(err) {
      console.log('getUserMedia() error: ' + err.name);
    });
  callButton.disabled = false;
}

function callStart() {
  createPeerConnection();
  //pc.addTrack(mediaStream);
  //stream.getTracks().forEach(track => pc.addTrack(track, localStream));
  callButton.disabled = true;
  hangupButton.disabled = false;
  if (isInitiator) {
    console.log('Sending offer to peer');
    pc.createOffer(setLocalAndSendMessage, function(err) {
      console.log(err.name + ': ' + err.message).then(pc.setLocalDescription);
    });
  }
}

/////////////////////////////////////////////////////////

function createPeerConnection() {
  try {
    pc = new RTCPeerConnection(null);
    pc.onicecandidate = ({ candidate }) => sendMessage({ candidate });
    pc.ontrack = event => {
      if (remoteVideo.srcObject) return;
      remoteVideo.srcObject = event.streams[0];
    };
    console.log('Created RTCPeerConnnection');
  } catch (e) {
    console.log('Failed to create PeerConnection, exception: ' + e.message);
    alert('Cannot create RTCPeerConnection object.');
    return;
  }
}

function setLocalAndSendMessage(sessionDescription) {
  console.log('setLocalAndSendMessage sending message', sessionDescription);
  pc.setLocalDescription(sessionDescription);
  sendMessage(sessionDescription);
}

function hangupCall() {
  pc.close();
  pc = null;
}

1 个答案:

答案 0 :(得分:2)

没有了解异步代码的解决方法。您不会在这里粘贴自己的方式。

如果您不打算使用async/await,则需要应对JavaScript是单线程的,并且永远不能阻塞以等待异步操作完成,因此您永远不能直接使用异步方法的返回值,就像您要在此处进行的操作一样:

createAnswer是一种异步方法,返回promise,而不是答案,所以这是错误

  pc.setLocalDescription(                                    // <-- wrong
    pc.createAnswer(setLocalAndSendMessage, function(err) {  //
      console
        .log(err.name + ': ' + err.message)
        .then(pc.setLocalDescription);
    })
  );

您正在呼叫setLocalDescription(promise),由于承诺不是有效的描述,因此您会提到错误。相反,a promise is an object you attach callbacks to

const promise = pc.createAnswer();
promise.then(setLocalAndSendMessage, function(err) {
  console.log(err.name + ': ' + err.message);
});

或简单地:

pc.createAnswer()
  .then(setLocalAndSendMessage, function(err) {
    console.log(err.name + ': ' + err.message);
  });

我们甚至可以连续使用then来形成promise chain

pc.createAnswer()
  .then(function(answer) {
    return pc.setLocalDescription(answer);
  })
  .then(function() {
    sendMessage(pc.localDescription);
  })
  .catch(function(err) {
    console.log(err.name + ': ' + err.message);
  });

此外,我不必告诉你console.log()并没有兑现承诺!

遗憾的是,您要在此处复制really old code,并且RTCPeerConnection具有一些旧版API,并提供了一些技巧,有时可以使呼叫者摆脱调用这些协商方法的麻烦,而无需真正的承诺链或检查错误。但这不可避免地会导致麻烦。