无法读取未定义的属性'createDataChannel'

时间:2017-09-06 09:38:34

标签: javascript reactjs webrtc

我正在使用WebRTC和ReactJS进行视频通话+聊天应用程序。创建数据通道时出现此错误:

TypeError:无法读取未定义的属性“createDataChannel”。 在此行检测到错误:

yourConn = new RTCPeerConnection(configuration, {optional: [{RtpDataChannels: true}]});

我的yourConn变量:import React from 'react'; import './CallPage.css'; import {conn} from '../../websocket/ws'; import {connect} from 'react-redux'; import TextArea from './textArea/TextArea'; var connectedUser, stream, yourConn, dataChannel; class CallPage extends React.Component { constructor(props) { super(props); this.state = { localVideoSrc: '', remoteVideoSrc: '', callToUser: '', tableRow: [], userList: [], message: '', receivedMessage: '' }; this.handleCall = this.handleCall.bind(this); this.handleHangup = this.handleHangup.bind(this); this.handleSend = this.handleSend.bind(this); } componentWillMount() { conn.onmessage = (msg) => { if (msg.data !== "Hello world") { var data = JSON.parse(msg.data); if (data.type && data.type !== "login") { console.log("Got message", msg.data); switch(data.type) { case "offer": this.handleOffer(data.offer, data.name); break; case "answer": this.handleAnswer(data.answer); break; //when a remote peer sends an ice candidate to us case "candidate": this.handleCandidate(data.candidate); break; case "leave": this.handleLeave(); break; case "update": this.handleUpdate(data.list, data.usersOnCall); break; case "updateUserTable": this.handleUpdateUserTable(data.usersOnCall); break; default: break; } } } }; this.initial(); } initial() { navigator.getUserMedia({video: true, audio: true}, (myStream) => { stream = myStream; this.setState({localVideoSrc: window.URL.createObjectURL(stream)}); var configuration = { "iceServers": [{ "url": "stun:stun2.1.google.com:19302" }] }; yourConn = new RTCPeerConnection(configuration, {optional: [{RtpDataChannels: true}]}); yourConn.addStream(stream); yourConn.onaddstream = (e) => { this.setState({remoteVideoSrc: window.URL.createObjectURL(e.stream)}); }; this.send({ type: "update" }); yourConn.onicecandidate = (event) => { if (event.candidate) { this.send({ type: "candidate", candidate: event.candidate }); } }; }, (error) => { console.log(error); }); dataChannel = yourConn.createDataChannel("channel1", {reliable:true}); dataChannel.onerror = (error) => { console.log("Ooops...error:", error); }; //when we receive a message from the other peer, display it on the screen dataChannel.onmessage = (event) => { var oldMessages = this.state.receivedMessage; var userB = this.state.callToUser; this.setState({ receivedMessage: oldMessages + userB + ": " + event.data + "<br />" }) }; dataChannel.onclose = () => { console.log("data channel is closed"); }; } send(message) { if (connectedUser) { message.name = connectedUser; } conn.send(JSON.stringify(message)); } handleCall(user) { // alert(user); var callToUsername = user; if (user.length > 0) { connectedUser = callToUsername; yourConn.createOffer((offer) => { this.send({ type: "offer", offer: offer }); yourConn.setLocalDescription(offer); }, (error) => { alert("Error when creating an offer"); }); } } handleUpdate(list, usersOnCall) { var row = list.map((user, key) => { return ( <tr key={key}> <td><i className={usersOnCall.indexOf(user) > -1 ? "fa fa-volume-control-phone" : "fa fa-volume-control-phone hidden"} aria-hidden="true"></i></td> <td className={user === this.props.yourName ? "your-name": ""}>{user}</td> <td><button className="btn btn-primary" onClick={() => this.handleCall(user)} disabled = {usersOnCall.indexOf(user) > -1 || user === this.props.yourName ? true : false }>Call</button></td> <td><button className="btn btn-danger" onClick={this.handleHangup} disabled = {true} >Hang up</button></td> </tr> ); }); this.setState({tableRow: row, userList: list}); } handleUpdateUserTable(usersOnCall) { this.handleUpdate(this.state.userList, usersOnCall); } handleOffer(offer, name) { connectedUser = name; this.setState({callToUser: name}) yourConn.setRemoteDescription(new RTCSessionDescription(offer)); yourConn.createAnswer((answer) => { yourConn.setLocalDescription(answer); this.send({ type: "answer", answer: answer }); this.send({ type: "updateUserTable", userA: this.props.yourName, userB: name }); }, (error) => { alert("Error when creating an answer"); }); } handleAnswer(answer) { yourConn.setRemoteDescription(new RTCSessionDescription(answer)); } handleCandidate(candidate) { yourConn.addIceCandidate(new RTCIceCandidate(candidate)); } handleHangup() { this.send({ type: "leave", userA: this.props.yourName, userB: this.state.callToUser }); this.handleLeave(); } handleChangeInputMessage(e) { this.setState({message: e.target.value}); } handleSend() { var message = this.state.message; var oldMessages = this.state.receivedMessage; this.setState({receivedMessage: oldMessages + "You: " + message + "<br />"}) } handleLeave() { connectedUser = null; this.setState({remoteVideoSrc: null, callToUser: ''}); yourConn.close(); yourConn.onicecandidate = null; yourConn.onaddstream = null; this.initial(); } render(){ return( <div className="container-fluid" id="callPage"> <div className="row"> <div className="col-sm-5"> <div className="call-page"> <video src={this.state.localVideoSrc} id="localVideo" autoPlay></video> <video src={this.state.remoteVideoSrc} id="remoteVideo" autoPlay></video> </div> </div> <TextArea message={this.state.message} receivedMessage={this.state.receivedMessage} handleSend={this.handleSend} handleChangeInputMessage={this.handleChangeInputMessage}/> <div className="col-sm-3"> <table className="table table-responsive table-hover"> <thead> <tr> <th className="text-center" colSpan="4">List of user</th> </tr> </thead> <tbody> {this.state.tableRow} </tbody> </table> </div> </div> </div> ); } } function mapStateToProps(state) { return { yourName: state.yourName } } export default connect(mapStateToProps)(CallPage);

我试过在gg上搜索这个问题,但没有希望。任何人都可以帮我解决这个问题吗?任何帮助表示赞赏。

更新:由于似乎仍然难以发现问题,因此这是发生问题的组件

var WebSocket = require('ws'); 
var WebSocketServer = require('ws').Server; 

//creating a websocket server at port 9090 
var wss = new WebSocketServer({port: 9090}); 

//all connected to the server users 
var users = {};
var userList = [];
var usersOnCall = [];
//when a user connects to our sever 
wss.on('connection', function(connection) {

 console.log("User connected");

//when server gets a message from a connected user 
connection.on('message', function(message) { 

  var data; 

  //accepting only JSON messages 
  try { 
     data = JSON.parse(message); 
  } catch (e) { 
     console.log("Invalid JSON"); 
     data = {}; 
  }

  //switching type of the user message 
  switch (data.type) { 
     //when a user tries to login
     case "login": 
        console.log("User logged", data.name); 
        //if anyone is logged in with this username then refuse 
        if(users[data.name]) { 
           sendTo(connection, { 
              type: "login", 
              success: false
           }); 
        } else { 
           //save user connection on the server 
           userList.push(data.name);
           users[data.name] = connection; 
           connection.name = data.name; 
           sendTo(connection, { 
              type: "login", 
              success: true
           });               
        }               
        break;

      case "update":
        broadcast(connection,{
          type: "update",
          list: userList,
          usersOnCall: usersOnCall
        });  
        break;

     case "offer": 
        //for ex. UserA wants to call UserB 
        console.log("Sending offer to: ", data.name);

        //if UserB exists then send him offer details 
        var conn = users[data.name]; 

        if(conn != null) { 
           //setting that UserA connected with UserB 
           connection.otherName = data.name; 

           sendTo(conn, { 
              type: "offer", 
              offer: data.offer, 
              name: connection.name 
           }); 
        }

        break;

     case "answer": 
        console.log("Sending answer to: ", data.name); 
        //for ex. UserB answers UserA 
        var conn = users[data.name]; 

        if(conn != null) { 
           connection.otherName = data.name; 
           sendTo(conn, { 
              type: "answer", 
              answer: data.answer 
           }); 
        } 

        break; 

     case "candidate": 
        console.log("Sending candidate to:",data.name); 
        var conn = users[data.name];

        if(conn != null) { 
           sendTo(conn, { 
              type: "candidate", 
              candidate: data.candidate 
           }); 
        } 

        break;

    case "updateUserTable":
      if (usersOnCall.indexOf(data.userA) === -1 && 
usersOnCall.indexOf(data.userB) === -1) {
        usersOnCall.push(data.userA);
        usersOnCall.push(data.userB);
        broadcast(connection, {
          type: "updateUserTable",
          usersOnCall: usersOnCall
        });
      }

      break;

     case "leave": 
        console.log("Disconnecting from", data.name); 
        var indexA = usersOnCall.indexOf(data.userA);
        usersOnCall.splice(indexA, 1);
        var indexB = usersOnCall.indexOf(data.userB);
        usersOnCall.splice(indexB, 1);
        broadcast(connection,{
          type: "update",
          list: userList,
          usersOnCall: usersOnCall
        });  
        var conn = users[data.name]; 
        conn.otherName = null; 

        //notify the other user so he can disconnect his peer connection 
        if(conn != null) {
           sendTo(conn, { 
              type: "leave" 
          }); 
        }
        break;

     default: 
        sendTo(connection, { 
           type: "error", 
           message: "Command not found: " + data.type 
        }); 

        break; 
  }

 }); 

 //when user exits, for example closes a browser window 
 //this may help if we are still in "offer","answer" or "candidate" state 
 connection.on("close", function() { 
 //  console.log(connection.name);
  userList.splice(userList.indexOf(connection.name),1);
  currentUser = "";
  broadcast(connection,{
    type: "update",
    list: userList
  });
  if(connection.name) { 
     delete users[connection.name]; 
     if(connection.otherName) { 
        console.log("Disconnecting from ", connection.otherName); 
        var conn = users[connection.otherName]; 
        conn.otherName = null;

        if(conn != null) { 
           sendTo(conn, { 
              type: "leave" 
           }); 
        }
     } 
  }

 });

connection.send("Hello world");  
});

function sendTo(connection, message) {
connection.send(JSON.stringify(message)); 
}

function broadcast(connection, message) {
  wss.clients.forEach(function each(client) {
    if (client.readyState === WebSocket.OPEN) {
      client.send(JSON.stringify(message));
    }
  });
}

这是我的服务器

awk -v r=6 'END{ while((r--)-NR>0) print "" }1' file

1 个答案:

答案 0 :(得分:0)

我发现了这个问题: 我的yourConn作业yourConn = new RTCPeerConnection(configuration, {optional: [{RtpDataChannels: true}]});被置于回调中,这就是yourConndataChannel = yourConn.createDataChannel("channel1", {reliable:true});未定义的原因