I want to stream video (with audio) over websocket in one direction without using STUN/TURN server. Is it possible to write such a web app?
Data will flow like this:
Peer A -> Websocket Server -> Peer B
Yes it is possible. if you ok 0.5 s latency
streamer:
navigator.mediaDevices.getUserMedia({video:true,audio:true}).then(stream=>{
var ws,mediaRecorder;
var options = {
mimeType: "video/webm;codecs=opus, vp8",
bitsPerSecond:5000 //quality
};
function handleVideo(){
try{
mediaRecorder.stop()
}catch(e){}
mediaRecorder=null;
mediaRecorder = new MediaRecorder(stream,options);
mediaRecorder.ondataavailable =function(e) {
if(e.data&&e.data.size>0) {
e.data.arrayBuffer().then(buffer=>{
ws.send(buffer)
})
}
}
mediaRecorder.start(300);
}
function connect(){
ws = new WebSocket("wss://yourwebsocket.com")
ws.binaryType = "arraybuffer"
ws.onopen=handleVideo
ws.onmessage=handleVideo
ws.onclose=connect
}
connect()
})
// so onmessage function neccessary for when someone join the socket stream again, because webm format need embl header
watcher:
var media,sourceBuffer,ws;
var video = document.getElementById('yourvideoid')
function handleStream(e){
const buffer=e.data
const data= new Uint8Array(buffer)
if(data[0]===26&&data[1]===69&&data[2]===223){
if(media){
URL.revokeObjectURL(media)
sourceBuffer=null;
}
media= new MediaSource();
video.src = URL.createObjectURL(media);
video.onloadedmetadata=function(){
video.muted=false
video.play()
}
media.onsourceopen=function(){
sourceBuffer= media.addSourceBuffer("video/webm;codecs=opus, vp8");
sourceBuffer.appendBuffer(buffer)
}
}
else {
if(!media)return;
sourceBuffer.appendBuffer(buffer)
}
}
function connect(){
ws = new WebSocket("wss://yourwsserver.com")
ws.binaryType = "arraybuffer"
ws.onmessage=handleStream
ws.onclose=connect
}
connect()
// we fetch data from websocket then add data to video buffer
nodejs server:
const EventEmitter = require('events');
const https = require('https');
const {Server} = require('ws'); //npm i ws
const emitter= new EventEmitter();
const app = https.createServer(options,function (req, res) {})
const wss = new Server({ server: app });
wss.on('connection', (socket,req) => {
var isStreamer=false
socket.fn=function(e){socket.send(e)}
const interval= setInterval(socket.ping, 5000);
emitter.on('data',socket.fn)
emitter.emit('refresh','0')
socket.on('message', (data) => {
isStreamer||(emitter.on('refresh',socket.fn),emitter.off('data',socket.fn),(isStreamer=true))
emitter.emit('data',data)
});
socket.on('close', () => {
clearInterval(interval)
emitter.off('data',socket.fn)
emitter.off('refresh',socket.fn)
})
socket.on('ping',socket.pong)
socket.on("error", (err) => {})
});
app.listen(PORT,'0.0.0.0')
//u need to set option for https or use http instead