Hello I’m building a livestream mediasoup app with Node and React.js and it doesn’t seem to work, all the logs in the console work but it doesnt display the video on the page.
This is the code for the viewer in React:
let roomId = window.location.pathname.split('/')[2]
let device
let consumer
let consumerTransport
useEffect(() => {
const receiveUserMedia = () => {
try{
if (runStartOnce.current) return;
runStartOnce.current = true;
webrtc.emit('requestRtpCapabilities', ({ roomId }), async ({ rtpCapabilities }) => {
device = new Device()
await device.load({
routerRtpCapabilities: rtpCapabilities
})
console.log(device, rtpCapabilities)
webrtc.emit('createConsumerTransport', ({ roomId }), async ({ params }) => {
if(params.error){
console.log(params.error)
return
}
try{
console.log("Received params: ", params)
consumerTransport = device.createRecvTransport(params)
console.log("Created consumerTransport: ", consumerTransport)
}catch(error){
console.log(error)
}
consumerTransport.on('connect', async ({ dtlsParameters }, callback, errback) => {
try{
await webrtc.emit('connectConsumer', {
// transportId: producerTransport.id,
dtlsParameters: dtlsParameters,
roomId
})
callback()
}catch(error){
console.log(error)
errback(error)
}
})
try{
console.log("consuming...")
console.log("Send rtp: ", device.rtpCapabilities)
await webrtc.emit('consume', {
rtpCapabilities: device.rtpCapabilities,
roomId
}, async ({ params }) => {
if(params.error){
console.log("cannot consume")
return
}
console.log(params)
consumer = await consumerTransport.consume({
id: params.id,
producerId: params.producerId,
kind: params.kind,
rtpParameters: params.rtpParameters
})
const { track } = consumer
console.log("Received consumer: ", consumer)
console.log("Track: ", track)
console.log("New Media: ", new MediaStream([track]))
const remoteMediaStream = new MediaStream([track])
remoteVideoRef.current.srcObject = remoteMediaStream
setRemoteVideoObject(remoteMediaStream)
webrtc.emit('resume', ({ roomId }))
})
}catch(error){
console.log(error)
}
})
})
}catch(err){
console.log(error)
notify()
}
}
receiveUserMedia()
}, [])
This is the display for the remote video received:
<video id='fan-video' ref={remoteVideoRef} autoPlay playsInline className='video-player'></video>
This is the code for the streamer in React:
let roomId = window.location.pathname.split('/')[2]
let device
let consumer
let consumerTransport
useEffect(() => {
const getUserMedia = () => {
try{
if (runStartOnce.current) return;
runStartOnce.current = true;
const stream = await navigator.mediaDevices.getUserMedia(constraints)
localVideoRef.current.srcObject = stream
localStream = stream
webrtc.emit('getRtpCapabilities', ({ roomId }), async ({ rtpCapabilities }) => {
device = new Device()
await device.load({
routerRtpCapabilities: rtpCapabilities
})
console.log(device, rtpCapabilities)
const track = localStream.getVideoTracks()[0]
videoParams = {
track,
...videoParams
}
console.log(track, videoParams)
webrtc.emit('createProducerTransport', ({ roomId }), async ({ params }) => {
if(params.error){
console.log(params.error)
return
}
console.log("Received params: ", params)
producerTransport = device.createSendTransport(params)
console.log("Created producerTransport: ", producerTransport)
producerTransport.on('connect', async ({ dtlsParameters }, callback, errback) => {
try{
await webrtc.emit('connectProducer', {
// transportId: producerTransport.id,
dtlsParameters: dtlsParameters,
roomId
})
callback()
}catch(error){
console.log(error)
errback(error)
}
})
producerTransport.on('produce', async (parameters, callback, errback) => {
console.log("Received parameters: ", parameters)
try{
await webrtc.emit('produceProducer', {
// transportId: producerTransport.id,
kind: parameters.kind,
rtpParameters: parameters.rtpParameters,
appData: parameters.appData
}, (id) => {
console.log("Producer id: ", id)
callback({ id })
})
}catch(error){
console.log(error)
errback(error)
}
})
if(producerTransport){
console.log("Send rtp: ", device.rtpCapabilities)
console.log("track found: ", videoParams)
try {
producer = await producerTransport.produce(videoParams);
console.log('Created producer: ', producer);
} catch (error) {
console.log('Error creating producer:', error);
}
producer.on('trackended', () => {
console.log('track ended')
})
producer.on('transportclose', () => {
console.log('transport ended')
})
}
})
})
}catch(err){
console.log(error)
notify()
}
}
getUserMedia()
}, [])
Lastly this is the backend code for the socket using mediasoup, again everything is logging perfectly but its just not displaying in the receiver’s ui.
node-mediasoup-socketio code excerpt:
const lives = {}
let worker
let producer
let consumer
let producerTransport
let consumerTransport
const createWorker = async () => {
worker = await mediasoup.createWorker({
rtcMinPort: 2000,
rtcMaxPort: 5000
})
worker.on('died', error => {
console.log("mediasoup worker has died")
setTimeout(() => process.exit(1), 2000)
})
return worker
}
worker = createWorker()
const mediaCodecs = [
{
kind: 'audio',
mimeType: 'audio/opus',
clockRate: 48000,
channels: 2,
},
{
kind: 'video',
mimeType: 'video/VP8',
clockRate: 90000,
parameters: {
'x-google-start-bitrate': 1000,
},
},
]
io.on('connection', async (socket) => {
socket.on('getRtpCapabilities', async ({ roomId }, callback) => {
const router = await worker.createRouter({ mediaCodecs })
const rtpCapabilities = router.rtpCapabilities
callback({ rtpCapabilities })
lives[roomId] = { router }
})
socket.on('requestRtpCapabilities', async ({ roomId }, callback) => {
const rtpCapabilities = lives[roomId].router.rtpCapabilities
callback({ rtpCapabilities })
})
socket.on('createProducerTransport', async ({ roomId }, callback) => {
const socketId = socket.id
producerTransport = await createWebRtcTransport(callback, roomId)
})
socket.on('createConsumerTransport', async ({ roomId }, callback) => {
socket.join(roomId)
consumerTransport = await createWebRtcTransport(callback, roomId)
})
const createWebRtcTransport = async (callback, roomId) => {
try{
const options = {
listenIps: [
{
ip: '127.0.0.1',
// announcedIp: '127.0.0.1'
}
],
enableUdp: true,
enableTcp: true,
preferUdp: true
}
const storedRouter = lives[roomId].router
const transport = await storedRouter.createWebRtcTransport(options)
transport.on('dtlsstatechange', dtlsState => {
if(dtlsState === 'closed'){
transport.close()
}
})
callback({
params: {
id: transport.id,
iceParameters: transport.iceParameters,
iceCandidates: transport.iceCandidates,
dtlsParameters: transport.dtlsParameters
}
})
return transport
}catch(error){
console.log(error)
}
}
socket.on('connectProducer', async ({ dtlsParameters, roomId }, callback) => {
await producerTransport.connect({ dtlsParameters })
// console.log("connecting...", producerTransport)
})
socket.on('produceProducer', async ({ kind, rtpParameters, appData, roomId }, callback) => {
producer = await producerTransport.produce({
kind,
rtpParameters
})
producer.on('transportclose', () => {
console.log('transport closed')
producer.close()
})
callback({
id: producer.id
})
})
socket.on('connectConsumer', async ({ dtlsParameters, roomId }, callback) => {
await consumerTransport.connect({ dtlsParameters })
console.log("consuming...", consumerTransport)
})
socket.on('consume', async ({ rtpCapabilities, roomId }, callback) => {
try{
const storedRouter = lives[roomId].router
console.log("Can consume? ", storedRouter.canConsume({ producerId: producer.id, rtpCapabilities: rtpCapabilities }))
if(storedRouter.canConsume({
producerId: producer.id,
rtpCapabilities: storedRouter.rtpCapabilities
})) {
consumer = await consumerTransport.consume({
producerId: producer.id,
rtpCapabilities: storedRouter.rtpCapabilities,
paused: true
})
consumer.on('transportclose', () => {
console.log('transport closed')
})
consumer.on('producerclose', () => {
console.log('transport closed')
})
const params = {
id: consumer.id,
producerId: producer.id,
kind: consumer.kind,
rtpParameters: consumer.rtpParameters
}
callback({ params })
}
}catch(error){
console.log(error)
callback({
params: {
error: error
}
})
}
})
socket.on('resume', async ({ roomId }) => {
console.log("resuming...")
await consumer.resume()
})
})
If you need more context please contact me, I am very appreciative of any help… I’ve been stuck for a couple of days now.