my webRTC implements never calls onaddstream - webrtc

I am using https://github.com/HenrikJoreteg/RTCPeerConnection which simplifies WebRTC but still cannot get it works. WebRTC peer connection (offer, answer, ice) get established but onaddstream never gets call.
(I open 2 browser tab with the same html which utilize the following code and I run the code by running start function to get the video and then running peer the start the connection.)
Can anyone help me point me out the bug in this code?
var local_stream;
var localvid = document.getElementById('localvid');
var remotevid = document.getElementById('remotevid');
var servers= {iceServers: [{"url": "stun:stun.l.google.com:19302"}]};
var constraints = {optional: [{"DtlsSrtpKeyAgreement": true}]};
var peerConn = new PeerConnection(servers,constraints);
function start(){
navigator.getUserMedia ||
(navigator.getUserMedia = navigator.getUserMedia || navigator.mozGetUserMedia ||
  navigator.webkitGetUserMedia || navigator.msGetUserMedia);
if (navigator.getUserMedia) {
navigator.getUserMedia({
      video: true,
      audio: false
    }, onSuccess, function(){});
} else {
    alert('getUserMedia is not supported in this browser.');
}
}
function onSuccess(stream){
localvid.src = window.webkitURL.createObjectURL(stream);
local_stream = stream;
localvid.autoplay = true;
}
function peer(){
peerConn.addStream(local_stream);
peerConn.offer({ mandatory: { OfferToReceiveAudio:false, OfferToReceiveVideo: true} },
function( err, offer){
if(!err){
console.log("Creating an offer...");
socket.emit('offer',offer);
}
}
);
}
peerConn.on('ice', function(candidate){
if(candidate){
console.log("Sending ice...");console.log(candidate);
socket.emit('ice',candidate);
}else { console.log("End of candidates.");}
});
peerConn.on('streamAdded',function(stream){
console.log("Adding stream..");
remotevid.src = window.webkitURL.createObjectURL(stream);
remotevid.autoplay = true;
});
socket.on('offer',function(offer){
peerConn.answer(offer,function (err,answer){
if(!err){
console.log("Creating the answer...");console.log(answer);
socket.emit('answer',answer);
}
});
});
socket.on('answer', function(answer){
console.log("Got the answer...");
peerConn.handleAnswer(answer);
});
socket.on('ice', function (candidate){
console.log("Processing ice...");
peerConn.processIce(candidate);
console.log(candidate);
});

OK. I got it to work now.
https://github.com/HenrikJoreteg/RTCPeerConnection
The document there is so wrong...
There is no 'streamAdded' event but 'addStream' event and the value inside is not stream but the event. So, I need to do as follow, instead.
peerConn.on('addStream',function(e){
remotevid.src = window.webkitURL.createObjectURL(e.stream);
remotevid.autoplay =true;
});

Related

Share screen using getScreenId.js in WebRTC for two peers

I am trying to implement share screen function in webrtc video conferencing. From suggestion, I am now following muaz-khan's solution using https://www.webrtc-experiment.com/getScreenId/ . I can easily capture the application images of one peer, and replace the video stream with the capture stream. But it is a video conferencing experiment, so two browsers need to video conference with each other. For example, browser 1, has video streams A (local video), video streams B (remote video); browser 2 has video streams B (local video), video streams A (remote video). So when I am in browser 1 and trying to share the screen, the share screen stream should replace the local video in browser 1, and remote video in browser 2.
But right now, I can only make the share screen replace the local video in browser 1, browser 2 doesn't have any changes, cann't see any changes in its remote video (which is the local video in browser 1). I don't know how to trigger the changes in browser 2 as well. do i need to signal the share screen streams to server? and change the remote stream accordingly?
Here is my code in javascript:
$(function() {
var brokerController, ws, webRTC, localid;
// ws = new XSockets.WebSocket("wss://rtcplaygrouund.azurewebsites.net:443", ["connectionbroker"], {
ws = new XSockets.WebSocket("ws://localhost:4502", ["connectionbroker"], {
ctx: "152300ed-4d84-4e72-bc99-965052dc1e95"
});
var addRemoteVideo = function(peerId,mediaStream) {
var remoteVideo = document.createElement("video");
remoteVideo.setAttribute("autoplay", "true");
remoteVideo.setAttribute("rel",peerId);
attachMediaStream(remoteVideo, mediaStream);
remoteVideo.setAttribute("class", "col-md-3");
remoteVideo.setAttribute("height", $( document ).height() * 0.3);
remoteVideo.setAttribute("id", 'remoteVideo');
$("#videoscreen").append(remoteVideo);
};
var onConnectionLost = function (remotePeer) {
console.log("onconnectionlost");
var peerId = remotePeer.PeerId;
var videoToRemove = $("video[rel='" + peerId + "']");
videoToRemove.remove();
};
var oncConnectionCreated = function() {
console.log("oncconnectioncreated", arguments);
}
var onGetUerMedia = function(stream) {
console.log("Successfully got some userMedia , hopefully a goat will appear..");
webRTC.connectToContext(); // connect to the current context?
};
var onRemoteStream = function (remotePeer) {
addRemoteVideo(remotePeer.PeerId, remotePeer.stream);
console.log("Opps, we got a remote stream. lets see if its a goat..");
};
var onLocalStream = function(mediaStream) {
console.log("Got a localStream", mediaStream.id);
localid = mediaStream.id;
console.log("check this id: meadiastram id ", mediaStream.id);
var video = document.createElement("video");
video.setAttribute("height", "100%");
video.setAttribute("autoplay", "true");
video.setAttribute("id", "localvideo");
video.setAttribute("name", mediaStream.id);
attachMediaStream(video, mediaStream);
$("#videoscreen").append(video);
$('#share').click(function() {
getScreenId(function (error, sourceId, screen_constraints) {
navigator.getUserMedia = navigator.mozGetUserMedia || navigator.webkitGetUserMedia;
navigator.getUserMedia(screen_constraints, function (stream) {
$('#localvideo').attr('src', URL.createObjectURL(stream));
}, function (error) {
console.error(error);
});
});
});
};
var onContextCreated = function(ctx) {
console.log("RTC object created, and a context is created - ", ctx);
webRTC.getUserMedia(webRTC.userMediaConstraints.hd(true), onGetUerMedia, onError);
};
var onOpen = function() {
console.log("Connected to the brokerController - 'connectionBroker'");
webRTC = new XSockets.WebRTC(this);
webRTC.onlocalstream = onLocalStream;
webRTC.oncontextcreated = onContextCreated;
webRTC.onconnectioncreated = oncConnectionCreated;
webRTC.onconnectionlost = onConnectionLost;
webRTC.onremotestream = onRemoteStream;
};
var onConnected = function() {
console.log("connection to the 'broker' server is established");
console.log("Try get the broker controller form server..");
brokerController = ws.controller("connectionbroker");
brokerController.onopen = onOpen;
};
ws.onconnected = onConnected;
});
I am using xsocket as the server, and the codes for click share and change the local stream with the share screen streams are just very simple as this:
$('#share').click(function() {
getScreenId(function (error, sourceId, screen_constraints) {
navigator.getUserMedia = navigator.mozGetUserMedia || navigator.webkitGetUserMedia;
navigator.getUserMedia(screen_constraints, function (stream) {
$('#localvideo').attr('src', URL.createObjectURL(stream));
}, function (error) {
console.error(error);
});
});
Any help or suggestion would be grateful.
Thanks for pointing out the other post: How to addTrack in MediaStream in WebRTC, but I don't think they are the same. And also I am not sure how to renegotiate the remote connection in this case.
Xsocket.webrtc.js file for webrtc connection:
https://github.com/XSockets/XSockets.WebRTC/blob/master/src/js/XSockets.WebRTC.latest.js
How I could I renegotiate the remote connection in this case?
I figured out a work around solution by myself for this question, do not replace the local stream with the sharescreen stream, instead remove the old local stream from local div, then add the new sharescreen stream to local div. In the meantime, send the old local stream id by datachanel to the other peer, and remove that old remote video as well.
The most important thing is reflesh the streams (renegotiation), then sharescreen stream would display in remote peer.
Code:
$('#share').click(function() {
getScreenId(function (error, sourceId, screen_constraints) {
navigator.getUserMedia = navigator.mozGetUserMedia || navigator.webkitGetUserMedia;
navigator.getUserMedia(screen_constraints, function (stream) {
webRTC.removeStream(webRTC.getLocalStreams()[0]);
var id = $('#localvideo').attr('name');
$('#localvideo').remove();
brokerController.invoke('updateremotevideo', id);
webRTC.addLocalStream(stream);
webRTC.getRemotePeers().forEach(function (p) {
webRTC.refreshStreams(p);
});
}, function (error) {
console.error(error);
});
});
});
after get the command to remove that old video stream from the server:
brokerController.on('updateremotevideo', function(streamid){
$(document.getElementById(streamid)).remove();
});
This solution works for me. Although if only like to replace the local video stream with share screen stream, we need to re create the offer with sdp, and send sdp to remote peer. It is more complicated.
getScreenId(function (error, sourceId, screen_constraints) {
navigator.getUserMedia = navigator.mozGetUserMedia || navigator.webkitGetUserMedia;
navigator.getUserMedia(screen_constraints, function (stream) {
navigator.getUserMedia({audio: true}, function (audioStream) {
stream.addTrack(audioStream.getAudioTracks()[0]);
var mediaRecorder = new MediaStreamRecorder(stream);
mediaRecorder.mimeType = 'video/mp4'
mediaRecorder.stream = stream;
self.setState({recorder: mediaRecorder, startRecord: true, shareVideo: true, pauseRecord: false, resumeRecord: false, stopRecord: false, downloadRecord: false, updateRecord: false});
document.querySelector('video').src = URL.createObjectURL(stream);
var video = document.getElementById('screen-video')
if (video) {
video.src = URL.createObjectURL(stream);
video.width = 360;
video.height = 300;
}
}, function (error) {
alert(error);
});
}, function (error) {
alert(error);
});
});

Add video track while navigator.getUserMedia in running

I'm trying to use navigator.getUserMedia() api for capturing the audio/video. I've following code.
var cameraEl;
window.URL = window.URL || window.webkitURL;
navigator.getUserMedia = (navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia);
navigator.getUserMedia(
{ video: true, audio: true },
function (stream) {
cameraEl = document.getElementById("selfCam");
cameraEl.src = window.URL.createObjectURL(stream);
window.mediaStream = stream;
},
function () {
alert('Error: Camera failed!');
}
);
Than I stop the video track like this,
window.mediaStream.getVideoTracks()[0].stop();
Now I want to start the video track again. How do I start it?
You need to call getUserMedia again. stop() is a final action.

rtcmulticonnection safari apple mac

I have my own rtcmulticonnection server up and running
I found this plugin https://github.com/muaz-khan/PluginRTC
But it doesn't seems to work
I get WebRTC 1.0 (RTCPeerConnection) API are NOT available in this
browser.
here my code (working in chrome and firefox but not in safari)
<div id="videos-container"></div>
<script src="js/rmc3.min.js').'"></script>
<script src="js/socket.io.js').'"></script>
<script src="js/Plugin.EveryWhere.js').'"></script>
<script>
var connection = new RTCMultiConnection();
connection.socketURL = "https://__MyDomain.com:9000/";
var roomid = "main_room";
connection.session = {
audio: true,
video: true
};
connection.sdpConstraints.mandatory = {
OfferToReceiveAudio: true,
OfferToReceiveVideo: true
};
var videosContainer = document.getElementById("videos-container");
connection.onstream = function(event) {
videosContainer.appendChild(event.mediaElement);
setTimeout(function() { event.mediaElement.play(); }, 5000);
};
connection.openOrJoin(roomid);
// *** Plugin.EveryWhere.js [BEGIN]
var Plugin = {};
window.onPluginRTCInitialized = function(pluginRTCObject) {
Plugin = pluginRTCObject;
MediaStreamTrack = Plugin.MediaStreamTrack;
RTCPeerConnection = Plugin.RTCPeerConnection;
RTCIceCandidate = Plugin.RTCIceCandidate;
RTCSessionDescription = Plugin.RTCSessionDescription;
};
if (!!window.PluginRTC) window.onPluginRTCInitialized(window.PluginRTC);
connection.onaddstream = function(event) {
if (isPluginRTC) {
var mediaElement = document.createElement("videos-container");
var body = (document.body || document.documentElement);
body.insertBefore(mediaElement, body.firstChild);
setTimeout(function() {
Plugin.attachMediaStream(mediaElement, event.stream);
// here you can append "mediaElement" to specific container
// specificContainer.appendChild(mediaElement);
}, 3000);
} else {
// do chrome/Firefox relevant stuff with "event.stream"
}
};
// *** Plugin.EveryWhere.js [END]
</script>
Is someone was able to make the plugin work ?
If yes how or what step did I missed ?
Thanks
RTCMultiConnection-v3.2.95 now supports IE/Safari:
https://github.com/muaz-khan/RTCMultiConnection/releases/tag/3.2.95
To support Safari/IE, please modify Gruntfile.js#L30 to enable dev/Plugin.EveryWhere.js.
Then don't forget calling grunt to recompile the codes.
Now set connection.trickleIce=false in your HTML file. And now video-conferencing/chat/etc. will work both among chrome/firefox/safari/IE.
Please install PluginRTC.dmg or PluginRTC.exe.
Additional notes:
You've to initiate calls from Safari/IE, because currently Safari/IE can not create answers. i.e. IE/Safari MUST call connection.open instead of calling connection.join.
Set this in your HTML: connection.processSdp = function(sdp) {return sdp;}; to prevent SDP conflicts/errors.

WebRTC/Socket.io Connecting two Clients / Signaling

I've updated my code with the complete signaling exchange. The problem now, is that upon completing the exchange, "socket.on('receivedAnswer')" throws an error. I'm testing all this on my local machine in two browser tabs so I assume I don't need ICE just yet for this to work...
<html>
<head>
<link rel = 'stylesheet' type = 'text/css' href= 'css.css'>
<script src="node_modules/socket.io/node_modules/socket.io-client/socket.io.js"></script>
</head>
<body>
<div id='video_box'>
<video id= 'video' autoplay="true">
</video>
</div>
<div id='video_box2'>
<video id='video2' autoplay="true">
</video>
<div>
<script>
var local_stream;
var baseURL = getBaseURL();
var socketIOPort = 8999;
var socketIOLocation = baseURL + socketIOPort;
var socket = io(socketIOLocation);
var localvid = document.getElementById('video');
var mediaOptions = { audio: false, video: true };
var pc = new mozRTCPeerConnection( {"iceServers": [{"url": "stun:stun.1.google.com:19302" }] });
var pc2 = new mozRTCPeerConnection();
var PeerConnection = window.RTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection;
var SessionDescription = window.RTCSessionDescription || window.mozRTCSessionDescription || window.webkitRTCSessionDescription;
var offerConstraints = {OfferToReceiveAudio: true, OfferToReceiveVideo: true }
socket.on('receivedAnswer', function(answerSDP){
pc.setRemoteDescription(new mozRTCSessionDescription(answerSDP), function(){
alert('received the answer');
}, error2);
});
socket.on('getPeer1', function(SDP) {
alert('got peer 1 SDP');
pc.setRemoteDescription(new mozRTCSessionDescription(SDP), function() {
pc.createAnswer(function(answerSDP){
pc.setLocalDescription(answerSDP, function() {
socket.emit('answerSDP', answerSDP);
alert('sending answer');
}, error2);
}, error2);
}, error2);
});
function start(){
checkMedia();
navigator.getUserMedia(mediaOptions, getMediaSuccess, error2);
}
function answer(offeredSDP){
offeredSDP = new SessionDescription(offeredSDP);
}
function peer(){
pc.addStream(local_stream);
pc.createOffer(function(SDP){
socket.emit('sendSDPtoServer', SDP);
}, error2, offerConstraints);
}
function getMediaSuccess(stream){
localvid.src = window.URL.createObjectURL(stream);
local_stream = stream;
peer(); ///////////
}
function error2(){
alert('error');
}
function error3(){
alert('error here');
}
function checkMedia() {
if (!navigator.getUserMedia) {
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
}
if (!navigator.getUserMedia){
alert('getUserMedia not supported in this browser.');
}
}
function getBaseURL(){
baseURL = location.protocol + "//" + location.hostname + ":" + location.port;
return baseURL;
}
start();
//alert('script');
</script>
</body>
</html>
Server
var static = require('node-static');
var express = require('express');
var app = express();
var port = 8999;
var http = require('http');
var file= new(static.Server)();
var io = require('socket.io').listen(app.listen(port));
var connectedClients = {};
var peer1 = 0;
var peer2 = 0;
var peer1sdp = 0;
var peer2sdp = 0;
app.set('views', __dirname)
.engine('html', require('ejs').renderFile)
.use(express.static(__dirname + '/public'))
.get('/', function(req, res) {
//res.render('indexcpy.html');
});
io.on('connection', function(socket) {
console.log('a user connected');
socket.on('disconnect', function(){
console.log('user disconnected');
});
socket.on('answerSDP', function(answerSDP){
console.log('ANSWER SENT');
io.to(peer1).emit('receivedAnswer', answerSDP);
});
socket.on('sendSDPtoServer', function(SDP) {
if(peer1 == 0){
console.log('peer 1 ' + socket.id + ' has sent its SDP to server');
peer1 = socket.id;
peer1sdp = SDP;
} else {
console.log('peer 2 ' + socket.id + ' has been sent to the server');
socket.emit('getPeer1', peer1sdp);
}
});
});
the mistake here is your assumption that, pc.addStream(stream) would fire pc.onstream(event) on the same peer, but it would actually be fired on the remote peer.
Reference
other that that, your webrtc code is incomplete, while your offer SDP reaches the server, it is not sent to the remote peer and also it's answer has to be forwarded to your peer and so on...
You have to make sure that before creating Answer your local stream is added to the peerconnection. It will be more clear if you show where you are generating the answer

How to record a video using webrtc

I need to record a video using the laptop camera on my website built using nodejs. For this I am using webRTC. So far I could take a photo using the laptop camera but I need to record a video. Could some one help as to how the code would go? My current code is as follows:
<video id="video"></video>
<button id="startbutton">Take photo</button>
<button id="pausebutton">Pause</button>
<button id="resumebutton">Resume</button>
<canvas id="canvas"></canvas>
<script type="text/javascript">
(function() {
var streaming = false,
video = document.querySelector('#video'),
canvas = document.querySelector('#canvas'),
//photo = document.querySelector('#photo'),
startbutton = document.querySelector('#startbutton'),
width = 620,
height = 50;
navigator.getMedia = ( navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia);
navigator.getMedia(
{
video: true,
audio: false
},
function(stream) {
if (navigator.mozGetUserMedia) {
video.mozSrcObject = stream;
} else {
var vendorURL = window.URL || window.webkitURL;
video.src = vendorURL.createObjectURL(stream);
}
video.play();
},
function(err) {
console.log("An error occured! " + err);
}
);
video.addEventListener('canplay', function(ev){
if (!streaming) {
height = video.videoHeight / (video.videoWidth/width);
video.setAttribute('width', width);
video.setAttribute('height', height);
canvas.setAttribute('width', width);
canvas.setAttribute('height', height);
streaming = true;
}
}, false);
function takepicture() {
canvas.width = width;
canvas.height = height;
canvas.getContext('2d').drawImage(video, 0, 0, width, height);
var data = canvas.toDataURL('image/png');
// photo.setAttribute('src', data);
}
function pausevideo() {
canvas.width = width;
canvas.height = height;
video.pause();
}
function resumevideo() {
canvas.width = width;
canvas.height = height;
video.play();
}
startbutton.addEventListener('click', function(ev){
takepicture();
ev.preventDefault();
}, false);
pausebutton.addEventListener('click', function(ev){
pausevideo();
ev.preventDefault();
}, false);
resumebutton.addEventListener('click', function(ev){
resumevideo();
ev.preventDefault();
}, false);
})();
</script>
I am not going to write code for you(you seem pretty capable if you have gotten this far) but here are some pointers to get you in the right direction.
Assign a global variable the value of the stream when you grab it(this way you can reuse the same stream in numerous functions
Once you have the stream you can easily follow the tutorials at RTC-Recording, there is a write to disk method that should help you out in downloading the recording
If you have a stream, this is how to start using RecordRTC.
var options = {
type: 'video'
};
var recordRTC = RecordRTC(mediaStream, options);
recordRTC.startRecording();
recordRTC.stopRecording(function(videoURL) {
mediaElement.src = videoURL; //plays the recorded blob url on that src
});