Javascript WebRTC的无服务器实现

Javascript WebRTC的无服务器实现,javascript,webrtc,Javascript,Webrtc,我不知道我在实现无服务器WebRTC时犯了什么错误 创建报价 将报价传递给远程 创造一个答案 我不知道我在实现无服务器WebRTC时犯了什么错误 以下是我到目前为止的情况: var localStream, localPeerConnection, remotePeerConnection; var servers = {"iceServers":[{"url":"stun:23.21.150.121"}]}; var sdpConstraints = { option

我不知道我在实现无服务器WebRTC时犯了什么错误

创建报价 将报价传递给远程 创造一个答案 我不知道我在实现无服务器WebRTC时犯了什么错误

以下是我到目前为止的情况:

    var localStream, localPeerConnection, remotePeerConnection;
var servers = {"iceServers":[{"url":"stun:23.21.150.121"}]};

var sdpConstraints = {
        optional: [],
        mandatory: {
            OfferToReceiveAudio: true,
            OfferToReceiveVideo: true
        }
    };

var localVideo = document.getElementById("alice");
var remoteVideo = document.getElementById("bob");

var startButton = document.getElementById("startButton");
var callButton = document.getElementById("callButton");
var hangupButton = document.getElementById("hangupButton");
var joinButton = document.getElementById("joinButton");

var localOffer = document.getElementById("localOffer");
var remoteOffer = document.getElementById("remoteOffer");
var localAnswer = document.getElementById("localAnswer");
var remoteAnswer = document.getElementById("remoteAnswer");

var showLocalOffer = document.getElementById("showLocalOffer");
var getRemoteOffer = document.getElementById("getRemoteOffer");
var showLocalAnswer = document.getElementById("showLocalAnswer");
var getRemoteAnswer = document.getElementById("getRemoteAnswer");

var sentLocalOfferButton = document.getElementById("sentLocalOfferButton");
var pasteRemoteOfferButton = document.getElementById("pasteRemoteOfferButton");
var sentLocalAnswerButton = document.getElementById("sentLocalAnswerButton");
var pasteRemoteAnswerButton = document.getElementById("pasteRemoteAnswerButton");

startButton.disabled = false;
callButton.disabled = true;
hangupButton.disabled = true;
joinButton.disabled = true;

showLocalOffer.style.display = 'none';
getRemoteOffer.style.display = 'none';
showLocalAnswer.style.display = 'none';
getRemoteAnswer.style.display = 'none';

startButton.onclick = start;
callButton.onclick = call;
joinButton.onclick = join;
hangupButton.onclick = hangup;
sentLocalOfferButton.onclick = showRemote;
pasteRemoteOfferButton.onclick = answerCreate;
pasteRemoteAnswerButton.onclick = answerRemote;
sentLocalAnswerButton.onclick = hideRemoteAnswer;

function trace(text) {
  console.log((performance.now() / 1000).toFixed(3) + ": " + text);
}

function start() {
  trace("Requesting local stream");
  startButton.disabled = true;
  getUserMedia({audio:true, video:true}, gotStream,
    function(error) {
      trace("getUserMedia error: ", error);
    });
}

function gotStream(stream){
  trace("Received local stream");
  localVideo.src = URL.createObjectURL(stream);
  localStream = stream;
  callButton.disabled = false;
  joinButton.disabled = false;
}

// ALICE

function call() {
    showLocalOffer.style.display = 'block';
    callButton.disabled = true;
    joinButton.disabled = true;
    hangupButton.disabled = false;
    trace("Starting call");

    if (localStream.getVideoTracks().length > 0) {
      trace('Using video device: ' + localStream.getVideoTracks()[0].label);
    }
    if (localStream.getAudioTracks().length > 0) {
      trace('Using audio device: ' + localStream.getAudioTracks()[0].label);
    }

    localPeerConnection = new RTCPeerConnection(servers);
    trace("Created local peer connection object localPeerConnection");

    localPeerConnection.addStream(localStream);
    trace("Added localStream to localPeerConnection");
    localPeerConnection.createOffer(gotLocalDescription,handleError,sdpConstraints);
}

function gotLocalDescription(description){
  localPeerConnection.setLocalDescription(description);
  trace("Offer from localPeerConnection SDP: \n" + description.sdp);
  trace("Offer from localPeerConnection TYPE: \n" + description.type);
  localOffer.value = JSON.stringify(description);
}

function showRemote() {
    showLocalOffer.style.display = 'none';
    getRemoteAnswer.style.display = 'block';
}

function answerRemote() {
  getRemoteAnswer.style.display = 'none';
    var remoteSesssionDescription = new RTCSessionDescription(JSON.parse(remoteAnswer.value));
    localPeerConnection.setRemoteDescription(remoteSesssionDescription);
    localPeerConnection.onaddstream = gotRemoteStream;
  localPeerConnection.onicecandidate = gotRemoteIceCandidate;
}

function gotRemoteIceCandidate(evt) {
    if (event.candidate) {
      localPeerConnection.addIceCandidate(new RTCIceCandidate(evt.candidate));
      trace("Remote ICE candidate: \n " + evt.candidate.candidate);
    }
}


// BOB

function join() {
    trace("Joining call");
    getRemoteOffer.style.display = 'block';
    callButton.disabled = true;
    hangupButton.disabled = false;
    joinButton.disabled = true;

    remotePeerConnection = new RTCPeerConnection(servers);
    trace("Created remote peer connection object remotePeerConnection");
}

function answerCreate() {
    getRemoteOffer.style.display = 'none';
    showLocalAnswer.style.display = 'block';

    var sessionDescription = new RTCSessionDescription(JSON.parse(remoteOffer.value));
    remotePeerConnection.setRemoteDescription(sessionDescription);
    remotePeerConnection.createAnswer(gotRemoteDescription,handleError,sdpConstraints);
}

function gotRemoteDescription(answerSdp) {
    remotePeerConnection.setLocalDescription(answerSdp);
    trace("Answer from remotePeerConnection SDP: \n" + answerSdp.sdp);
    trace("Answer from remotePeerConnection TYPE: \n" + answerSdp.type);
    localAnswer.value = JSON.stringify(answerSdp);
    remotePeerConnection.onaddstream = gotRemoteStream;
    remotePeerConnection.onicecandidate = gotLocalIceCandidate;

}

function hideRemoteAnswer() {
    showLocalAnswer.style.display = 'none';
}

function gotRemoteStream(evt) {
    console.log('evt: ', evt);
    remoteVideo.src = URL.createObjectURL(evt.stream);
    trace("Received remote stream");
}

function gotLocalIceCandidate(evt){
  if (event.candidate) {
    remotePeerConnection.addIceCandidate(new RTCIceCandidate(evt.candidate));
    trace("Local ICE candidate: \n" + evt.candidate.candidate);
  }
}

// GENERAL USE

function hangup() {
  trace("Ending call");
  localPeerConnection = null;
  remotePeerConnection = null;
  hangupButton.disabled = true;
  callButton.disabled = false;
  joinButton.disabled = false;

  showLocalOffer.style.display = 'none';
  getRemoteOffer.style.display = 'none';
  showLocalAnswer.style.display = 'none';
  getRemoteAnswer.style.display = 'none';
}

function handleError(){
    trace("Cannot Create Offer");
}

您应该使用onGetationRequired事件检查是否需要协商。如果该事件被触发,您应该创建一个要约并交换它。您可能想查看我的代码,这可能会对您有所帮助。

我已经编写了其中一个,您可以在中的Firefox中尝试。是的,通常使用服务器,您会在ICE候选者可用时通过您的信令通道发送他们

但在这里这是不切实际的。我想你想给你的朋友捎个口信。要做到这一点,请等待浏览器有时间发现所有ICE候选对象。然后,它们将包含在为您提供的报价/答复中注意:根据我的经验,在Windows上这可能需要15秒

执行此操作的一种方法是侦听OnGetationNeeded,直到它返回一个空候选者,表示ice收集结束:

pc.onicecandidate = function(e) {
  if (e.candidate) return;
  var offerSdp = pc.localDescription.sdp;
  // send offerSdp string to friend
};

希望能有帮助。

我也不知道你做错了什么。发生了什么或没有发生什么?您是如何传递报价及其答案的?我将创建的报价发送给一位远程朋友,他将使用报价创建答案,并将答案发送回@decezeLike,How?通过聊天?您还必须发送一批ICE候选人,而不仅仅是SDP报价。是的,通过chat@deceze。。。。您认为我将如何发送ICE候选人?您需要收听rtpeerConnection.onicecandidate。很容易就有20-50名ICE候选人。我认为把它们一个接一个地复制是不太可行的。