LINXD-2209-black-screen-when-2-video-calls-are-answered-simultaneously #3

Merged
sergiu merged 31 commits from LINXD-2209-black-screen-when-2-video-calls-are-answered-simultaneously into master 2022-09-15 14:49:55 +00:00
Showing only changes of commit 6acd276324 - Show all commits

132
app.js
View File

@ -18,11 +18,7 @@ import Server from 'socket.io'
import mediasoup, { getSupportedRtpCapabilities } from 'mediasoup' import mediasoup, { getSupportedRtpCapabilities } from 'mediasoup'
let worker let worker
let router = {} let videoCalls = {}
let producerTransport
let consumerTransport
let producer
let consumer
app.get('/', (_req, res) => { app.get('/', (_req, res) => {
res.send('Hello from mediasoup app!') res.send('Hello from mediasoup app!')
@ -96,42 +92,16 @@ const mediaCodecs = [
}, },
] ]
let queue = []
// queue.push({
// callId: 1,
// callback: () => console.log('callback')
// })
// queue.push({
// callId: 2,
// callback: () => console.log('callback')
// })
// queue.push({
// callId: 3,
// callback: () => console.log('callback')
// })
const getRtpCapabilities = (callId, callback) => { const getRtpCapabilities = (callId, callback) => {
const rtpCapabilities = router[callId].rtpCapabilities console.log('[getRtpCapabilities] callId', callId);
callback({ rtpCapabilities }) const rtpCapabilities = videoCalls[callId].router.rtpCapabilities;
callback({ rtpCapabilities });
} }
setInterval(async () => {
if (queue.length > 0) {
const { callId, callback } = queue.shift();
if (router[callId] === undefined) {
router[callId] = await worker.createRouter({ mediaCodecs })
console.log(`[createRoom] Router ID: ${router[callId].id}`)
}
getRtpCapabilities(callId, callback)
}
}, 4000);
peers.on('connection', async socket => { peers.on('connection', async socket => {
console.log('[connection] socketId:', socket.id) console.log('[connection] socketId:', socket.id)
socket.emit('connection-success', { socket.emit('connection-success', {
socketId: socket.id, socketId: socket.id
existsProducer: producer ? true : false,
}) })
socket.on('disconnect', () => { socket.on('disconnect', () => {
@ -140,23 +110,12 @@ peers.on('connection', async socket => {
}) })

not important: we don't need socket.id on clients

not important: we don't need socket.id on clients
socket.on('createRoom', async ({ callId }, callback) => { socket.on('createRoom', async ({ callId }, callback) => {
if (videoCalls[callId].router === undefined) {
console.log('[createRoom] callId', callId); console.log('[createRoom] callId', callId);
// console.log('Router length:', Object.keys(router).length); videoCalls[callId].router = await worker.createRouter({ mediaCodecs })
// if (router[callId] === undefined) { console.log(`[createRoom] Router ID: ${videoCalls[callId].router.id}`)
// // worker.createRouter(options) }
// // options = { mediaCodecs, appData } getRtpCapabilities(callId, callback)
// // mediaCodecs -> defined above
// // appData -> custom application data - we are not supplying any
// // none of the two are required
// router[callId] = await worker.createRouter({ mediaCodecs })
// console.log(`[createRoom] Router ID: ${router[callId].id}`)
// }
// getRtpCapabilities(callId, callback)
queue.push({
callId,
callback
})
}) })
// Client emits a request to create server side Transport // Client emits a request to create server side Transport
@ -166,88 +125,88 @@ peers.on('connection', async socket => {
// The client indicates if it is a producer or a consumer // The client indicates if it is a producer or a consumer
// if sender is true, indicates a producer else a consumer // if sender is true, indicates a producer else a consumer
if (sender) if (sender)
producerTransport = await createWebRtcTransportLayer(callId, callback) videoCalls[callId].producerTransport = await createWebRtcTransportLayer(callId, callback)
else else
consumerTransport = await createWebRtcTransportLayer(callId, callback) videoCalls[callId].consumerTransport = await createWebRtcTransportLayer(callId, callback)
}) })
// see client's socket.emit('transport-connect', ...) // see client's socket.emit('transport-connect', ...)
socket.on('transport-connect', async ({ dtlsParameters }) => { socket.on('transport-connect', async ({ dtlsParameters, callId }) => {
console.log('[transport-connect] DTLS PARAMS... ', { dtlsParameters }) console.log('[transport-connect] DTLS PARAMS... ', { dtlsParameters })
await producerTransport.connect({ dtlsParameters }) await videoCalls[callId].producerTransport.connect({ dtlsParameters })
}) })
// see client's socket.emit('transport-produce', ...) // see client's socket.emit('transport-produce', ...)
socket.on('transport-produce', async ({ kind, rtpParameters, appData }) => { socket.on('transport-produce', async ({ kind, rtpParameters, appData, callId }) => {
cristi marked this conversation as resolved Outdated

For refactor: why do we need to differentiate between producerTransport and consumerTransport? Why don't we have a transport variable (it is only one transport for each client regardless if they are producer or consumer)?

For refactor: why do we need to differentiate between producerTransport and consumerTransport? Why don't we have a `transport` variable (it is only one transport for each client regardless if they are producer or consumer)?

We need producer and consumer transports for each call.

We need producer and consumer transports for each call.
// call produce based on the prameters from the client // call produce based on the prameters from the client
producer = await producerTransport.produce({ videoCalls[callId].producer = await videoCalls[callId].producerTransport.produce({
kind, kind,
rtpParameters, rtpParameters,
}) })
console.log(`[transport-produce] Producer ID: ${producer.id} | kind: ${producer.kind}`) console.log(`[transport-produce] Producer ID: ${videoCalls[callId].producer.id} | kind: ${videoCalls[callId].producer.kind}`)
producer.on('transportclose', () => { videoCalls[callId].producer.on('transportclose', () => {
console.log('transport for this producer closed', callId) console.log('transport for this producer closed', callId)
// https://mediasoup.org/documentation/v3/mediasoup/api/#producer-close // https://mediasoup.org/documentation/v3/mediasoup/api/#producer-close
producer.close() videoCalls[callId].producer.close()
// https://mediasoup.org/documentation/v3/mediasoup/api/#router-close // https://mediasoup.org/documentation/v3/mediasoup/api/#router-close
router[callId].close() videoCalls[callId].router.close()
delete router[callId] delete videoCalls[callId]
}) })
}) })
// see client's socket.emit('transport-recv-connect', ...) // see client's socket.emit('transport-recv-connect', ...)
socket.on('transport-recv-connect', async ({ dtlsParameters }) => { socket.on('transport-recv-connect', async ({ dtlsParameters, callId }) => {
console.log(`[transport-recv-connect] DTLS PARAMS: ${dtlsParameters}`) console.log(`[transport-recv-connect] DTLS PARAMS: ${dtlsParameters}`)
await consumerTransport.connect({ dtlsParameters }) await videoCalls[callId].consumerTransport.connect({ dtlsParameters })
}) })
socket.on('consume', async ({ rtpCapabilities, callId }, callback) => { socket.on('consume', async ({ rtpCapabilities, callId }, callback) => {
console.log('[consume] callId', callId, router); console.log('[consume] callId', callId);
try { try {
// console.log('consume', rtpCapabilities, callId); // console.log('consume', rtpCapabilities, callId);
// check if the router can consume the specified producer // check if the router can consume the specified producer
if (router[callId].canConsume({ if (videoCalls[callId].router.canConsume({
producerId: producer.id, producerId: videoCalls[callId].producer.id,
rtpCapabilities rtpCapabilities
})) { })) {
console.log('[consume] Can consume', callId); console.log('[consume] Can consume', callId);
// transport can now consume and return a consumer // transport can now consume and return a consumer
consumer = await consumerTransport.consume({ videoCalls[callId].consumer = await videoCalls[callId].consumerTransport.consume({
producerId: producer.id, producerId: videoCalls[callId].producer.id,
rtpCapabilities, rtpCapabilities,
paused: true, paused: true,
}) })
consumer.on('transportclose', () => { videoCalls[callId].consumer.on('transportclose', () => {
console.log('transport close from consumer', callId) console.log('transport close from consumer', callId)
// https://mediasoup.org/documentation/v3/mediasoup/api/#router-close // https://mediasoup.org/documentation/v3/mediasoup/api/#router-close
router[callId].close() stvideoCallsate[callId].router.close()
delete router[callId] delete videoCalls[callId].router
producer.close() videoCalls[callId].producer.close()
consumer.close() videoCalls[callId].consumer.close()
}) })
consumer.on('producerclose', () => { videoCalls[callId].consumer.on('producerclose', () => {
console.log('producer of consumer closed', callId) console.log('producer of consumer closed', callId)
// https://mediasoup.org/documentation/v3/mediasoup/api/#router-close // https://mediasoup.org/documentation/v3/mediasoup/api/#router-close
router[callId].close() videoCalls[callId].router.close()
delete router[callId] delete videoCalls[callId].router
producer.close() videoCalls[callId].producer.close()
consumer.close() videoCalls[callId].consumer.close()
}) })
// from the consumer extract the following params // from the consumer extract the following params
// to send back to the Client // to send back to the Client
const params = { const params = {
id: consumer.id, id: videoCalls[callId].consumer.id,
producerId: producer.id, producerId: videoCalls[callId].producer.id,
kind: consumer.kind, kind: videoCalls[callId].consumer.kind,
rtpParameters: consumer.rtpParameters, rtpParameters: videoCalls[callId].consumer.rtpParameters,
} }
// send the parameters to the client // send the parameters to the client
@ -265,9 +224,9 @@ peers.on('connection', async socket => {
} }
}) })
socket.on('consumer-resume', async () => { socket.on('consumer-resume', async ({ callId }) => {
console.log(`[consumer-resume]`) console.log(`[consumer-resume]`)
await consumer.resume() await videoCalls[callId].consumer.resume()
}) })
}) })
@ -288,10 +247,9 @@ const createWebRtcTransportLayer = async (callId, callback) => {
} }
// console.log('webRtcTransport_options', webRtcTransport_options); // console.log('webRtcTransport_options', webRtcTransport_options);
// console.log('router', router, '| router[callId]', router[callId]);
// https://mediasoup.org/documentation/v3/mediasoup/api/#router-createWebRtcTransport // https://mediasoup.org/documentation/v3/mediasoup/api/#router-createWebRtcTransport
let transport = await router[callId].createWebRtcTransport(webRtcTransport_options) let transport = await videoCalls[callId].router.createWebRtcTransport(webRtcTransport_options)
console.log(`callId: ${callId} | transport id: ${transport.id}`) console.log(`callId: ${callId} | transport id: ${transport.id}`)
transport.on('dtlsstatechange', dtlsState => { transport.on('dtlsstatechange', dtlsState => {