WebRTC:RTCDataChannel不是“打开”

我跟随了关于WebRTC的整个教程并实现了一个简单的p2p聊天。 我的信令服务器在localhost:9090上工作。 当我尝试发送消息时,我收到:

RTCDataChannel.readyState is not 'open'

但是,这种联系似乎已经得到妥善建立:

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=0rno=- 5123156273253761787 2 IN IP4 127.0.0.1rns=-rnt=0 0rna=group:BUNDLE datarna=msid-semantic: WMSrnm=application 9 UDP/TLS/RTP/SAVPF 127rnc=IN IP4 0.0.0.0rnb=AS:30rna=rtcp:9 IN IP4 0.0.0.0rna=ice-ufrag:aWnc+x1ot0kpmCj6rna=ice-pwd:o8BH8EIsb/FVLBDkUt5Mw6V4rna=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:F2rna=setup:activerna=mid:datarna=sendrecvrna=rtcp-muxrna=rtpmap:127 google-data/90000rna=ssrc:2024832766 cname:y/zAQto2dzSH04r0rna=ssrc:2024832766 msid:myDataChannel myDataChannelrna=ssrc:2024832766 mslabel:myDataChannelrna=ssrc:2024832766 label:myDataChannelrn"}}
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

这里是client.js的代码:

我怎样才能确保每个客户真正连接到另一个客户,并且答案/ SDP是正确的? 对此的任何提示:也许渠道创建过早完成,应该只在整个“握手”之后完成? 非常感谢

__编辑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);
    });

数据通道的创建是不对称的,就像提供/回答交换一样。 只有pc.createDataChannel()调用pc.createDataChannel() ,而pc.ondatachannel收听pc.ondatachannel

在调用createOffer之前将您的createDataChannel调用移动到正确createOffer ,然后添加到某处:

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

另外,使用dataChannel.onopen来学习何时打开通道(两端都工作)。

我怎样才能确保每个客户真正连接到另一个客户,并且答案/ SDP是正确的?

你可以做两件事:

  • 检查ICE连接状态(“检查”,“连接”):

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

  • 添加错误回调。 像setLocalDescription这样的调用可能会失败,并告诉你为什么,但是你没有检查失败。


  • 删除后添加ondatachannel处理{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();
    
    链接地址: http://www.djcxy.com/p/92469.html

    上一篇: WebRTC: RTCDataChannel is not 'open'

    下一篇: Android: Transparent status bar with dynamic actionBar colors and DrawerLayout