2016-07-04 24 views
7

Ich folgte einem kompletten Tutorial über WebRTC und implementierte einen einfachen P2P-Chat. Mein Signalisierungsserver arbeitet auf localhost: 9090. Wenn ich versuche, eine Nachricht zu senden, erhalte ich:WebRTC: RTCDataChannel ist nicht 'offen'

RTCDataChannel.readyState is not 'open' 

Allerdings scheint die Verbindung hergestellt worden ist ordnungsgemäß zu haben:

Connected 
Got message {"type":"login","success":true} 
RTCPeerConnection object was created 
RTCPeerConnection {localDescription: RTCSessionDescription, remoteDescription: RTCSessionDescription, signalingState: "stable", iceGatheringState: "new", iceConnectionState: "new"…} 
Channel created 
Got message {"type":"answer","answer":{"type":"answer","sdp":"v=0\r\no=- 5123156273253761787 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=group:BUNDLE data\r\na=msid-semantic: WMS\r\nm=application 9 UDP/TLS/RTP/SAVPF 127\r\nc=IN IP4 0.0.0.0\r\nb=AS:30\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=ice-ufrag:aWnc+x1ot0kpmCj6\r\na=ice-pwd:o8BH8EIsb/FVLBDkUt5Mw6V4\r\na=fingerprint:sha-256 D6:18:83:20:FC:3F:0B:87:8F:FB:D8:5D:D6:33:13:FE:C6:EE:53:3D:18:69:DD:C0:BF:23:35:95:F7:26:4D:F2\r\na=setup:active\r\na=mid:data\r\na=sendrecv\r\na=rtcp-mux\r\na=rtpmap:127 google-data/90000\r\na=ssrc:2024832766 cname:y/zAQto2dzSH04r0\r\na=ssrc:2024832766 msid:myDataChannel myDataChannel\r\na=ssrc:2024832766 mslabel:myDataChannel\r\na=ssrc:2024832766 label:myDataChannel\r\n"}} 
Got message {"type":"candidate","candidate":{"candidate":"candidate:2633341356 1 udp 2113937151 172.20.10.6 54721 typ host generation 0 ufrag aWnc+x1ot0kpmCj6","sdpMid":"data","sdpMLineIndex":0}} 
candidate added 

Hier ist der Code von Client.js ist:

Wie kann ich sicherstellen, dass jeder Client wirklich mit dem anderen verbunden ist und dass die Antwort/SDP korrekt war? Irgendwelche Tipps dazu: Vielleicht ist die Channel-Erstellung zu früh gemacht und sollte erst nach dem ganzen "Handshake" erfolgen? Vielen Dank

__ EDIT Nach Jib der ersten Antwort __

var connectedUser, myConnection, dataChannel; 

//when a user clicks the login button 
loginBtn.addEventListener("click", function(event) { 
    name = loginInput.value; 
     send({ 
      type: "login", 
      name: name 
      }); 
    }); 

//handle messages from the server 
connection.onmessage = function (message) { 
    console.log("Got message", message.data); 
    var data = JSON.parse(message.data); 

    switch(data.type) { 
    case "login": 
    onLogin(data.success); 
    break; 
    case "offer": 
    onOffer(data.offer, data.name); 
    break; 
    case "answer": 
    onAnswer(data.answer); 
    break; 
    case "candidate": 
    onCandidate(data.candidate); 
    break; 
    default: 
    break; 
    } 
}; 

//when a user logs in 
function onLogin(success) { 

    if (success === false) { 
    alert("oops...try a different username"); 
    } else { 
    //creating our RTCPeerConnection object 
    var configuration = { 
     "iceServers": [{ "urls": "stun:stun.1.google.com:19302" }] 
    }; 

    myConnection = new webkitRTCPeerConnection(configuration, { 
     optional: [{RtpDataChannels: true}] 
     }); 
    //ondatachannel is defined a bit later, commented out this line. 
    //myConnection.ondatachannel = event => dataChannel = event.channel; 
    console.log("RTCPeerConnection object was created"); 
    console.log(myConnection); 

    //setup ice handling 
    //when the browser finds an ice candidate we send it to another peer 
    myConnection.onicecandidate = function (event) { 

     if (event.candidate) { 
     send({ 
      type: "candidate", 
      candidate: event.candidate 
      }); 
     } 
    }; 
    myConnection.oniceconnectionstatechange = e => console.log(myConnection.iceConnectionState); 
    myConnection.ondatachannel = function(ev) { 
     console.log('Data channel is created!'); 
     ev.channel.onopen = function() { 
      console.log('Data channel is open and ready to be used.'); 
     }; 
    } 
    } 
}; 

connection.onopen = function() { 
    console.log("Connected"); 
}; 

connection.onerror = function (err) { 
    console.log("Got error", err); 
}; 

// Alias for sending messages in JSON format 
function send(message) { 
    if (connectedUser) { 
    message.name = connectedUser; 
    } 

    connection.send(JSON.stringify(message)); 
}; 

//setup a peer connection with another user 
connectToOtherUsernameBtn.addEventListener("click", function() { 

    var otherUsername = otherUsernameInput.value; 
    connectedUser = otherUsername; 

    if (otherUsername.length > 0) { 
     //Create channel before sending the offer 
     openDataChannel(); 
     //make an offer 
     myConnection.createOffer(function (offer) { 
      send({ 
       type: "offer", 
       offer: offer 
       }); 

      myConnection.setLocalDescription(offer); 
     }, function (error) { 
      alert("An error has occurred.:", error); 
     }); 
    } 
    }); 

//when somebody wants to call us 
function onOffer(offer, name) { 
    connectedUser = name; 
    myConnection.setRemoteDescription(new RTCSessionDescription(offer)); 

    myConnection.createAnswer(function (answer) { 
     myConnection.setLocalDescription(answer); 
     send({ 
      type: "answer", 
      answer: answer 
      }); 

    }, function (error) { 
     alert("oops...error: ", error); 
    }); 
} 

//when another user answers to our offer 
function onAnswer(answer) { 
    myConnection.setRemoteDescription(new RTCSessionDescription(answer)); 
} 

//when we got ice candidate from another user 
function onCandidate(candidate) { 
    myConnection.addIceCandidate(new RTCIceCandidate(candidate)); 
    console.log("candidate added"); 
} 

//creating data channel 
function openDataChannel() { 

    var dataChannelOptions = { 
    reliable:true 
    }; 
    dataChannel = myConnection.createDataChannel("myDataChannel", dataChannelOptions); 
    console.log("Channel created"); 

    dataChannel.onerror = function (error) { 
     console.log("Error:", error); 
    }; 

    dataChannel.onmessage = function (event) { 
     console.log("new message received"); 
     console.log("Got message:", event.data); 
    }; 
    dataChannel.onopen = function() { 
     console.log("channel opened"); 
    }; 
} 


//when a user clicks the send message button 
sendMsgBtn.addEventListener("click", function (event) { 
    console.log("send message"); 
    var val = msgInput.value; 
    dataChannel.send(val); 
    }); 
+1

Entfernen 'RtpDataChannels' entfernen. Das Zeug ist veraltet, nur für Chrome und funktioniert wahrscheinlich nicht. – jib

+0

Danke Ich kann Daten von dem Benutzer senden, der die Verbindung initiiert (wer einen Datachannel erstellt hat). Wie kann ich Daten mit dem anderen Benutzer zurücksenden, da Sie mir gesagt haben, dass nur 1 einen Datenkanal erstellen muss? – Arkon

+0

Datenkanäle sind bidirektional. Fügen Sie einfach "dataChannel.onmessage" hinzu, um empfangen zu können. – jib

Antwort

3

Datenkanal Schöpfung ist asymmetrisch, ebenso wie das Angebot/Antwort Austausch. Nur der Anbieter ruft pc.createDataChannel() an, während der Beantworter auf pc.ondatachannel hört.

Ihre createDataChannel Anruf nach rechts verschieben, bevor Sie createOffer rufen, und fügen Sie irgendwo:

myConnection.ondatachannel = event => dataChannel = event.channel; 

Zusätzlich dataChannel.onopen nutzen zu lernen, wenn der Kanal (arbeitet an beiden Enden) geöffnet wird.

How can I make sure that each client is really connected to the other and that the answer/SDP was correct?

Sie können zwei Dinge tun:

  1. den ICE-Verbindungszustand überprüfen ("Überprüfung", "verbunden"):

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

  2. hinzufügen Rückrufe Fehler. Anrufe wie setLocalDescription können fehlschlagen und Ihnen sagen, warum, aber Sie nicht auf Fehler überprüfen.

+0

Vielen Dank Jib! Also habe ich meine Hauptnachricht mit deinen Änderungen bearbeitet. Ich habe {openDataChannel} direkt vor {myConnection.createOffer} verschoben. Ich habe auch myConnection.ondatachannel hinzugefügt (ich habe es mit der gleichen Syntax definiert wie im offiziellen API-Dokument). Ich habe {dataChannel.onnopen} und {myConnection.oniceconnectionstatechange} hinzugefügt. Ich habe immer noch das gleiche Problem. Der Prozess ist: Ich loggte Benutzer1 dann Benutzer2 ein. user1 stellt eine Verbindung her und sendet eine Nachricht. {client.js: 178 Uncaught InvalidStateError: Fehler beim Ausführen von 'send' für 'RTCDataChannel': RTCDataChannel.readyState ist nicht 'open'} in Zeile 178. – Arkon

+0

Vielen Dank! Ich folgte dieser Anweisung: https://www.tutorialspoint.com/webrtc/webrtc_text_demo.htm aber es fehlte eine Übergabe des dataChannel. wie du didi mit myConnection.ondatachannel = event => dataChannel = event.channel; – jvoigt

1

ondatachannel Handhabung hinzufügen nach {optional: [{RtpDataChannels: true}]}:

myConnection.onicecandidate = function (event) { 

if (event.candidate) { 
    send({ 
     type: "candidate", 
     candidate: event.candidate 
    }); 
} }; 

myConnection.ondatachannel = function(event) { 
var receiveChannel = event.channel; 
receiveChannel.onmessage = function(event) { 
    console.log("ondatachannel message:", event.data); 
};  }; openDataChannel();