diff --git a/.env b/.env new file mode 100644 index 0000000..58d58e3 --- /dev/null +++ b/.env @@ -0,0 +1,3 @@ +PORT=3000 +IP=0.0.0.0# Listening IPv4 or IPv6. +ANNOUNCED_IP=127.0.0.1 # Announced IPv4 or IPv6 (useful when running mediasoup behind NAT with private IP). \ No newline at end of file diff --git a/app.js b/app.js index 51421d2..9a7e2a2 100644 --- a/app.js +++ b/app.js @@ -1,3 +1,5 @@ +import 'dotenv/config' + /** * integrating mediasoup server with a node.js application */ @@ -22,7 +24,7 @@ let consumerTransport let producer let consumer -app.get('/', (req, res) => { +app.get('/', (_req, res) => { res.send('Hello from mediasoup app!') }) @@ -35,8 +37,9 @@ const options = { } const httpsServer = https.createServer(options, app) -httpsServer.listen(3000, () => { - console.log('listening on port: ' + 3000) + +httpsServer.listen(process.env.PORT, () => { + console.log('Listening on port:', process.env.PORT) }) const io = new Server(httpsServer) @@ -58,11 +61,11 @@ const createWorker = async () => { rtcMinPort: 2000, rtcMaxPort: 2020, }) - console.log(`worker pid ${worker.pid}`) + console.log(`[createWorker] worker pid ${worker.pid}`) worker.on('died', error => { // This implies something serious happened, so kill the application - console.error('mediasoup worker has died') + console.error('mediasoup worker has died', error) setTimeout(() => process.exit(1), 2000) // exit in 2 seconds }) @@ -94,11 +97,13 @@ const mediaCodecs = [ ] peers.on('connection', async socket => { - console.log(socket.id) - socket.emit('connection-success', { - socketId: socket.id, - existsProducer: producer ? true : false, - }) + console.log('[connection] socketId:', socket.id) + setTimeout(() => { + socket.emit('connection-success', { + socketId: socket.id, + existsProducer: producer ? true : false, + }) + }, 1000); socket.on('disconnect', () => { // do some cleanup @@ -113,7 +118,7 @@ peers.on('connection', async socket => { // appData -> custom application data - we are not supplying any // none of the two are required router[callId] = await worker.createRouter({ mediaCodecs }) - console.log(`Router ID: ${router[callId].id}`) + console.log(`[createRoom] Router ID: ${router[callId].id}`) } getRtpCapabilities(callId, callback) @@ -128,7 +133,7 @@ peers.on('connection', async socket => { // Client emits a request to create server side Transport // We need to differentiate between the producer and consumer transports socket.on('createWebRtcTransport', async ({ sender, callId }, callback) => { - console.log(`Is this a sender request? ${sender} | callId ${callId}`) + console.log(`[createWebRtcTransport] Is this a sender request? ${sender} | callId ${callId}`) // The client indicates if it is a producer or a consumer // if sender is true, indicates a producer else a consumer if (sender) @@ -139,7 +144,7 @@ peers.on('connection', async socket => { // see client's socket.emit('transport-connect', ...) socket.on('transport-connect', async ({ dtlsParameters }) => { - console.log('DTLS PARAMS... ', { dtlsParameters }) + console.log('[transport-connect] DTLS PARAMS... ', { dtlsParameters }) await producerTransport.connect({ dtlsParameters }) }) @@ -151,7 +156,7 @@ peers.on('connection', async socket => { rtpParameters, }) - console.log('Producer ID: ', producer.id, producer.kind) + console.log(`[transport-produce] Producer ID: ${producer.id} | kind: ${producer.kind}`) producer.on('transportclose', () => { console.log('transport for this producer closed ') @@ -166,7 +171,7 @@ peers.on('connection', async socket => { // see client's socket.emit('transport-recv-connect', ...) socket.on('transport-recv-connect', async ({ dtlsParameters }) => { - console.log(`DTLS PARAMS: ${dtlsParameters}`) + console.log(`[transport-recv-connect] DTLS PARAMS: ${dtlsParameters}`) await consumerTransport.connect({ dtlsParameters }) }) @@ -215,30 +220,29 @@ peers.on('connection', async socket => { }) socket.on('consumer-resume', async () => { - console.log('consumer resume') + console.log(`[consumer-resume]`) await consumer.resume() }) }) const createWebRtcTransportLayer = async (callId, callback) => { try { - console.log('createWebRtcTransportLayer | callId', callId); // https://mediasoup.org/documentation/v3/mediasoup/api/#WebRtcTransportOptions const webRtcTransport_options = { listenIps: [ { - ip: '0.0.0.0', // replace with relevant IP address - announcedIp: '127.0.0.1', + ip: process.env.IP, // Listening IPv4 or IPv6. + announcedIp: process.env.ANNOUNCED_IP, // Announced IPv4 or IPv6 (useful when running mediasoup behind NAT with private IP). } ], enableUdp: true, enableTcp: true, preferUdp: true, } - console.log('🔴 router[callId]', JSON.stringify(router)); + // https://mediasoup.org/documentation/v3/mediasoup/api/#router-createWebRtcTransport let transport = await router[callId].createWebRtcTransport(webRtcTransport_options) - console.log(`transport id: ${transport.id}`) + console.log(`callId: ${callId} | transport id: ${transport.id}`) transport.on('dtlsstatechange', dtlsState => { if (dtlsState === 'closed') { @@ -264,7 +268,6 @@ const createWebRtcTransportLayer = async (callId, callback) => { return transport } catch (error) { - console.log('11111', error) callback({ params: { error: error diff --git a/package-lock.json b/package-lock.json index 265da6f..c4adf31 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "1.0.0", "license": "ISC", "dependencies": { + "dotenv": "^16.0.1", "express": "^4.18.1", "httpolyglot": "^0.1.2", "mediasoup": "^3.10.4", @@ -919,6 +920,14 @@ "npm": ">=1.2" } }, + "node_modules/dotenv": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.1.tgz", + "integrity": "sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ==", + "engines": { + "node": ">=12" + } + }, "node_modules/duplexer2": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", @@ -4263,6 +4272,11 @@ "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", "dev": true }, + "dotenv": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.1.tgz", + "integrity": "sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ==" + }, "duplexer2": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", diff --git a/package.json b/package.json index 70291eb..704a4af 100644 --- a/package.json +++ b/package.json @@ -13,12 +13,15 @@ "license": "ISC", "type": "module", "dependencies": { + "dotenv": "^16.0.1", "express": "^4.18.1", "httpolyglot": "^0.1.2", "mediasoup": "^3.10.4", "mediasoup-client": "^3.6.54", "socket.io": "^2.0.3", - "socket.io-client": "^2.0.3" + "socket.io-client": "^2.0.3", + "nodemon": "^2.0.19", + "watchify": "^4.0.0" }, "devDependencies": { "nodemon": "^2.0.19", diff --git a/public/bundle.js b/public/bundle.js index 498634a..19283b6 100644 --- a/public/bundle.js +++ b/public/bundle.js @@ -20651,22 +20651,45 @@ yeast.decode = decode; module.exports = yeast; },{}],95:[function(require,module,exports){ +module.exports = { + hubAddress: 'https://hub.dev.linx.safemobile.com/', + mediasoupAddress: 'https://localhost:3000/mediasoup', +} +},{}],96:[function(require,module,exports){ const io = require('socket.io-client') const mediasoupClient = require('mediasoup-client') const urlParams = new URLSearchParams(location.search); +const config = require('./config') +console.log('[CONFIG]', config); const ASSET_ID = parseInt(urlParams.get('assetId')) || null; const ACCOUNT_ID = parseInt(urlParams.get('accountId')) || null; let callId = parseInt(urlParams.get('callId')) || null; const IS_PRODUCER = urlParams.get('producer') === 'true' ? true : false -console.log('ASSET_ID', ASSET_ID, '| ACCOUNT_ID', ACCOUNT_ID, '| callId', callId, ' | IS_PRODUCER', IS_PRODUCER) +console.log('[URL] ASSET_ID', ASSET_ID, '| ACCOUNT_ID', ACCOUNT_ID, '| callId', callId, ' | IS_PRODUCER', IS_PRODUCER) let socket -hub = io('https://hub.dev.linx.safemobile.com/') +hub = io(config.hubAddress) + +const connectToMediasoup = () => { + + socket = io(config.mediasoupAddress) + + socket.on('connection-success', ({ _socketId, existsProducer }) => { + console.log(`[MEDIA] ${config.mediasoupAddress} | connected: ${socket.connected} | existsProducer: ${existsProducer}`) + if (!IS_PRODUCER && existsProducer && consumer === undefined) { + goConnect() + // document.getElementById('btnRecvSendTransport').click(); + } + if (IS_PRODUCER && urlParams.get('testing') === 'true') { getLocalStream() } + }) +} if (IS_PRODUCER === true) { hub.on('connect', async () => { - console.log('hub.connected', hub.connected); + console.log(`[HUB] ${config.hubAddress} | connected: ${hub.connected}`) + connectToMediasoup() + hub.emit( 'ars', JSON.stringify({ @@ -20689,11 +20712,6 @@ if (IS_PRODUCER === true) { if (parsedData.type === 'notify-request' && IS_PRODUCER) { getLocalStream() } - - // setTimeout(() => { - // !IS_PRODUCER && goConnect() - // }, 1000); - // getRtpCapabilities() }) }) @@ -20708,23 +20726,10 @@ if (IS_PRODUCER === true) { hub.on('disconnect', () => { console.log('disconnect') }) +} else { + connectToMediasoup() } - -socket = io('https://localhost:3000/mediasoup') - -socket.on('connection-success', ({ socketId, existsProducer }) => { - console.log(socketId, existsProducer) - // if (IS_PRODUCER) { getLocalStream() } - // setInterval(() => { - // if (!IS_PRODUCER && existsProducer) { goConnect() } - - // }, 5000); - if (!IS_PRODUCER && existsProducer && consumer === undefined) { goConnect() } -}) - - - let device let rtpCapabilities let producerTransport @@ -20769,11 +20774,11 @@ const streamSuccess = (stream) => { track, ...params } - goConnect() } const getLocalStream = () => { + console.log('[getLocalStream]'); navigator.mediaDevices.getUserMedia({ audio: false, video: { @@ -20925,7 +20930,7 @@ const connectSendTransport = async () => { const answer = { origin_asset_id: ASSET_ID, - dest_asset_id: originAssetId, + dest_asset_id: originAssetId || parseInt(urlParams.get('dest_asset_id')), type: 'notify-answer', origin_asset_priority: 1, origin_asset_type_name: originAssetTypeName, @@ -20978,7 +20983,6 @@ const createRecvTransport = async () => { errback(error) } }) - connectRecvTransport() }) } @@ -20997,7 +21001,6 @@ const connectRecvTransport = async () => { return } - console.log(params) // then consume with the local consumer transport // which creates a consumer consumer = await consumerTransport.consume({ @@ -21010,16 +21013,16 @@ const connectRecvTransport = async () => { // destructure and retrieve the video track from the producer const { track } = consumer - const stream = new MediaStream([track]) + let stream = new MediaStream() + stream.addTrack(track) + // stream.removeTrack(track) remoteVideo.srcObject = stream - - // the server consumer started with media paused - // so we need to inform the server to resume socket.emit('consumer-resume') console.log('consumer', consumer); + }) } btnLocalVideo.addEventListener('click', getLocalStream) btnRecvSendTransport.addEventListener('click', goConnect) -},{"mediasoup-client":67,"socket.io-client":83}]},{},[95]); +},{"./config":95,"mediasoup-client":67,"socket.io-client":83}]},{},[96]); diff --git a/public/config.js b/public/config.js new file mode 100644 index 0000000..fe79e7b --- /dev/null +++ b/public/config.js @@ -0,0 +1,4 @@ +module.exports = { + hubAddress: 'https://hub.dev.linx.safemobile.com/', + mediasoupAddress: 'https://localhost:3000/mediasoup', +} \ No newline at end of file diff --git a/public/index.html b/public/index.html index 6a6ddae..ce0d73a 100644 --- a/public/index.html +++ b/public/index.html @@ -55,6 +55,9 @@ + +
+