2017-09-06 10 views
0

我正在使用WebRTC和ReactJS進行視頻通話+聊天應用程序。在創建數據通道時出現此錯誤:無法讀取未定義的屬性'createDataChannel'

TypeError:無法讀取未定義的屬性'createDataChannel'。在這條線上檢測 錯誤:

dataChannel = yourConn.createDataChannel("channel1", {reliable:true}); 

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

我試圖尋找在GG這個問題,但沒有希望。任何人都可以幫我解決這個問題嗎?任何幫助表示讚賞。

更新:因爲它似乎仍然是防不​​勝防的問題,這裏是我的部件,其中該問題發生

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); 

,這裏是我的服務器

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)); 
    } 
    }); 
} 
+1

只是一個瘋狂的猜測,但我認爲它應該是'this.yourConn.createDataChannel(「channel1」,{reliable:true});'當你調用它時。 _since,因爲你沒有指定你的整個代碼只是一個guess_ – masterpreenz

+0

其實我確實是這樣的:'var yourConn;'從一開始 – AquaStar

+1

在JavaScript的意義上應該可以工作,但是因爲你使用的是框架,把你的組件代碼。 – masterpreenz

回答

0

我找到了問題: 我的yourConn分配yourConn = new RTCPeerConnection(configuration, {optional: [{RtpDataChannels: true}]});被置於回調中,這就是爲什麼yourConndataChannel = yourConn.createDataChannel("channel1", {reliable:true});未定義

相關問題