Nodejs - RTSP live camera feed - distributed architecture - node.js

We have a requirement where we pass the camera details and need to show the live stream to the end-user in a web browser. As this is distributed architecture, so we can do it using the Rest API only or socket communication.
Technology stack
Nodejs - at Backend
Angular - at frontend
As part of the solution, I found npm - node-rtsp-stream - https://www.npmjs.com/package/node-rtsp-stream but problem is that we have to create the API and pass the stream in api, have at least 20-30 camera to see the live stream. Pass the port from the frontend and use it at the backend.
Problem -
How to stop the stream as the user click on the pause button, I have tried with API - '/camera/feed/stop/:port' but it is not working?
As creating API for the stream, there is a high chance that the stream gets mixed up, and how to manage the ws port?
Any better solution to show the stream on the client-side using the RTSP URL
I tried the below solution, but no luck
const Stream = require('node-rtsp-stream');
app.get('/camera/feed/:camera/:port', (req, res) => {
console.log(req.params.port);
if (req.params.camera == 1) {
var ip_address2 = "192.168.1.12"
var username2 = "admin";
var password2 = "admin";
} else if (req.params.camera == 2) {
var ip_address2 = "192.168.1.10"
var username2 = "admin";
var password2 = "admin";
}
stream = new Stream({
streamUrl: 'rtsp://' + username2 + ':' + password2 + '#' + ip_address2 + ':554/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif',
wsPort: req.params.port
});
res.send('OK');
});
// Stop the stream that produce using ffmpeg
app.get('/camera/feed/stop/:port', (req, res) => {
stream.stop() // This is not make ffmpeg to stop the processing stream
res.send('OK');
});
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`)
})
index.html
var canvas3 = document.getElementById('canvas3');
var websocket = new WebSocket("ws://127.0.0.1:9999");
var player3 = new jsmpeg(websocket, { canvas: canvas3, autoplay: true, loop: true })
Thank you.

I found the solution. Passing the stream object in API response and this contains the PID res.send(stream); For the stop/kill the FFmpeg process we can use the PID from the frontend kill(req.params.pid);

For pausing the stream, you can use the stop() method in player, player3.stop()

Related

Socket.Io not emitting immediately after first emit (order important)

Environment:
Backend
node:latest
socket.io | 4.5.2
Frontend
React Native | 0.70.4
socket.io-client | 4.6.0
both Android and iOS
Here is my NodeJs entry file:
const numCPUs = cpus().length
if (cluster.isPrimary) {
const app = express()
const httpServer = http.createServer(app)
setupMaster(httpServer, { loadBalancingMethod: 'least-connection' })
setupPrimary()
for (let i = 0; i < numCPUs; i++) {
cluster.fork()
}
cluster.on('exit', (worker) => {
cluster.fork()
})
} else {
const app = express()
const httpServer = http.createServer(app)
const io = new Server(httpServer, { maxHttpBufferSize: 1e8 })
io.adapter(createAdapter())
setupWorker(io)
API.Socket.init(io, process.pid)
middlewares.forEach((middleware: any) => app.use(middleware))
routes.forEach((route) => app.use(route.path, route.handler))
httpServer.listen(CONFIG.PORT, () => {})
}
I have a simple chat application.
When user A sends message to user B, new chat message and notification is recorded in database. Now that chat message and notification* should be sent to the B user. There are 2 socket emit-functions for that:
sendNewNotification(
notification: BE.Entities.TNotification,
toUser: string,
) {
this.io
?.to(toUser)
.volatile.emit(ECustomEvents.NewNotification, notification)
}
sendPrivateMessage(
toUser: string | Array<string>,
chatMessage: BE.Entities.TChatMessage,
sourceUser: BE.Entities.TUser,
) {
this.io
?.to(toUser)
.volatile.emit(ECustomEvents.PrivateMessage, chatMessage, sourceUser)
}
If I do it like this, the targetUser is not going to receive the event with the newChatMessage however he will receive the savedNotification
API.Socket.sendPrivateMessage(targetUserId, newChatMessage, userToPass)
API.Socket.sendNewNotification(savedNotification, targetUserId)
Now, if I switch these lines:
API.Socket.sendNewNotification(savedNotification, targetUserId)
API.Socket.sendPrivateMessage(targetUserId, newChatMessage, userToPass)
the behavior would be as expected: the target user B will receive both saved notification and new chat message
How is that possible? What could be wrong?
Thank you mates in advance!
With the current information, I'm not so sure the order matters but perhaps that it's a side-effect / coincidence. Are you checking anywhere to make sure the server-side socket is ready before the client emits?
Consider this super simple WebSocket chat sandbox:
One of the issues I noticed when writing this is when the server WebSocket is not ready, I could not emit from the client to the server. To make sure the server is ready, I sent a ping from the server to the client notifying the client that the server is ready:
wss.on("connection", async function connection(client, request) {
console.log("user connected", Date.now());
client.send(JSON.stringify({ ready: true }));
...
});
I also notice you are usingg the volatile.emit which according to the documentation:
Volatile events
Volatile events are events that will not be sent if the underlying connection is not ready (a bit like UDP, in terms of reliability).
This can be interesting for example if you need to send the position of the characters in an online game (as only the latest values are useful).
socket.volatile.emit("hello", "might or might not be received");
The Socket.IO docs have a similar listener which lets you know when the server is ready.
If you prevent the client from emitting until the server is ready, you can avoid this issue. You also should not need to use the volatile.emit for something that must be delivered.

How to grab all events of freeswitch in nodejs

Am newbie in node.js and would like to grab all events types.
In this case i already did my homework.I found from far this one.
In link, Continuosly throwing below error.
Error :
TypeError: esl.createCallServer is not a function
I am expecting : If any call has been started and forward to the gateway.So on the realtime would like to get gateway name in node.js to check which gateway is using
Might be possible,I understand is not correct way but below also one more try to achieve this but that not giving me gateway information.
call_handler = require('seem');
const esl = require("esl");
const port = 4041;
const server = esl.server(call_handler).listen(port);
server.listen(port, function() {
console.log("Server listening for connection requests on socket localhost:"+port);
});
esl.client(call_handler).connect(4050);
server.on("connection", function(chunk) {
console.log("Connection has been established");
chunk.on("data", (data) => {
console.log("Channel Park info");
var data_string = data.toString();
var data_arr= data_string.replace(/\r\n/g, "\r").replace(/\n/g, "\r").split(/\r/);
var data_array= JSON.stringify( data_arr );
console.log(data_array);
chunk.end();
});
});
Node.js server have port is 4050.
From Freeswitch dialplan, I am executing below line
<action application="socket" data="127.0.0.1:4041 full"/>
Expected Output :
Whenever call is bridge on any gateway then after and before complete call am able to get bridge line from node.js
Also parameters which are added in dialplan as set/export that also must be get on node.js
Anyone like to share some hints for this problem ?

Error video-stream socket.io + socket.io-stream (Maximum call stack size exceeded)

I'm trying to create a webcam video-stream trough my node.js server with the help of socket.io and socket.io-stream.
I want to capture the video in /camera, open a stream trough socket.io (with the help of socket.io-stream) with the video, and receive it on the index url.
When I connect to the server trough /camera, and thus initiate the stream, the server crashes with the error "RangeError: Maximum call stack size exceeded".
The error seems to coming from "/node_modules/socket.io/node_modules/has-binary/index.js:48:23".
In the examples, I left out most of the arbitrary code, as the server/connection is working fine for transferring data-snippits.
Here is my current setup:
Server:
io.on('connection', function(socket) {
ioStream(socket).on('videoStream', function(stream, data) {
socket.broadcast.emit('videoStream', stream);
});
});
Camera
window.glob_socket = io();
var video = document.getElementById('camera');
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
if (navigator.getUserMedia) {
navigator.getUserMedia({
audio: false,
video: {
width: 320,
height: 240
}
}, function(videoStream) {
// Local preview
video.src = window.URL.createObjectURL(videoStream);
video.onloadedmetadata = function(e) {
video.play();
};
// Stream
var stream = ss.createStream();
ss(glob_socket).emit('videoStream', stream, videoStream);
fs.createReadStream(videoStream).pipe(stream);
}, function(err) {
console.log("The following error occurred: " + err.name);
});
} else {
console.log("getUserMedia not supported");
}
Index
var video = document.getElementById('camera');
ss(glob_socket).on('videoStream', function(stream) {
video.src = window.URL.createObjectURL(stream);
video.onloadedmetadata = function(e) {
video.play();
};
});
I'm unable to test the code on the server/index as the server crashes when the camera initiates the stream.
Anyone has an idea what's wrong here?
Unfortunately, you can't do that. socket.io-stream library only deals with static files, but not with live video streams.
To share video stream you should use WebRTC. There are a couple of libraries that may help you get started:
https://simplewebrtc.com/
http://peerjs.com/
Worth noting that WebRTC won't transfer video through your server (in most cases). It does more - it transfers video stream from one peer to another directly, which is good for your server's bandwidth. But there might be problems when peers are behind symmetric NAT. In this case video stream should be transfered through a TURN server.
More information about WebRTC you can find here.

How to handle multiple chat sessions with Node.js

I am currently developing a chat system using Node.js. My question is, how do I handle multiple chat sessions with Node.js. That's a bit vague so I'll explain...
So for example two people might engage in a chat session. Node.js checks every couple of seconds for new messages. This is simple enough as I can get this to work fine using my code below.
My issue is when another two people at the same time are in another chat session.
At present I am sending two query strings called "chat_id" and "check_date" so it can check for new chat messages after a certain date and time.
Problem is, the "chat_id" and "check_date" are overwritten every time a new chat is started because the server is being used by both chat rooms.
Am I making sense?
My code below:
var chat_id, check_date;
var sys = require("sys"),
http = require("http"),
url = require("url"),
path = require("path"),
fs = require("fs"),
events = require("events");
// Conntect to database
var Client = require('mysql').Client;
var client = new Client();
client.host = 'localhost';
client.port = 3306;
client.database = '****';
client.user = '****';
client.password = '****';
client.connect(function(error, results) {
if(error) {
console.log('Connection Error: ' + error.message);
return;
}
console.log('Connected to MySQL');
});
// Check for chat updates
function getChatUpdates() {
if (typeof(check_date) == 'undefined')
return;
client.query('SELECT name, message FROM chat WHERE chat_id = "' + chat_id + '" AND date_entered > "' + check_date + '"',
function selectCb(error, results, fields) {
if (error) {
console.log('GetData Error: ' + error.message);
client.end();
return;
}
if (results.length > 0) {
for(var i = 0;i<results.length;i++) {
console.log('Name: ' + results[i]['name']);
console.log('Message: ' + results[i]['message']);
}
}
});
}
// Set interval to check for chat updates every 2 seconds
setInterval(getChatUpdates, 2000);
http.createServer(function(request, response) {
// Get the query strings
var uri = url.parse(request.url, true);
chat_id = uri.query.chat_id;
check_date = uri.query.check_date;
console.log('Chat ID: ' + chat_id);
console.log('Last Check: ' + check_date);
// we'll do something here later.
}).listen(8080);
sys.puts("Server running at http://localhost:8080/");
It seems like you are having a PHP background and when programming in node.js you should have a completely different mindset. You should not poll(setInterval(getChatUpdates, 2000);
) for messages, but push(callbacks/events) messages to users on event. I advice you to have a look at socket.io and use a in-memory database like redis(instead of mysql) to store your messages. When you code like this your site will perform much better and is going to be real-time(more). Also I would advice you to use express as your framework to develop websites instead of using raw http module. I don't know if you already know about npm, but you should use that to manage your dependencies.
var chat_id, check_date;
Are global variables. You are going to be overriding the chat_id on every connection (in createServer. You probably need some sort of session storage (to associate a user and their chat) eg. an Array, Redis, etc.
It looks like you trying to use MySQL as message queue. RabbitMQ?

Node JS Express JS Client / Server game

I'm writing a two player card game, (say it's regular poker for simplicity) in Node.js and Express js. There's a couple of things I'm having trouble with. First, how do I make sure that there are only 2 players that can access an instance of the game, and is it possible to have them reconnect if they lose the connection? Second, how do send a message from the server to the client? I can send it within the "socket.on" listener call, but within the normal scope of the program I can't get it to work.
var socket = io.listen(app);
socket.on('connection', function(client){
player++;
if(player <= 2) {
var messageout = "player " + player + " connected";
client.broadcast(messageout);
client.on('message', function(data){console.log(data); })
client.on('disconnect', function(){console.log('disconnected');})
}
else {
socket.end;
}
});
I'm having trouble conceptually what's going on here and how to approach the problem. For example, do I do it all with sockets? Or do I return a web page with the updated state of the game (cards, bets, etc.) every turn?
First, how do I make sure that there
are only 2 players that can access an
instance of the game?
Create an array of instance objects.
When a new player joins either create a new instance and set them as player1, or add them to an existing instance as player two.
var instances = [];
function Instance () {
return {
name = 'game' + instances.length + 1,
gameVariables = defaults,
player1 = null,
player2 = null,
player1UUID = UUID(),
player2UUID = UUID()
}
}
Is it possible to have them reconnect
if they lose the connection?
If you send each player a UUID when they initially connect you can have them use it to authenticate when they reconnect.
How do I send a message from the
server to the client?
client.send({ gameState: gameState() });
of if you've saved the client into an object: instances[ 'game1' ].player1.send( data );
I do it all with sockets?
I would deal with all dynamic interactions with web sockets.
Do I return a web page with the updated state of the game (cards, bets, etc.) every turn?
I wouldn't send html over web sockets. Instead send json and use a client side template to render it.
Try now.
// server
var nowjs = require("now")
var everyone = nowjs.initialize(app);
everyone.connected(function() {
if (users.length < 2) {
users.push(this);
}
});
everyone.now.sendMessage = function(message, cb) {
gameLogic(message);
users.forEach(function(user) {
user.update(gameLogic.getState());
});
};
//client
$("#action").click(function() {
now.sendMessage($(this).data("action"));
});
now.update = function(data) {
// update UI
};

Resources