Create MediaStream from ReadableStream - node.js

I'm using puppeteer-stream to get a stream of a browser controlled by Node, running on a server. I am able to write this stream out to a file with no issues.
I wanted to stream this stream via WebRTC to a browser (basically to see what the browser is running in realtime). For webrtc, I'm trying to use simple-peer since it has ready bindings for Node as well as the browser-side.
However, when I try to pass this stream to simple-peer, I get the following error:
/Users/my_user/my_project/node_modules/simple-peer/index.js:286
stream.getTracks().forEach(track => {
^
TypeError: stream.getTracks is not a function
at Peer.addStream (/Users/my_user/my_project/node_modules/simple-peer/index.js:286:12)
This is because the Stream I have is a ReadableStream, but simple-peer (or most webrtc libs) expects a MediaStream.
How can I convert a realtime ReadableStream into a MediaStream that can be used with WebRTC? I found examples to convert MediaStreams into ReadableStreams such as here but not vice versa.
Am I missing something here?

Related

Stream files uploaded by client

Background: Stream Consumption
This is how you can consume and read a stream of data-bytes that is received in the client:
Get a Response object (example a fetch response.)
Retrieve the ReadableStream from the body field of it i.e response.body
As body is an instance of ReadableStream, we can do body.getReader()
And use the reader as reader.read()
That is simple enough, we can consume the stream of bytes coming from the server and we can consume it the same way in NodeJS and Browser through the Node Web Stream API.
Stream from path in NodeJS
To create a stream from URLPath in Node JS it is quite easy (you just pass the path to a stream.) You can also switch from NodeStream to WebStream with ease (Stream.toWebStream())
Problem: Stream from user upload action
Can we get a stream right from user file uploads in the browser ? Can you give a simple example ?
The point of it would be to process the files as the user is uploading them, not to use the Blob stream.
Is it possible analyze user data as it is being uploaded i.e is it possible for it to be a stream ?

How to save a webRTC stream into a file on server with nodejs?

I get my stream from my client like this :
webrtc_connection.ontrack = async (e) => {
//TODO : RECORD
}
How can I record / save it into a file on server? Apparently nodejs does not have MediaRecorder, so I am at loss for going further.
There are two options. The first is to use MediaRecorder+Socket.io+FFmpeg. Here is an example of how to stream from the browser to RTMP via node.js, but instead of streaming, you can just save it to the file.
draw your video on canvas, use canvas.captureStream() to get MediaStream from the canvas;
append your audio to MediaStream that you got in the previous step using MediaStream.addTrack();
use MediaRecorder to get raw data from the MediaStream;
send this raw data via WebSockets to node.js;
use FFmpeg to decode and save your video data to a file.
The Second is to use node-webrtc. You can join your WebRTC room from the server as another participant using WebRTC and record media tracks using FFmpeg. Here is an example.

How to stream the response using wreck node module?

I have a requirement where I need to stream the response from a get request using Wreck node module (cannot use any other node modules as Wreck needs to be used as part of our framework). I went through the documentation but couldn't find any helpful results. Is there a way to using streaming here?
As per the Wreck docs:
get(uri, [options])
Returns a promise that resolves into an object with the following properties:
- res - The HTTP Incoming Message object, which is a readable stream that has "ended" and contains no more data to read
- payload - The payload in the form of a Buffer or (optionally) parsed JavaScript object (JSON).
As per the Node docs if readable stream emitted the 'end' event then the data from it has been consumed.
If you really must use a stream, I suggest you have a look at implementing a stream to basically fake streaming.

how to create node server that receiving video stream and save the stream as video file?

I try to look for some examples that doing something like it - but all i found is example of receiving picture and not receiving static stream of video.
I need to receive a video - and save it on the server disk until the client send some flag that the video stream is done.
How to do it ?
For example: you can convert stream to Binary Data and send this: Sending_and_Receiving_Binary_Data
Also you can use MediaStream Recording API, if you want to process video\audio stream: docs

Stream audio simultaneously from soundcloud source with node

I am using the Soundcloud api from a node server. I want to stream an audio track simultaneously to multiple users.
I tried something like this (using the code on this question Streaming audio from a Node.js server to HTML5 <audio> tag) but it does not work. Any idea on how I could do this?
var radio = require("radio-stream");
var http = require('http');
var url = "http://api.soundcloud.com/tracks/79031167/stream?client_id=db10c5086fe237d1718f7a5184f33b51";
var stream = radio.createReadStream(url);
var clients = [];
stream.on("connect", function() {
console.error("Radio Stream connected!");
console.error(stream.headers);
});
stream.on("data", function (chunk) {
if (clients.length > 0){
for (client in clients){
clients[client].write(chunk);
};
}
});
stream.on("metadata", function(title) {
console.error(title);
});
var server = http.createServer(function(req, res){
res.writeHead(200,{
"Content-Type": "audio/mpeg",
'Transfer-Encoding': 'chunked'
});
clients.push(res);
console.log('Client connected; streaming');
});
server.listen("8000", "0.0.0.0");
console.log('Server running at http://127.0.0.1:8000');
There are several problems
Follow Redirects
The radio-stream module that you're using hasn't been updated in 4 years. That's an eternity in Node.js API's time. I recommend not using it, as there are undoubtedly compatibility issues with current and future versions of Node.js. At a minimum, there are much better ways of handling this now with the new streams API.
In any case, that module does not follow HTTP redirects. The SoundCloud API is redirecting you to the actual media file.
Besides, the radio-stream module is built to demux SHOUTcast/Icecast style metadata, not MP3 ID3 data. It won't help you.
All you need is a simple http.get(). You can then either follow the redirect yourself, or use the request package. More here: How do you follow an HTTP Redirect in Node.js?
Chunked Encoding
Many streaming clients cannot deal with chunked encoding. Node.js (correctly) adds it when you have streaming output. For our purposes though, let's disable it.
res.useChunkedEncodingByDefault = false;
https://stackoverflow.com/a/11589937/362536
Building a Coherent Stream
In theory, you can just append MPEG stream after MPEG stream and all will work fine. In practice, this doesn't work. ID3 tags will corrupt the stream. One file might be in a different sample rate than the other file and most software will not be able to switch the hardware to that new sample rate on the fly. Basically, you cannot reliably do what you're trying to do.
The only thing you can do is re-encode the entire stream by playing back these audio files, and getting a solid stream out the other end. This gives you the added bonus that you can handle other codecs and formats, not just MP3.
To handle many of your codec issues, you can utilize FFmpeg. However, you're going to need a way to play back those files to FFmpeg for encoding.
Rate Limiting
You must stream audio at the rate of playback. (You can send an initial buffer to get clients started quickly, but you can't keep slamming data to them as fast as possible.) If you don't do this, you will run out of memory on the server very quickly, as clients will lower their TCP window size down to zero and stay there until the audio has caught up enough to allow buffering more data. Since you're not using pipe, your streams are in flowing mode and will indefinitely buffer on the server. Now, this is actually a good thing in some ways because that prevents one slow client from slowing down the others. It's a bad thing though in that your code, you are streaming as fast as possible and not at the rate of playback.
If you play back the audio to another encoder, use RTC over several seconds as a clock. It doesn't have to be perfect, that's what client buffers are for. If you're playing back to an audio device, it has its own clock of course, which will be used.
What you should actually do
You've stumbled into a huge project. I strongly recommend using Liquidsoap instead. There are ways you can control it from Node.js. From there, use a server like Icecast for your streaming.

Resources