双方的远程视频都不会显示

时间:2019-01-12 19:48:33

标签: javascript socket.io webrtc

当前使用的是Chrome 70,Firefox 64和Safari12。

另一个用户的远程视频没有在两侧显示,我不确定这可能是问题所在。

任何浏览器都没有错误,这些错误无助于调试代码。

我正在使用chrome的内部WebRTC调试工具(chrome:// webrtc-internals),发送或接收的数据包为零。

该工具中有一个参数googCandidatePair,但这在通话过程中根本不显示。 enter image description here

ICEgatheringstatechange事件触发并声明它已经完成,但是仅当主机是chrome用户时。

我也尝试使用

pc.oniceconnectionstatechange = () => console.log(pc.iceConnectionState);

检查ICE状态是否更改,但这根本不会触发。

我认为它可能无法正常运行的一个原因可能是由于RTCPeerconnection是如何配置的(如上图所示),Ice候选池的大小为0,但从未在代码本身中声明。 enter image description here

下面是两张图片,其中第一张是当主机是chrome时,另一张是接收者 enter image description here enter image description here

代码如下:

'use strict';

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);
  startVideo();
});

socket.on('full', function(room) {
  console.log('Message from client: Room ' + room + ' is full :^(');
});

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

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

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

async function sendMessage(message) {
  console.log('Client sending message: ', message);
  await socket.emit('message', message);
}

// This client receives a message
socket.on('message', message => {
  if (message.sdp) {
    pc.setRemoteDescription(new RTCSessionDescription(message.sdp))
      .then(function() {
        if (pc.setRemoteDescription.type === 'offer') {
          pc.setLocalDescription(pc.createAnswer())
            .then(function() {
              sendMessage({ sdp: pc.localDescription });
            })
            .catch(function(err) {
              console.log(err.name + ': ' + err.message);
            });
        }
      })
      .catch(error => console.error(error));
  } else if (message.candidate) {
    pc.addIceCandidate(new RTCIceCandidate(message.candidate))
      .then(() => {
        console.log('Candidates received');
      })
      .catch(error => console.error(error));
  }
});

pc.onicecandidate = event => {
  if (event.candidate) {
    sendMessage({ candidate: event.candidate });
  }
};

pc.ontrack = event => {
  if (remoteVideo.srcObject !== event.streams[0]) {
    remoteVideo.srcObject = event.streams[0];
    console.log('Got remote stream');
  }
};

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

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(stream) {
      localVideo.srcObject = stream;
      stream.getTracks().forEach(track => pc.addTrack(track, stream));
    })
    .catch(function(err) {
      console.log('getUserMedia() error: ' + err.name);
    });
  callButton.disabled = false;
}

async function callStart() {
  callButton.disabled = true;
  hangupButton.disabled = false;

  console.log('Sending offer to peer');
  await pc
    .setLocalDescription(await pc.createOffer())
    .then(() => {
      sendMessage({ sdp: pc.localDescription });
    })
    .catch(err => {
      console.log(err.name + ': ' + err.message);
    });
}

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

function hangupCall() {
  pc.close();
  pc = null;
  callButton.disabled = false;
  hangupButton.disabled = true;
  console.log('Call Ended');
}

2 个答案:

答案 0 :(得分:2)

您正在混合您的诺言样式,并且这里有一个错误:

          pc.setLocalDescription(pc.createAnswer()) // bug!
            .then(function() {

以上将本地描述设置为Promise对象。始终选择async / await

          await pc.setLocalDescription(await pc.createAnswer());

...或.then()链:

          pc.createAnswer()
            .then(answer => pc.setLocalDescription(answer))
            .then(function() {

如果选择后者,请不要忘记return all the promises

这是仅使用async / await完成的消息处理程序:

// This client receives a message
socket.on('message', async message => {
  try {
    if (message.sdp) {
      await pc.setRemoteDescription(message.sdp);
      if (pc.setRemoteDescription.type === 'offer') {
        await pc.setLocalDescription(await pc.createAnswer());
        sendMessage({sdp: pc.localDescription});
      }
    } else if (message.candidate) {
      await pc.addIceCandidate(message.candidate);
      console.log('Candidates received');
    }
  } catch (err) {
    console.log(err.name + ': ' + err.message);
  }
}

答案 1 :(得分:0)

如果有人可能对远程视频没有显示有问题,我发现这是因为该消息不是通过第二条IF语句来检查message.type === offer的,并且因为它无法创建因此,它无法将其本地描述发送给其他用户。但是通过在开始时将消息拆分为sdp和候选人,它就可以工作了。

socket.on('message', async ({ sdp, candidate }) => {
  if (sdp) {
    await pc.setRemoteDescription(new RTCSessionDescription(sdp));
    if (sdp.type === 'offer') {
      await pc
        .setLocalDescription(await pc.createAnswer())
        .then(function() {
          sendMessage({ sdp: pc.localDescription });
        })
        .catch(function(err) {
          console.log(err.name + ': ' + err.message);
        });
    }
  } else if (candidate) {
    await pc
      .addIceCandidate(new RTCIceCandidate(candidate))
      .then(() => {
        console.log('Candidates received');
      })
      .catch(error => console.error(error));
  }
});