2016-07-04 45 views
7

Ho seguito un intero tutorial su WebRTC e implementando una semplice chat p2p. Il mio server di segnalazione funziona a parte su localhost: 9090. Quando cerco di inviare un messaggio, sto ricevendo:WebRTC: RTCDataChannel non è "aperto"

RTCDataChannel.readyState is not 'open' 

Tuttavia, la connessione sembra essere stato stabilito correttamente:

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 

Ecco il codice di Client.js:

Come posso essere sicuro che ogni client sia realmente connesso all'altro e che la risposta/SDP sia corretta? Qualche consiglio per questo: forse la creazione del canale è troppo presto e dovrebbe essere fatta solo dopo l'intera "stretta di mano"? Grazie mille

__ EDIT Dopo il 1 ° risposta di Jib __

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

Rimuovere 'RtpDataChannels'. Quella roba è obsoleta, solo Chrome e probabilmente non funziona. – jib

+0

Grazie, posso inviare dati dall'utente che avvia la connessione (chi ha creato un canale dati). Come posso inviare indietro i dati con l'altro utente poiché mi hai detto che solo 1 deve creare un canale dati? – Arkon

+0

I canali dati sono bidirezionali, quindi basta aggiungere 'dataChannel.onmessage' per ricevere. – jib

risposta

3

creazione del canale dati è asimmetrica, proprio come lo scambio offerta/risposta. Solo l'offerente chiama lo pc.createDataChannel(), mentre il rispondente ascolta pc.ondatachannel.

Spostare il createDataChannel chiamata a destra prima di chiamare createOffer, e aggiungere qualche parte:

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

Inoltre, utilizzare dataChannel.onopen da imparare quando si apre il canale (funziona su entrambe le estremità).

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

Si possono fare due cose:

  1. controllare lo stato di connessione ICE ("controllo", "connesso"):

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

  2. Aggiungi callback di errore. Chiamate come setLocalDescription possono fallire e dirti perché, ma non stai controllando il fallimento.

+0

Grazie mille fiocco! Così ho modificato il mio messaggio principale con le tue modifiche. Ho spostato {openDataChannel} poco prima di {myConnection.createOffer}. Ho aggiunto anche myConnection.ondatachannel (l'ho definito con la stessa sintassi del documento ufficiale api). Ho aggiunto {dataChannel.onnopen} e {myConnection.oniceconnectionstatechange}. Ho ancora lo stesso problema in realtà. Il processo è: ho effettuato l'accesso utente1 poi utente2. utente1 stabilisce la connessione e invia un messaggio. {client.js: 178 Uncaught InvalidStateError: Impossibile eseguire 'send' su 'RTCDataChannel': RTCDataChannel.readyState non è 'aperto'} sulla riga 178. – Arkon

+0

Grazie mille! Stavo seguendo queste istruzioni: https://www.tutorialspoint.com/webrtc/webrtc_text_demo.htm ma mancava un passaggio del dataChannel. come yout didi con myConnection.ondatachannel = event => dataChannel = event.channel; – jvoigt

1

Aggiungi ondatachannel movimentazione dopo aver rimosso {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();