我正在使用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
答案 0 :(得分:0)
我发现了这个问题:
我的yourConn作业yourConn = new RTCPeerConnection(configuration, {optional: [{RtpDataChannels: true}]});
被置于回调中,这就是yourConn
中dataChannel = yourConn.createDataChannel("channel1", {reliable:true});
未定义的原因