hello recently I've been creating a video system called that is working super well here the code I'm using: Html
<html>
<head>
<title>Delta Meet</title>
</head>
<body>
<h1 class="title">Delta Meet</h1>
<p id="notification" hidden></p>
<div class="entry-modal" id="entry-modal">
<p>Create or Join Meeting</p>
<input id="room-input" class="room-input" placeholder="Enter Room ID">
<div>
<button onclick="createRoom()">Create Room</button>
<button onclick="joinRoom()">Join Room</button>
</div>
</div>
<div class="meet-area">
<!-- Remote Video Element-->
<video id="remote-video"></video>
<!-- Local Video Element-->
<video id="local-video"></video>
</div>
<br><br><br>
</body>
<script src="https://unpkg.com/peerjs#1.3.1/dist/peerjs.min.js"></script>
<script src="script.js"></script>
</html>
and here the js:
const PRE = "DELTA"
const SUF = "MEET"
var room_id;
var getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
var local_stream;
function createRoom(){
console.log("Creating Room")
let room = document.getElementById("room-input").value;
if(room == " " || room == "") {
alert("Please enter room number")
return;
}
room_id = PRE+room+SUF;
let peer = new Peer(room_id)
peer.on('open', (id)=>{
console.log("Peer Connected with ID: ", id)
hideModal()
getUserMedia({video: true, audio: true}, (stream)=>{
local_stream = stream;
setLocalStream(local_stream)
},(err)=>{
console.log(err)
})
notify("Waiting for peer to join.")
})
peer.on('call',(call)=>{
call.answer(local_stream);
call.on('stream',(stream)=>{
setRemoteStream(stream)
})
})
}
function setLocalStream(stream){
let video = document.getElementById("local-video");
video.srcObject = stream;
video.muted = true;
video.play();
}
function setRemoteStream(stream){
let video = document.getElementById("remote-video");
video.srcObject = stream;
video.play();
}
function hideModal(){
document.getElementById("entry-modal").hidden = true
}
function notify(msg){
let notification = document.getElementById("notification")
notification.innerHTML = msg
notification.hidden = false
setTimeout(()=>{
notification.hidden = true;
}, 3000)
}
function joinRoom(){
console.log("Joining Room")
let room = document.getElementById("room-input").value;
if(room == " " || room == "") {
alert("Please enter room number")
return;
}
room_id = PRE+room+SUF;
hideModal()
let peer = new Peer()
peer.on('open', (id)=>{
console.log("Connected with Id: "+id)
getUserMedia({video: true, audio: true}, (stream)=>{
local_stream = stream;
setLocalStream(local_stream)
notify("Joining peer")
let call = peer.call(room_id, stream)
call.on('stream', (stream)=>{
setRemoteStream(stream);
})
}, (err)=>{
console.log(err)
})
})
}
so far so good, so I decided to create a button for the user to be able to share the screen:
<button id="start">Start Capture</button> <button id="stop">Stop Capture</button>
then I went there and created a script:
async function startCapture() {
try {
videoElem.srcObject = await navigator.mediaDevices.getDisplayMedia(displayMediaOptions);
dumpOptionsInfo();
} catch(err) {
console.error("Error: " + err);
}
}
function stopCapture(evt) {
let tracks = videoElem.srcObject.getTracks();
tracks.forEach(track => track.stop());
videoElem.srcObject = null;
}
function dumpOptionsInfo() {
const videoTrack = videoElem.srcObject.getVideoTracks()[0];
console.info("Track settings:");
console.info(JSON.stringify(videoTrack.getSettings(), null, 2));
console.info("Track constraints:");
console.info(JSON.stringify(videoTrack.getConstraints(), null, 2));
}const videoElem = document.getElementById("local-video");
const logElem = document.getElementById("log");
const startElem = document.getElementById("start");
const stopElem = document.getElementById("stop");
// Options for getDisplayMedia()
var displayMediaOptions = {
video: {
cursor: "always"
},
audio: false
};
// Set event listeners for the start and stop buttons
startElem.addEventListener("click", function(evt) {
startCapture();
}, false);
stopElem.addEventListener("click", function(evt) {
stopCapture();
}, false);
it works just right for me because for the other user it doesn't appear at all. What did I do wrong?
Related
I am trying to use WebRTC for creating a two-person video chat application. I am able to establish a connection and send messages between the two clients, but I am not able to stream the other client's video. I am using firebase to establish the connection, and that part seems to be working since I am able to send messages. What am I doing wrong?
index.svelte is
<script lang="ts">
import { db } from '$lib/firebase';
import { doc, setDoc, getDoc, updateDoc, deleteDoc, onSnapshot } from 'firebase/firestore';
const collectionName = 'conversations';
var server = '';
var pc: RTCPeerConnection | null = null;
var dc: RTCDataChannel | null = null;
var connected = false;
var finishedAddingRemoteDescription = false;
const iceConfig = {
iceServers: [
{
urls: ['stun:stun1.l.google.com:19302', 'stun:stun2.l.google.com:19302']
}
],
iceCandidatePoolSize: 10
};
const startHost = async () => {
if (server == '') {
console.log('Name cannot be empty');
return;
}
await deleteDoc(doc(db, collectionName, server));
pc = new RTCPeerConnection(iceConfig);
dc = pc.createDataChannel('channel');
dc.onmessage = (e) => console.log('Just got a message ' + e.data);
dc.onopen = (_) => (connected = true);
pc.ontrack = (e) => console.log('On track a!');
pc.onicecandidate = async (_) => {
try {
const docRef = await setDoc(doc(db, collectionName, server), {
offer: pc!.localDescription?.toJSON()
});
onSnapshot(doc(db, collectionName, server), (doc) => {
if (
doc.data() != undefined &&
'answer' in doc.data() &&
!finishedAddingRemoteDescription
) {
pc!.setRemoteDescription(doc.data().answer);
finishedAddingRemoteDescription = true;
}
});
} catch (e) {
console.error('Error adding document: ', e);
}
};
pc.createOffer()
.then((o) => pc!.setLocalDescription(o))
.then((_) => console.log('Set successfully'));
};
const startJoin = async () => {
const docRef = doc(db, collectionName, server);
const docSnap = await getDoc(docRef);
if (docSnap.exists()) {
pc = new RTCPeerConnection(iceConfig);
pc.onicecandidate = async (_) => {
try {
const docRef = await updateDoc(doc(db, collectionName, server), {
answer: pc!.localDescription?.toJSON()
});
} catch (e) {
console.error('Error adding document: ', e);
}
};
pc.ondatachannel = (e) => {
dc = e.channel;
dc.onmessage = (e) => console.log('new message from client: ' + e.data);
dc.onopen = (_) => (connected = true);
};
pc.ontrack = (e) => console.log('On track b!');
pc.setRemoteDescription(docSnap.data().offer).then((_) => console.log('offer set!'));
pc.createAnswer()
.then((a) => pc!.setLocalDescription(a))
.then((_) => console.log('answer crated'));
} else {
console.log('No such document!');
}
};
var message = '';
const sendMsg = () => {
console.log('Send msg: ' + message);
dc!.send(message);
};
var localVideo: HTMLVideoElement;
var remoteVideo: HTMLVideoElement;
var remoteStream: MediaProvider | null = null;
const startWebcam = async () => {
const localStream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
remoteStream = new MediaStream();
localStream.getTracks().forEach((track) => {
pc!.addTrack(track, localStream);
});
pc!.ontrack = (event) => {
console.log('Handling on track'); // never called
event.streams[0].getTracks().forEach((track) => {
console.log('GOT A TRACK!!!'); // never called
remoteStream!.addTrack(track);
});
};
localVideo.srcObject = localStream;
remoteVideo.srcObject = remoteStream;
};
</script>
<div class="m-5">
<input type="text" bind:value={server} placeholder="server" class="rounded-xl p-3 block" />
<button on:click={startHost} class="text-blue-500 block">host</button>
<button on:click={startJoin} class="text-blue-500 block">join</button>
<p>{connected ? 'Connected' : 'Not connected'}</p>
<div>
<input type="text" placeholder="message" bind:value={message} class="rounded-xl p-3 block" />
<button class="text-blue-500 disabled:text-blue-300" disabled={!connected} on:click={sendMsg}
>send</button
>
</div>
<div class="flex w-full space-x-5 {connected || 'opacity-50'}">
<div class="flex-1 text-center">
<h3>Yours</h3>
<video
class="bg-black aspect-video w-full"
bind:this={localVideo}
autoplay
playsinline
muted
/>
<button class="text-blue-500" disabled={!connected} on:click={startWebcam}>Start video</button
>
</div>
<div class="flex-1">
<h3 class="text-center">Others</h3>
<video
class="bg-black aspect-video w-full"
bind:this={remoteVideo}
autoplay
playsinline
muted
/>
</div>
</div>
</div>
The lib/firebase.ts code is:
import { initializeApp } from 'firebase/app';
import { getFirestore } from 'firebase/firestore';
const firebaseConfig = {
...
};
const app = initializeApp(firebaseConfig);
export const db = getFirestore(app);
I have a Raspberry Pi running a Node express server with webRTC. The Raspberry Pi is connected to a web cam. I'm able to view the index.html page and see the video stream, but then it randomly freezes or black out completely. I've tried researching the issue but most solutions refer to changing settings on components that are not part of what I'm using. Help is sincerely appreciated as I've been banging my head for the past few days.
index.html
<!DOCTYPE html>
<html>
<head>
<title>Stream</title>
<meta charset="UTF-8" />
<link href="/styles.css" rel="stylesheet" />
</head>
<body>
<video playsinline autoplay muted></video>
<button id="enable-audio">Enable audio</button>
<script src="/socket.io/socket.io.js"></script>
<script src="/watch.js"></script>
</body>
</html>
broadcast.js
// wip 21 January 2022
const peerConnections = {};
const config = {
iceServers: [
{
"urls": "stun:stun.l.google.com:19302",
},
// {
// "urls": "turn:TURN_IP?transport=tcp",
// "username": "TURN_USERNAME",
// "credential": "TURN_CREDENTIALS"
// }
]
};
const socket = io.connect(window.location.origin);
socket.on("answer", (id, description) => {
peerConnections[id].setRemoteDescription(description);
});
socket.on("watcher", id => {
const peerConnection = new RTCPeerConnection(config);
peerConnections[id] = peerConnection;
let stream = videoElement.srcObject;
stream.getTracks().forEach(track => peerConnection.addTrack(track, stream));
peerConnection.onicecandidate = event => {
if (event.candidate) {
socket.emit("candidate", id, event.candidate);
}
};
peerConnection
.createOffer()
.then(sdp => peerConnection.setLocalDescription(sdp))
.then(() => {
socket.emit("offer", id, peerConnection.localDescription);
});
});
socket.on("candidate", (id, candidate) => {
peerConnections[id].addIceCandidate(new RTCIceCandidate(candidate));
});
socket.on("disconnectPeer", id => {
peerConnections[id].close();
delete peerConnections[id];
});
window.onunload = window.onbeforeunload = () => {
socket.close();
};
// Get camera and microphone
const videoElement = document.querySelector("video");
const audioSelect = document.querySelector("select#audioSource");
const videoSelect = document.querySelector("select#videoSource");
audioSelect.onchange = getStream;
videoSelect.onchange = getStream;
getStream()
.then(getDevices)
.then(gotDevices);
function getDevices() {
return navigator.mediaDevices.enumerateDevices();
}
function gotDevices(deviceInfos) {
window.deviceInfos = deviceInfos;
for (const deviceInfo of deviceInfos) {
const option = document.createElement("option");
option.value = deviceInfo.deviceId;
if (deviceInfo.kind === "audioinput") {
option.text = deviceInfo.label || `Microphone ${audioSelect.length + 1}`;
audioSelect.appendChild(option);
} else if (deviceInfo.kind === "videoinput") {
option.text = deviceInfo.label || `Camera ${videoSelect.length + 1}`;
videoSelect.appendChild(option);
}
}
}
function getStream() {
if (window.stream) {
window.stream.getTracks().forEach(track => {
track.stop();
});
}
const audioSource = audioSelect.value;
const videoSource = videoSelect.value;
const constraints = {
audio: { deviceId: audioSource ? { exact: audioSource } : undefined },
video: { deviceId: videoSource ? { exact: videoSource } : undefined }
};
return navigator.mediaDevices
.getUserMedia(constraints)
.then(gotStream)
.catch(handleError);
}
function gotStream(stream) {
window.stream = stream;
audioSelect.selectedIndex = [...audioSelect.options].findIndex(
option => option.text === stream.getAudioTracks()[0].label
);
videoSelect.selectedIndex = [...videoSelect.options].findIndex(
option => option.text === stream.getVideoTracks()[0].label
);
videoElement.srcObject = stream;
socket.emit("broadcaster");
}
function handleError(error) {
console.error("Error: ", error);
}
watch.js
let peerConnection;
const config = {
iceServers: [
{
"urls": "stun:stun.l.google.com:19302",
},
// {
// "urls": "turn:TURN_IP?transport=tcp",
// "username": "TURN_USERNAME",
// "credential": "TURN_CREDENTIALS"
// }
]
};
const socket = io.connect(window.location.origin);
const video = document.querySelector("video");
const enableAudioButton = document.querySelector("#enable-audio");
enableAudioButton.addEventListener("click", enableAudio)
socket.on("offer", (id, description) => {
peerConnection = new RTCPeerConnection(config);
peerConnection
.setRemoteDescription(description)
.then(() => peerConnection.createAnswer())
.then(sdp => peerConnection.setLocalDescription(sdp))
.then(() => {
socket.emit("answer", id, peerConnection.localDescription);
});
peerConnection.ontrack = event => {
video.srcObject = event.streams[0];
};
peerConnection.onicecandidate = event => {
if (event.candidate) {
socket.emit("candidate", id, event.candidate);
}
};
});
socket.on("candidate", (id, candidate) => {
peerConnection
.addIceCandidate(new RTCIceCandidate(candidate))
.catch(e => console.error(e));
});
socket.on("connect", () => {
socket.emit("watcher");
});
socket.on("broadcaster", () => {
socket.emit("watcher");
});
window.onunload = window.onbeforeunload = () => {
socket.close();
peerConnection.close();
};
function enableAudio() {
console.log("Enabling audio")
video.muted = false;
}
I am using peerJS for screen sharing feature and flutter for web app, I'm able to call javascript functions in flutter but not able to pass values from Javascript and Flutter and make them listen in flutter.
this is my script.js:
const PRE = "Devcom"
const SUF = "Community"
var room_id;
var getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
var local_stream;
var screenStream;
var peer = null;
var currentPeer = null
var screenSharing = false
function createRoom() {
console.log("Creating Room")
let room = document.getElementById("room-input").value;
if (room == " " || room == "") {
alert("Please enter room number")
return;
}
room_id = PRE + room + SUF;
peer = new Peer(room_id)
peer.on('open', (id) => {
console.log("Peer Connected with ID: ", id)
hideModal()
getUserMedia({ video: true, audio: true }, (stream) => {
local_stream = stream;
setLocalStream(local_stream)
}, (err) => {
console.log(err)
})
notify("Waiting for peer to join.")
})
peer.on('call', (call) => {
call.answer(local_stream);
call.on('stream', (stream) => {
setRemoteStream(stream)
})
currentPeer = call;
})
}
function setLocalStream(stream) {
let video = document.getElementById("local-video");
video.srcObject = stream;
video.muted = true;
video.play();
}
function setRemoteStream(stream) {
let video = document.getElementById("remote-video");
video.srcObject = stream;
video.play();
}
function hideModal() {
document.getElementById("entry-modal").hidden = true
}
function notify(msg) {
let notification = document.getElementById("notification")
notification.innerHTML = msg
notification.hidden = false
setTimeout(() => {
notification.hidden = true;
}, 3000)
}
function joinRoom() {
console.log("Joining Room")
let room = document.getElementById("room-input").value;
if (room == " " || room == "") {
alert("Please enter room number")
return;
}
room_id = PRE + room + SUF;
hideModal()
peer = new Peer()
peer.on('open', (id) => {
console.log("Connected with Id: " + id)
getUserMedia({ video: true, audio: true }, (stream) => {
local_stream = stream;
setLocalStream(local_stream)
notify("Joining peer")
let call = peer.call(room_id, stream)
call.on('stream', (stream) => {
setRemoteStream(stream);
})
currentPeer = call;
}, (err) => {
console.log(err)
})
})
}
function startScreenShare() {
if (screenSharing) {
stopScreenSharing()
}
navigator.mediaDevices.getDisplayMedia({ video: true }).then((stream) => {
screenStream = stream;
let videoTrack = screenStream.getVideoTracks()[0];
videoTrack.onended = () => {
stopScreenSharing()
}
if (peer) {
let sender = currentPeer.peerConnection.getSenders().find(function (s) {
return s.track.kind == videoTrack.kind;
})
sender.replaceTrack(videoTrack)
screenSharing = true
}
console.log(screenStream)
})
}
function stopScreenSharing() {
if (!screenSharing) return;
let videoTrack = local_stream.getVideoTracks()[0];
if (peer) {
let sender = currentPeer.peerConnection.getSenders().find(function (s) {
return s.track.kind == videoTrack.kind;
})
sender.replaceTrack(videoTrack)
}
screenStream.getTracks().forEach(function (track) {
track.stop();
});
screenSharing = false
}
function alertMessage(text) {
alert(text)
}
window.logger = (flutter_value) => {
console.log({ js_context: this, flutter_value });
}
window.state = {
hello: 'world'
}
I am able to call these javascript functions in my flutter app using:
import 'dart:js' as js;
js.context.callMethod('alertMessage', ['Flutter is calling upon JavaScript!']);
I have webRTC.html file below which works fine with my js file attached above:
<html>
<head>
<title>DEVCOM - Rooms</title>
<link rel="stylesheet" type="text/css" href="styles.css">
</head>
<body>
<h1 class="title">Devcom</h1>
<p id="notification" hidden></p>
<div class="entry-modal" id="entry-modal">
<p>Create or Join Meeting</p>
<input id="room-input" class="room-input" placeholder="Enter Room ID">
<div>
<button onclick="createRoom()">Create Room</button>
<button onclick="joinRoom()">Join Room</button>
</div>
</div>
<div class="meet-area">
<!-- Remote Video Element-->
<video id="remote-video"></video>
<!-- Local Video Element-->
<video id="local-video"></video>
<div class="meet-controls-bar">
<button onclick="startScreenShare()">Screen Share</button>
</div>
</div>
</body>
<script src="https://unpkg.com/peerjs#1.3.1/dist/peerjs.min.js"></script>
<script src="script.js"></script>
</html>
but the problem which I am facing is how can I make a flutter widget listen to javascript like instead of using document.getElementById("room-input").value I want to make javascript listen to flutter widgets and variables rather than html id, values...
or Is there any other way which can make html rendering in flutter web I tried webview_flutter, easy_web_view, flutter_html but nothing worked for me as I want to use it in windows chrome (web) few of earlier mentioned plugins are rather legacy and other are only for android and ios
Thanks in advance.
I am following the guide to implement webrtc from the official page:
https://webrtc.org/
And I am having trouble for two-way communication. On one pc I have a video camera and on the other only a microphone.
I manage to receive the camcorder, but I cannot receive the .ontrack event on the pc that sends the camcorder and it has to receive only the audio, when I am adding the track on the computer that sends the audio but not launch event .ontrack on remote machine.
The connection is made correctly, here paste the connection and the code
MY CODE one one localhost/video.php antother localhsot/video.php?cliente=1
<?php
/**
* Created by PhpStorm.
* User: Jesús
* Date: 16/03/2020
* Time: 13:16
*/
?>
<video id="localVideo" autoplay <?= !isset($_GET['cliente']) ? 'muted' : '' ?> playsinline controls="false" style="width: 600px; height: 320px;"></video>
<?php
if(!isset($_GET['cliente'])) {
?>
<button onclick="makeCallAdmin()">enviar llamada</button>
<?php
}
?>
<script src="../app/js/lib/socket.io.js"></script>
<script>
let cliente = <?= isset($_GET['cliente']) ? 'true' : 'false' ?>;
let tipo = cliente ? 'client' : 'admin';
var ipSocket = 'SCOCKETADDRESS';
// var ipSocket = 'https://192.168.125.175:3001';
var idgrupo = '5ed44424c2df0470d689.4f6370fbe1ac319e5dc1d7417822d28a';
var socket = io(ipSocket, {
query: "grupo=" + idgrupo + "&tipo=" + tipo
});
const iceConfiguration = {
iceServers: [
{
urls: 'stun:stun.l.google.com:19302?transport=udp'
},
{
urls: 'turns:turnserver',
username: 'prueba',
credential: '123456'
}
],
}
const offerOptions = {
offerToReceiveAudio: 1,
offerToReceiveVideo: 1
};
// let peerConnection, remoteStream, videoElement;
let peerConnection;
let fuerzaConectar;
async function getConnectedDevices(type) {
const devices = await navigator.mediaDevices.enumerateDevices();
return await devices.filter(device => device.kind === type)
}
// Open camera with at least minWidth and minHeight capabilities
async function openCamera(cameraId, audioid) {
let constraints;
if(!cameraId) {
constraints = {
'audio': {'echoCancellation': true}
}
}else{
constraints = {
'audio': {'echoCancellation': true},
'video': {
'deviceId': cameraId
}
}
}
// constraints = {'video': true, 'audio': true};
return await navigator.mediaDevices.getUserMedia(constraints);
}
async function playVideoFromCamera(peerConnection, type, fuerza) {
if(type == null)
type = 'videoinput';
if(fuerza == null)
fuerza = false;
try {
const cameras = await getConnectedDevices(type);
if (cameras && cameras.length > 0) {
let stream;
if(fuerza) //si solo ha encontrado el audio enviamos solo audio
stream = await openCamera(false, cameras[0].deviceId);
else //si ha encontrado camara enviamos camara y audio
stream = await openCamera(cameras[0].deviceId, false);
stream.getTracks().forEach(track => {
peerConnection.addTrack(track, stream);
});
}else{
if(!fuerza)
await playVideoFromCamera(peerConnection, 'audioinput', true);
else
console.log('no hay input');
}
} catch(error) {
console.error('Error opening video camera.', error);
}
}
async function makeCallAdmin() {
fuerzaConectar = (fuerzaConectar == null | !fuerzaConectar) ? true : false;
if(typeof peerConnection == 'object') {
peerConnection.close();
peerConnection = null;
const videoElement = document.querySelector('video#localVideo');
videoElement.srcObject = null;
if(cliente)
socket.off('videoconferenciaRecibeCliente');
else
socket.off('videoconferenciaRecibeAdmin');
}
peerConnection = new RTCPeerConnection(iceConfiguration);
const remoteStream = new MediaStream();
// Listen for local ICE candidates on the local RTCPeerConnection
// peerConnection.removeEventListener('icecandidate', iceCandidate);
// peerConnection.addEventListener('icecandidate', iceCandidate);
peerConnection.onicecandidate = e => iceCandidate(e);
// Listen for connectionstatechange on the local RTCPeerConnection
// peerConnection.removeEventListener('iceconnectionstatechange', iceconnectionstatechange);
peerConnection.oniceconnectionstatechange = e => iceconnectionstatechange(e, peerConnection);
// peerConnection.removeEventListener('track', track);
// peerConnection.addEventListener('track', trackEv);
peerConnection.ontrack = e => trackEv(e, remoteStream);
socket.on('videoconferenciaRecibeAdmin', data => videoconferenciaRecibeAdmin(data, peerConnection));
const offer = await peerConnection.createOffer(offerOptions);
await peerConnection.setLocalDescription(offer);
socket.emit('videoconferenciaAdmin', {'tipo':'remoteDescription','offer': offer});
}
async function makeCallCliente()
{
fuerzaConectar = (fuerzaConectar == null | !fuerzaConectar) ? true : false;
if(typeof peerConnection == 'object') {
peerConnection.close();
peerConnection = null;
const videoElement = document.querySelector('video#localVideo');
videoElement.srcObject = null;
if(cliente)
socket.off('videoconferenciaRecibeCliente');
else
socket.off('videoconferenciaRecibeAdmin');
}
peerConnection = await new RTCPeerConnection(iceConfiguration);
const remoteStream = await new MediaStream();
// Listen for local ICE candidates on the local RTCPeerConnection
// peerConnection.removeEventListener('icecandidate', iceCandidate);
// peerConnection.addEventListener('icecandidate', iceCandidate);
peerConnection.onicecandidate = e => iceCandidate(e);
// Listen for connectionstatechange on the local RTCPeerConnection
// peerConnection.removeEventListener('iceconnectionstatechange', iceconnectionstatechange);
peerConnection.oniceconnectionstatechange = e => iceconnectionstatechange(e, peerConnection);
// peerConnection.removeEventListener('track', track);
// peerConnection.addEventListener('track', trackEv);
peerConnection.ontrack = e => trackEv(e, remoteStream);
socket.on('videoconferenciaRecibeCliente', data => videoconferenciaRecibeCliente(data, peerConnection, ));
}
async function videoconferenciaRecibeCliente(data, peerConnection)
{
switch(data.tipo) {
case 'remoteDescription':
if (data.offer) {
console.log(data.offer);
await peerConnection.setRemoteDescription(new RTCSessionDescription(data.offer));
const answer = await peerConnection.createAnswer(offerOptions);
await peerConnection.setLocalDescription(answer);
await socket.emit('videoconferenciaCliente', {'tipo':'remoteDescription','answer': answer});
console.log('recibida conexion cliente');
console.log(peerConnection);
}
break;
case 'icecandidate':
if (data.icecandidate) {
try {
await peerConnection.addIceCandidate(data.icecandidate);
console.log('creado ice candidate cliente');
console.log(data.icecandidate);
} catch (e) {
console.error('Error adding received ice candidate', e);
}
}
break;
}
}
async function videoconferenciaRecibeAdmin(data, peerConnection)
{
switch(data.tipo) {
case 'remoteDescription':
if (data.answer) {
console.log(data.answer);
const remoteDesc = new RTCSessionDescription(data.answer);
await peerConnection.setRemoteDescription(remoteDesc);
console.log('recibida conexion admin');
console.log(peerConnection);
}
break;
case 'icecandidate':
if (data.icecandidate) {
try {
await peerConnection.addIceCandidate(data.icecandidate);
console.log('creado ice candidate admin');
console.log(data.icecandidate);
} catch (e) {
console.error('Error adding received ice candidate', e);
}
}
break;
}
}
async function iceCandidate(event)
{
let el_evento = cliente ? 'videoconferenciaCliente' : 'videoconferenciaAdmin';
if (event.candidate) {
socket.emit(el_evento, {'tipo':'icecandidate','icecandidate': event.candidate});
}
}
async function iceconnectionstatechange(event, peerConnection)
{
console.log(peerConnection.iceConnectionState);
switch(peerConnection.iceConnectionState) {
case 'connected':
console.log('CONECTADO');
await enviarLLamada(peerConnection);
switch(true) {
case fuerzaConectar && cliente:
// makeCallCliente();
break;
case fuerzaConectar && !cliente:
makeCallAdmin();
break;
}
break;
case 'disconnected':
console.log('DESconectado');
await peerConnection.close();
peerConnection = null;
const videoElement = document.querySelector('video#localVideo');
videoElement.srcObject = null;
if(cliente)
await socket.off('videoconferenciaRecibeCliente');
else
await socket.off('videoconferenciaRecibeAdmin');
break;
}
}
async function trackEv(event, remoteStream)
{
const videoElement = document.querySelector('video#localVideo');
if(videoElement.srcObject == null)
videoElement.srcObject = remoteStream;
console.log('entra a TRACK');
await remoteStream.addTrack(event.track, remoteStream);
// videoElement.play();
}
async function enviarLLamada(peerConnection)
{
await playVideoFromCamera(peerConnection);
}
document.addEventListener("DOMContentLoaded", function(event) {
if(cliente)
makeCallCliente();
// else
// makeCallAdmin();
});
</script>
I'm trying to make a simple chat using webrtc technology, react.js and meteor.js.
This is client code:
class Rtc extends Component {
constructor(props) {
super(props);
}
componentDidUpdate(){
let localVideo, remoteVideo, peerConnection, localStream;
$('#start').on('click', ()=>{ start(true) });
let id = Meteor.uuid();
localVideo = document.getElementById('localVideo');
remoteVideo = document.getElementById('remoteVideo');
if (!this.props.loadingRtc) {
this.props.messagesRtc.forEach((item, i ,arr)=>{
let signal = JSON.parse(item.text);
if(i == 0)return;
gotMessageFromServer(signal);
});
}
if(navigator.mediaDevices.getUserMedia) {
navigator.mediaDevices.getUserMedia( { video:true, audio:true}).then( ( stream )=> {
localStream = stream;
localVideo.src = window.URL.createObjectURL(stream);
}).catch(errorHandler);
} else { alert('Your browser does not support getUserMedia API'); }
function start(isCaller) {
peerConnection = new RTCPeerConnection( { 'iceServers': [{'urls': 'stun:stun.services.mozilla.com'}, {'urls': 'stun:stun.l.google.com:19302'},]});
peerConnection.onicecandidate = ( e ) => {
console.log('e.candidate', e.candidate);
if(e.candidate != null) {
Meteor.call('addMsgRtc', JSON.stringify({'ice': e.candidate, '_id':id}), id);
}
};
peerConnection.onaddstream = ( e )=>{
remoteVideo.src = window.URL.createObjectURL(e.stream);
};
peerConnection.addStream(localStream);
if(isCaller) {
peerConnection.createOffer().then(createdDescription).catch(errorHandler);
}
}
function gotMessageFromServer(signal) {
if(!peerConnection) start(false);
if(signal._id == id) return;
if(signal.sdp) {
peerConnection.setRemoteDescription(new RTCSessionDescription(signal.sdp)).then(()=> {
if(signal.sdp.type == 'offer') {
peerConnection.createAnswer().then(createdDescription).catch(errorHandler);
}
}).catch(errorHandler);
} else if(signal.ice) {
peerConnection.addIceCandidate(new RTCIceCandidate(signal.ice)).catch(errorHandler);
}
}
function createdDescription(description) {
peerConnection.setLocalDescription(description).then(()=> {
Meteor.call('addMsgRtc', JSON.stringify({'sdp':peerConnection.localDescription, '_id':id}), id);
}).catch(errorHandler);
}
function errorHandler(error) { console.log(error); }
}
render() {
return (
<div>
<video id="localVideo" autoPlay muted style={{width:"40%"}}></video>
<video id="remoteVideo" autoPlay style={{width:"40%"}}></video>
<br/>
<input type="button" id="start" value="Start Video"/>
</div>
);
}
}
export default createContainer( ()=> {
const subscriptionRtc = Meteor.subscribe('rtc');
const loadingRtc = !subscriptionRtc.ready();
return {
loadingRtc:loadingRtc,
messagesRtc: msgRtc.find().fetch(),
};
}, App);
Server code:
export const msgRtc = new Mongo.Collection('rtc');
let messagesRtc = [];
let clients = [];
Meteor.publish('rtc', function wsPub() {
clients.push(this);
_.each(messagesRtc, (message) => {
this.added('rtc', message._id, message);
});
this.ready();
});
Meteor.methods({
'addMsgRtc'(arr, id) {
let newMessage = {_id:id, 'text':arr};
messagesRtc.push(newMessage);
_.each(clients, (client) => {
client.added('rtc', id, newMessage);
});
},
The problem is that why after the initialization of getUserMedia does not want to further this videos and what not so I can't understand. Because it is actually a similar code with the usual websockets like this works and syncs fine.
UPD:
When you click on the button and call the function start.
TypeError: Argument 1 of RTCPeerConnection.addStream is not an object
If websockets to put in then then it turns out another error:
Code:
navigator.mediaDevices.getUserMedia( { video:true, audio:true}).then( ( stream )=> {
localStream = stream;
localVideo.src = window.URL.createObjectURL(stream);
}).catch(errorHandler).then(()=>{
if (!this.props.loadingRtc) {
for(let i of this.props.messagesRtc){
let signal = JSON.parse(i.text);
gotMessageFromServer(signal)
}
}
}).catch(errorHandler);
Error:
DOMException [InvalidStateError: "Cannot set remote offer or answer in
current state have-remote-offer" code: 11 nsresult: 0x8053000b]
app.js:11075:9 DOMException [InvalidStateError: "No outstanding offer"
code: 11 nsresult: 0x8053000b]