如何解决一旦我将媒体轨道添加到连接,WebRTC 数据通道连接就会失败
我一直在尝试创建视频群组通话应用程序。它遵循网状拓扑结构,我遵循的步骤如下:
- 当客户端连接时。如果房间是第一个客户端,或者它向该房间中的所有其他客户端广播其套接字 ID,则会创建一个房间
- 当客户端收到套接字 id 时,它会向它发送一个报价,然后循环开始。其他客户端也遵循类似的流程。 问题是当我简单地创建数据通道时,它工作正常,但是一旦我开始添加媒体轨道,事情就会中断,甚至数据通道也无法连接。下面附上代码
import { io } from 'socket.io-client'
class RTConnection {
constructor() {
this.config = {
iceServers: [
{
urls: ["stun:stun.l.google.com:19302"]
}
]
}
this.connections = {}
this.videoElements = {}
this.ICEqueue = {}
}
init = async (roomId,videoElemRef) => {
this.roomId = roomId
this.videoElemRef = videoElemRef.current
let video = document.createElement('VIDEO')
this.myVideo = video
video.onloadedMetadata = e => video.play()
this.videoElemRef.appendChild(video)
const stream = await navigator.mediaDevices.getUserMedia({video: true,audio: false})
video.srcObject = stream
this.socket = io()
this.socket.emit("join-room",roomId)
this.socket.on('new-member',id => {
this.createOffer(id)
})
this.socket.on("offer",(id,offer) => {
this.acceptOffer(id,offer)
})
this.socket.on("new-ice-candidate",candidate) => {
this.handleIceCandidate(id,candidate)
})
this.socket.on("answer",answer) => {
this.acceptAnswer(id,answer)
})
}
acceptAnswer = async (id,answer) => {
const peerConnection = this.connections[id]
await peerConnection.setRemoteDescription(answer)
console.log("Answer Accepted")
}
handleIceCandidate = async (id,candidate) => {
if(!candidate) {
return
}
const peerConnection = this.connections[id]
if(peerConnection.remoteDescription) {
console.log("Setting Ice")
console.log(candidate)
await peerConnection.addIceCandidate(new RTCIceCandidate(candidate))
} else {
if(id in this.ICEqueue) {
console.log("Storing Ice Candidates")
console.log(id)
this.ICEqueue[id].push(candidate)
} else {
this.ICEqueue[id] = []
}
}
}
hydrateIceCandidates = async (id) => {
const peerConnection = this.connections[id]
console.log("Hydrating Ice")
for(let i in this.ICEqueue[id]) {
const candidate = this.ICEqueue[id][i]
await peerConnection.addIceCandidate(candidate)
}
}
acceptOffer = async (id,offer) => {
const peerConnection = new RTCPeerConnection()
peerConnection.ondatachannel = e => {
console.log("Data Channel Received")
peerConnection.dc = e.channel
peerConnection.dc.onopen = e => console.log("Connected!!!!")
}
this.connections[id] = peerConnection
peerConnection.onicecandidate = e => {
this.socket.emit("new-ice-candidate",e.candidate)
}
peerConnection.ontrack = (e) => {
console.log("Received a track");
console.log(e.streams)
const video = document.createElement('VIDEO')
this.videoElemRef.appendChild(video)
video.onloadeddata = ev => {console.log("Meta Data Loaded") ; video.play()}
video.srcObject = e.streams[0]
}
const stream = this.myVideo.srcObject
console.log("Private Stream")
console.log(stream)
//await stream.getTracks().forEach(async track => peerConnection.addTrack(track,stream))
await peerConnection.setRemoteDescription(offer)
console.log("Remote Description Set")
const ans = await peerConnection.createAnswer()
console.log("Answer Created")
await peerConnection.setLocalDescription(ans)
console.log("Local Description Set")
await this.hydrateIceCandidates(id)
this.socket.emit("answer",id,ans)
}
createOffer = async (id) => {
const peerConnection = new RTCPeerConnection()
const stream = this.myVideo.srcObject
//stream.getTracks().forEach(track => peerConnection.addTrack(track,stream))
peerConnection.dc = peerConnection.createDataChannel("channel")
peerConnection.dc.onopen = e => {
console.log("Connected!!!")
}
this.connections[id] = peerConnection
peerConnection.ontrack = (e) => {
console.log("Received a track");
console.log(e.streams)
const video = document.createElement('VIDEO')
console.log("Video Element")
console.log(video)
this.videoElemRef.appendChild(video)
video.onloadedMetadata = ev => video.play()
video.srcObject = e.streams[0]
}
peerConnection.onicecandidate = (e) => {
this.socket.emit("new-ice-candidate",e.candidate)
}
const offer = await peerConnection.createOffer()
await peerConnection.setLocalDescription(offer)
console.log(peerConnection.localDescription)
this.socket.emit("offer",offer)
}
stopStream = (stream,elem) => {
stream.getTracks().forEach(track => {
track.stop()
})
this.videoElemRef.current.removeChild(elem)
}
cleanMedia = () => {
this.stopStream(this.videoEl.srcObject,this.videoEl)
for(let id in this.videoElements) {
this.stopStream(this.videoElements[id].srcObject,this.videoElements[id])
delete this.videoElements[id]
}
delete this.videoElements
}
leaveCall = () => {
for(let id in this.connections) {
this.connections[id].close()
delete this.connections[id]
}
delete this.connections
this.cleanMedia()
this.socket.disconnect()
}
}
export default RTConnection
服务端代码
const express = require('express')
const fs = require('fs')
const app = express()
const path = require('path')
const v4 = require('uuid').v4
const options = {
key: fs.readFileSync("key.pem"),cert: fs.readFileSync("cert.pem")
}
const server = require('http').createServer(app)
const io = require('socket.io')(server)
const port = process.env.port || '5000'
app.set('view engine','ejs')
app.use("/",express.static(path.resolve(__dirname + '/public')))
app.get('/',(req,res) => {
res.render('home')
})
app.get('/room',res) => {
const roomId = v4()
res.redirect(`/room/${roomId}`)
})
app.get('/room/:roomId',res) => {
res.render('room',{roomId: req.params.roomId})
})
server.listen(port,() => {
console.log(`Starting server on ${port}`)
})
io.on("connection",socket => {
socket.on('join-room',(roomId) => {
socket.join(roomId)
socket.to(roomId).emit("new-member",socket.id)
socket.on("new-ice-candidate",(candidate) => {
socket.to(roomId).emit("new-ice-candidate",socket.id,candidate)
})
socket.on("offer",offer) => {
socket.to(id).emit("offer",offer)
})
socket.on("answer",answer) => {
socket.to(id).emit("answer",answer)
})
socket.on("disconnecting",() => {
for(let room of socket.rooms) {
socket.to(room).emit("leaveCall",socket.id)
}
})
})
})
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。