Hello, I am trying to get plainrtp as an outgoing rtp endpoint to be captured by an external program. Here is my code:
type or paste const mediasoup = require('mediasoup');
const fs = require('fs');
const https = require('https');
const express = require('express');
const socketIO = require('socket.io');
const config = require('./config');
// Global variables
let worker;
let webServer;
let socketServer;
let expressApp;
let producer;
let consumer;
let producerTransport;
let consumerTransport;
let mediasoupRouter;
(async () => {
try {
await runExpressApp();
await runWebServer();
await runSocketServer();
await runMediasoupWorker();
} catch (err) {
console.error(err);
}
})();
async function runExpressApp() {
expressApp = express();
expressApp.use(express.json());
expressApp.use(express.static(__dirname));
expressApp.use((error, req, res, next) => {
if (error) {
console.warn('Express app error,', error.message);
error.status = error.status || (error.name === 'TypeError' ? 400 : 500);
res.statusMessage = error.message;
res.status(error.status).send(String(error));
} else {
next();
}
});
}
async function runWebServer() {
const { sslKey, sslCrt } = config;
if (!fs.existsSync(sslKey) || !fs.existsSync(sslCrt)) {
console.error('SSL files are not found. check your config.js file');
process.exit(0);
}
const tls = {
cert: fs.readFileSync(sslCrt),
key: fs.readFileSync(sslKey),
};
webServer = https.createServer(tls, expressApp);
webServer.on('error', (err) => {
console.error('starting web server failed:', err.message);
});
await new Promise((resolve) => {
const { listenIp, listenPort } = config;
webServer.listen(listenPort, listenIp, () => {
const listenIps = config.mediasoup.webRtcTransport.listenIps[0];
const ip = listenIps.announcedIp || listenIps.ip;
console.log('server is running');
console.log(`open https://${ip}:${listenPort} in your web browser`);
resolve();
});
});
}
async function runSocketServer() {
socketServer = socketIO(webServer, {
serveClient: false,
path: '/server',
log: false,
});
socketServer.on('connection', (socket) => {
console.log('client connected');
// inform the client about existence of producer
if (producer) {
socket.emit('newProducer');
}
socket.on('disconnect', () => {
console.log('client disconnected');
});
socket.on('connect_error', (err) => {
console.error('client connection error', err);
});
socket.on('getRouterRtpCapabilities', (data, callback) => {
callback(mediasoupRouter.rtpCapabilities);
});
socket.on('startRecording', async (data, callback) => {
callback(await startRecording());
});
socket.on('createProducerTransport', async (data, callback) => {
try {
const { transport, params } = await createWebRtcTransport();
producerTransport = transport;
callback(params);
} catch (err) {
console.error(err);
callback({ error: err.message });
}
});
socket.on('createConsumerTransport', async (data, callback) => {
try {
const { transport, params } = await createWebRtcTransport();
consumerTransport = transport;
callback(params);
} catch (err) {
console.error(err);
callback({ error: err.message });
}
});
socket.on('connectProducerTransport', async (data, callback) => {
await producerTransport.connect({ dtlsParameters: data.dtlsParameters });
callback();
});
socket.on('connectConsumerTransport', async (data, callback) => {
await consumerTransport.connect({ dtlsParameters: data.dtlsParameters });
callback();
});
socket.on('produce', async (data, callback) => {
const {kind, rtpParameters} = data;
producer = await producerTransport.produce({ kind, rtpParameters });
callback({ id: producer.id });
// inform clients about new producer
socket.broadcast.emit('newProducer');
});
socket.on('consume', async (data, callback) => {
callback(await createConsumer(producer, data.rtpCapabilities));
});
socket.on('resume', async (data, callback) => {
await consumer.resume();
callback();
});
});
}
async function runMediasoupWorker() {
worker = await mediasoup.createWorker({
logLevel: config.mediasoup.worker.logLevel,
logTags: config.mediasoup.worker.logTags,
rtcMinPort: config.mediasoup.worker.rtcMinPort,
rtcMaxPort: config.mediasoup.worker.rtcMaxPort,
});
worker.on('died', () => {
console.error('mediasoup worker died, exiting in 2 seconds... [pid:%d]', worker.pid);
setTimeout(() => process.exit(1), 2000);
});
const mediaCodecs = config.mediasoup.router.mediaCodecs;
mediasoupRouter = await worker.createRouter({ mediaCodecs });
}
async function createWebRtcTransport() {
const {
maxIncomingBitrate,
initialAvailableOutgoingBitrate
} = config.mediasoup.webRtcTransport;
const transport = await mediasoupRouter.createWebRtcTransport({
listenIps: config.mediasoup.webRtcTransport.listenIps,
enableUdp: true,
enableTcp: true,
preferUdp: true,
initialAvailableOutgoingBitrate,
});
if (maxIncomingBitrate) {
try {
await transport.setMaxIncomingBitrate(maxIncomingBitrate);
} catch (error) {
}
}
return {
transport,
params: {
id: transport.id,
iceParameters: transport.iceParameters,
iceCandidates: transport.iceCandidates,
dtlsParameters: transport.dtlsParameters
},
};
}
async function createConsumer(producer, rtpCapabilities) {
if (!mediasoupRouter.canConsume(
{
producerId: producer.id,
rtpCapabilities,
})
) {
console.error('can not consume');
return;
}
try {
consumer = await consumerTransport.consume({
producerId: producer.id,
rtpCapabilities,
paused: producer.kind === 'video',
});
} catch (error) {
console.error('consume failed', error);
return;
}
if (consumer.type === 'simulcast') {
await consumer.setPreferredLayers({ spatialLayer: 2, temporalLayer: 2 });
}
return {
producerId: producer.id,
id: consumer.id,
kind: consumer.kind,
rtpParameters: consumer.rtpParameters,
type: consumer.type,
producerPaused: consumer.producerPaused
};
}
async function startRecording() {
const router = config.mediasoup.router;
// Start mediasoup's RTP consumer(s)
const rtpTransport = await mediasoupRouter.createPlainTransport({
// No RTP will be received from the remote side
comedia: false,
// FFmpeg and GStreamer don't support RTP/RTCP multiplexing ("a=rtcp-mux" in SDP)
rtcpMux: false,
...config.mediasoup.plainRtpTransport
});
router.videoTransport = rtpTransport;
await rtpTransport.connect({
ip: config.mediasoup.recording.ip,
port: config.mediasoup.recording.videoPort,
rtcpPort: config.mediasoup.recording.videoPortRtcp
});
console.log(
"mediasoup VIDEO RTP SEND transport connected: %s:%d <--> %s:%d (%s)",
rtpTransport.tuple.localIp,
rtpTransport.tuple.localPort,
rtpTransport.tuple.remoteIp,
rtpTransport.tuple.remotePort,
rtpTransport.tuple.protocol
);
console.log(
"mediasoup VIDEO RTCP SEND transport connected: %s:%d <--> %s:%d (%s)",
rtpTransport.rtcpTuple.localIp,
rtpTransport.rtcpTuple.localPort,
rtpTransport.rtcpTuple.remoteIp,
rtpTransport.rtcpTuple.remotePort,
rtpTransport.rtcpTuple.protocol
);
const rtpConsumer = await rtpTransport.consume({
producerId: producer.id,
rtpCapabilities: mediasoupRouter.rtpCapabilities, // Assume the recorder supports same formats as mediasoup's router
paused: false
});
router.videoConsumer = rtpConsumer;
console.log(
"mediasoup VIDEO RTP SEND consumer created, kind: %s, type: %s, paused: %s, SSRC: %s CNAME: %s",
rtpConsumer.kind,
rtpConsumer.type,
rtpConsumer.paused,
rtpConsumer.rtpParameters.encodings[0].ssrc,
rtpConsumer.rtpParameters.rtcp.cname
);
// const consumer = router.videoConsumer;
router.videoConsumer.resume();
}
I am able to connect, publish, but when i try to record i get this and nothing is sent to the UDP ports. I checked netstat -an | grep 500 to see if the ports are being consumed but i get nothing on the data ports. Am i missing anything in the startRecording() function ? Thank you
LOGS seen on NODE CONSOLE:
client connected
mediasoup VIDEO RTP SEND transport connected: 127.0.0.1:10099 <–> 127.0.0.1:5006 (udp)
mediasoup VIDEO RTCP SEND transport connected: 127.0.0.1:10051 <–> 127.0.0.1:5007 (udp)
mediasoup VIDEO RTP SEND consumer created, kind: video, type: simple, paused: false, SSRC: 490767103 CNAME: v0DsId7KomagyQsQ
netstat -an | grep 10017
udp 0 0 127.0.0.1:10017 0.0.0.0:*
root@cdn-03:/opt/mediasoup-sample-app# netstat -an | grep 10057
udp 0 0 127.0.0.1:10057 0.0.0.0:*
root@cdn-03:/opt/mediasoup-sample-app# netstat -an | grep 10057
udp 0 0 127.0.0.1:10057 0.0.0.0:*
netstat -an | grep 5005 -> NOTHING
netstat -an | grep 5006 -> NOTHING
netstat -an | grep 5007 -> NOTHING