Compare commits

...

14 Commits

Author SHA1 Message Date
32692f2390 replace classic build for docker 2025-04-03 21:19:15 +00:00
755df1ec5a Merge pull request 'LINXD-2850: Add handler on icestatechange failed/disconnected to send 'connection-failed' event to participants' (#39) from LINXD-2850-connection-failed-handler into develop
Reviewed-on: #39
Reviewed-by: Cristi Ene <cristi.ene@safemobile.com>
2025-03-12 15:22:30 +00:00
cd91d40dd0 LINXD-2850: Added image in doc 2025-03-12 09:56:09 +02:00
642dba8dac LINXD-2850: Add handler on icestatechange failed/disconnected to send 'connection-failed' event to participants 2025-03-12 09:31:36 +02:00
4f044555ba Merge pull request 'Update node version in Dockerfile' (#38) from update-build into develop
Reviewed-on: #38
2025-03-07 09:35:02 +00:00
230d5b6bce Merge branch 'develop' into update-build 2025-03-07 09:34:33 +00:00
73c7700ded Update node version in Dockerfile 2025-03-07 11:33:47 +02:00
9e66772b53 Merge pull request 'update-build' (#37) from update-build into develop
Reviewed-on: #37
2025-03-07 09:14:06 +00:00
5ef66af3f8 Update build.sh 2025-03-07 11:12:56 +02:00
1b29d43580 Update build.sh 2025-03-07 11:12:12 +02:00
dd5af12c7c Merge pull request 'LINXD-2842-log-protocol-change' (#36) from LINXD-2842-log-protocol-change into develop
Reviewed-on: #36
Reviewed-by: Cristi Ene <cristi.ene@safemobile.com>
2025-03-05 21:40:24 +00:00
af21774d17 LINXD-2842: Update mediasoup version; Add handler for icestatechange; Add env PREFER_TCP; Add 3s ICE consent timeout 2025-03-05 23:37:35 +02:00
fc250c248e LINXD-2842: Update README 2025-03-04 17:01:54 +02:00
fc39d5bead LINXD-2842: Log message when protocol is changed 2025-03-03 22:30:41 +02:00
8 changed files with 1166 additions and 53 deletions

1
.env
View File

@ -8,3 +8,4 @@ SERVER_KEY="./server/ssl/key.pem"
ENABLE_UDP=true ENABLE_UDP=true
ENABLE_TCP=true ENABLE_TCP=true
PREFER_UDP=true PREFER_UDP=true
PREFER_TCP=false

View File

@ -5,7 +5,7 @@ WORKDIR /app
RUN apt-get update && \ RUN apt-get update && \
apt-get install -y build-essential pip net-tools iputils-ping iproute2 curl apt-get install -y build-essential pip net-tools iputils-ping iproute2 curl
RUN curl -fsSL https://deb.nodesource.com/setup_18.x | bash - RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
RUN apt-get install -y nodejs RUN apt-get install -y nodejs
COPY . /app/ COPY . /app/

View File

@ -38,22 +38,22 @@
##### To start in production mode you must: ##### To start in production mode you must:
1. Install the dependencies `npm install`. 1. Install the dependencies `npm install`.
2. Run the `npm start:prod` command to start the server in production mode. 2. Run the `npm start:prod` command to start the server in production mode.
(To connect to the terminal, use `pm2 log video-server`) (To connect to the terminal, use `pm2 log video-server`)
### Web client ### Web client
- The server will start by default on port 3000, and the ssl certificates will have to be configured - The server will start by default on port 3000, and the ssl certificates will have to be configured
- The web client can be accessed using the /sfu path - The web client can be accessed using the /sfu path
ex: https://HOST/sfu/?assetId=1&&accountId=1&producer=true&dest_asset_id=75&assetName=Adi ex: https://HOST/sfu/?assetId=1&&accountId=1&producer=true&dest_asset_id=75&assetName=Adi
assetId = asset id of the unit on which you are doing the test assetId = asset id of the unit on which you are doing the test
accountId = account id of the unit on which you are doing the test accountId = account id of the unit on which you are doing the test
producer = it will always be true because you are the producer producer = it will always be true because you are the producer
(it's possible to put false, but then you have to have another client with producer true) (it's possible to put false, but then you have to have another client with producer true)
assetName = asset name of the unit on which you are doing the test assetName = asset name of the unit on which you are doing the test
dest_asset_id= the addressee with whom the call is made dest_asset_id= the addressee with whom the call is made
- To make a call using this client, you need a microphone and permission to use it - To make a call using this client, you need a microphone and permission to use it
- For any changes related to the client, the command `npm run watch' will have to be used to generate the bundle.js used by the web client - For any changes related to the client, the command `npm run watch' will have to be used to generate the bundle.js used by the web client
### Demo project ### Demo project
The demo project used initially and then modified for our needs `https://github.com/jamalag/mediasoup2` The demo project used initially and then modified for our needs `https://github.com/jamalag/mediasoup2`

40
app.js
View File

@ -12,6 +12,11 @@ try {
console.log('https support is disabled!'); console.log('https support is disabled!');
} }
const mediasoup = require('mediasoup'); const mediasoup = require('mediasoup');
const isUdpEnabled = process.env.ENABLE_UDP === 'true';
const isTcpEnabled = process.env.ENABLE_TCP === 'true';
const isUdpPreferred = process.env.PREFER_UDP === 'true';
const isTcpPreferred = process.env.PREFER_TCP === 'true';
let currentConnectionType = isUdpPreferred ? 'udp' : 'tcp';
let worker; let worker;
/** /**
@ -537,6 +542,15 @@ const isInitiator = (callId, socketId) => {
return videoCalls[callId]?.initiatorSocket?.id === socketId; return videoCalls[callId]?.initiatorSocket?.id === socketId;
}; };
const emitToParticipants = (callId, event, message) => {
try {
videoCalls[callId].receiverSocket.emit(event, message);
videoCalls[callId].initiatorSocket.emit(event, message);
} catch (error) {
console.error(`[emitToParticipants] | ERROR | callId: ${callId} | error: ${error.message}`);
}
}
/* /*
- Called from at event 'createWebRtcTransport' and assigned to the consumer or producer transport - Called from at event 'createWebRtcTransport' and assigned to the consumer or producer transport
- It will return parameters, these are required for the client to create the RecvTransport - It will return parameters, these are required for the client to create the RecvTransport
@ -555,14 +569,34 @@ const createWebRtcTransportLayer = async (callId, callback) => {
announcedIp: process.env.ANNOUNCED_IP, // Announced IPv4 or IPv6 (useful when running mediasoup behind NAT with private IP). announcedIp: process.env.ANNOUNCED_IP, // Announced IPv4 or IPv6 (useful when running mediasoup behind NAT with private IP).
}, },
], ],
enableUdp: process.env.ENABLE_UDP === 'true', enableUdp: isUdpEnabled,
enableTcp: process.env.ENABLE_TCP === 'true', enableTcp: isTcpEnabled,
preferUdp: process.env.PREFER_UDP === 'true', preferUdp: isUdpPreferred,
preferTcp: isTcpPreferred,
iceConsentTimeout: 3
}; };
// https://mediasoup.org/documentation/v3/mediasoup/api/#router-createWebRtcTransport // https://mediasoup.org/documentation/v3/mediasoup/api/#router-createWebRtcTransport
let transport = await videoCalls[callId].router.createWebRtcTransport(webRtcTransport_options); let transport = await videoCalls[callId].router.createWebRtcTransport(webRtcTransport_options);
// `iceselectedtuplechange`: Fires when ICE switches transport (e.g., UDP → TCP).
transport.on('iceselectedtuplechange', (selectedTuple) => {
const { protocol } = selectedTuple;
if (currentConnectionType !== protocol) {
console.warn(`⚠️ ${currentConnectionType.toUpperCase()} blocked! Switching to ${protocol.toUpperCase()} for callId: ${callId}`);
currentConnectionType = protocol;
}
});
// `icestatechange`: Fires when ICE connection state changes (e.g., new, connected, failed).
transport.on('icestatechange', (iceState) => {
console.log(`[ICE STATE CHANGE] callId: ${callId} | State: ${iceState}`);
if (iceState === 'failed' || iceState === 'disconnected') {
console.warn(`⚠️ ICE failure detected for callId: ${callId}! Possible UDP blockage.`);
emitToParticipants(callId, 'connection-failed', { callId });
}
});
// Handler for when DTLS(Datagram Transport Layer Security) changes // Handler for when DTLS(Datagram Transport Layer Security) changes
transport.on('dtlsstatechange', (dtlsState) => { transport.on('dtlsstatechange', (dtlsState) => {
console.log(`transport | dtlsstatechange | calldId ${callId} | dtlsState ${dtlsState}`); console.log(`transport | dtlsstatechange | calldId ${callId} | dtlsState ${dtlsState}`);

View File

@ -56,7 +56,7 @@ fi
## PROJECT NEEDS ## PROJECT NEEDS
echo "Building app... from $(git rev-parse --abbrev-ref HEAD)" echo "Building app... from $(git rev-parse --abbrev-ref HEAD)"
#npm run-script build #npm run-script build
cp -r {.env,app.js,package.json,server,public,doc,Dockerfile} dist/ cp -r {.env,app.js,package.json,server,public,doc,Dockerfile,tsconfig.json,.dockerignore} dist/
#cp -r ./* dist/ #cp -r ./* dist/
# Generate Git log # Generate Git log

Binary file not shown.

After

Width:  |  Height:  |  Size: 215 KiB

1150
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -16,7 +16,7 @@
"@types/express": "^4.17.13", "@types/express": "^4.17.13",
"dotenv": "^16.0.1", "dotenv": "^16.0.1",
"express": "^4.18.1", "express": "^4.18.1",
"mediasoup": "^3.10.4", "mediasoup": "^3.15.5",
"mediasoup-client": "^3.6.54", "mediasoup-client": "^3.6.54",
"parcel": "^2.7.0", "parcel": "^2.7.0",
"socket.io": "^2.0.3", "socket.io": "^2.0.3",