I am trying out the sample code for peer-to-peer webcam communication in http://www.html5rocks.com/en/tutorials/webrtc/basics/ where both clients are implemented in the same page.
The 'local' webcam stream is displayed correctly. However, nothing shows up on the 'remote' stream and I'm not sure why.
Below is my code. I am currently testing it out on a hosted server. Thanks!
var localStream;
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia || navigator.msGetUserMedia;
window.URL = window.URL || window.webkitURL;
navigator.getUserMedia({'audio':true, 'video':true}, onMediaSuccess, onMediaFail);
function onMediaSuccess(stream) {
var localVideo = document.getElementById("localVideo");
var url = window.URL.createObjectURL(stream);
localVideo.autoplay = true;
localVideo.src = url;
localStream = stream;
console.log('Local stream established: ' + url);
}
function onMediaFail() {
alert('Could not connect stream');
}
function iceCallback1(){}
function iceCallback2(){}
function gotRemoteStream(e) {
var remoteVideo = document.getElementById("remoteVideo");
var stream = e.stream;
var url = window.URL.createObjectURL(stream);
remoteVideo.autoplay = true;
remoteVideo.src = url;
console.log('Remote stream received: ' + url);
}
function call(){
pc1 = new webkitPeerConnection00(null, iceCallback1); // create the 'sending' PeerConnection
pc2 = new webkitPeerConnection00(null, iceCallback2); // create the 'receiving' PeerConnection
pc2.onaddstream = gotRemoteStream; // set the callback for the receiving PeerConnection to display video
console.log("Adding local stream to pc1");
pc1.addStream(localStream); // add the local stream for the sending PeerConnection
console.log("Creating offer");
var offer = pc1.createOffer({audio:true, video:true}); // create an offer, with the local stream
console.log("Setting local description for pc1");
pc1.setLocalDescription(pc1.SDP_OFFER, offer); // set the offer for the sending and receiving PeerConnection
console.log("Start pc1 ICE");
pc1.startIce();
console.log("Setting remote description for pc2");
pc2.setRemoteDescription(pc2.SDP_OFFER, offer);
// gotRemoteStream Triggers here
console.log("Creating answer"); // create an answer
var answer = pc2.createAnswer(offer.toSdp(), {has_audio:true, has_video:true});
console.log("Setting local description for pc2");
pc2.setLocalDescription(pc2.SDP_ANSWER, answer); // set it on the sending and receiving PeerConnection
console.log("Setting remote description for pc1");
pc1.setRemoteDescription(pc1.SDP_ANSWER, answer);
console.log("Start pc2 ICE");
pc2.startIce(); // start the connection process
console.log("script done");
}
Try this:
simpl.info RTCPeerConnectionby Vikas Marwaha and Justin Uberti
http://www.simpl.info/rtcpeerconnection/
It's working well for me and it's very clean and simple.
Related
I have a problem I have these files in js that I need to create a webrtc. The problem is that hosting doesn't support nodejs. i was wondering if it was possible to change them in js to make it work. Can I copy the request files that I do to require ("node-static") and put them in the hosting?
Help me I don't know how to proceed. Thanks so much
server.js
var static = require('node-static');
var https = require('https');
var util = require('util');
var file = new(static.Server)();
var app = https.createServer(function (req, res) {
file.serve(req, res);
}).listen(443);
var io = require('socket.io').listen(app);
io.sockets.on('connection', function (socket){
// convenience function to log server messages on the client
function log(){
var array = [">>> Message from server: "];
for (var i = 0; i < arguments.length; i++) {
array.push(arguments[i]);
}
socket.emit('log', array);
}
// when receive sdp, broadcast sdp to other user
socket.on('sdp', function(data){
console.log('Received SDP from ' + socket.id);
socket.to(data.room).emit('sdp received', data.sdp);
});
// when receive ice candidate, broadcast sdp to other user
socket.on('ice candidate', function(data){
console.log('Received ICE candidate from ' + socket.id + ' ' + data.candidate);
socket.to(data.room).emit('ice candidate received', data.candidate);
});
socket.on('message', function (message) {
log('Got message:', message);
// for a real app, would be room only (not broadcast)
socket.broadcast.emit('message', message);
});
socket.on('create or join', function (room) {
// join room
var existingRoom = io.sockets.adapter.rooms[room];
var clients = [];
if(existingRoom){
clients = Object.keys(existingRoom);
}
if(clients.length == 0){
socket.join(room);
io.to(room).emit('empty', room);
}
else if(clients.length == 1){
socket.join(room);
socket.to(room).emit('joined', room, clients.length + 1);
}
// only allow 2 users max per room
else{
socket.emit('full', room);
}
});
socket.on('error', function(error){
console.error(error);
})
});
main.js
"use strict"
//my signalling server
var serverIP = "https://www.website.com/";
// RTCPeerConnection Options
var server = {
// Uses Google's STUN server
iceServers: [{
"urls" :
navigator.mozGetUserMedia ? "stun:stun.services.mozilla.com" :
navigator.webkitGetUserMedia ? "stun:stun.l.google.com:19302" :
"stun:23.21.150.121"
}
]
};
var localPeerConnection, signallingServer;
var localStream, localIsCaller;
function disconnect() {
var localVideo = document.getElementById('from-video');
var remoteVideo = document.getElementById('to-video');
// stop video stream
if (localStream != null) {
let tracks = localStream.getTracks();
tracks.forEach(function(track) {
track.stop();
});
}
// kill all connections
if (localPeerConnection != null) {
localPeerConnection.getSenders().forEach(function(sender){
localStream.getTracks().forEach(function(track){
if(track == sender.track){
localPeerConnection.removeTrack(sender);
}
})
});
localPeerConnection.close();
signallingServer.close();
localVideo.src = "";
remoteVideo.src = "";
}
}
// WEBRTC STUFF STARTS HERE
// Set objects as most are currently prefixed
window.RTCPeerConnection = window.RTCPeerConnection || window.mozRTCPeerConnection ||
window.webkitRTCPeerConnection || window.msRTCPeerConnection;
window.RTCSessionDescription = window.RTCSessionDescription || window.mozRTCSessionDescription ||
window.webkitRTCSessionDescription || window.msRTCSessionDescription;
navigator.getUserMedia = navigator.getUserMedia || navigator.mozGetUserMedia ||
navigator.webkitGetUserMedia || navigator.msGetUserMedia;
window.SignallingServer = window.SignallingServer;
var sdpConstraints = {
optional: [],
mandatory: {
OfferToReceiveVideo: true,
}
}
function connect_video(room) {
// create peer connection
localPeerConnection = new RTCPeerConnection(server);
// create local data channel, send it to remote
navigator.getUserMedia({
video: true,
audio: true
}, function(stream) {
// get and save local stream
trace('Got stream, saving it now and starting RTC conn');
// must add before calling setRemoteDescription() because then
// it triggers 'addstream' event
localPeerConnection.addStream(stream);
localStream = stream;
// show local video
var localVideo = document.getElementById('from-video');
localVideo.srcObject = stream;
localVideo.onloadedmetadata = function(e) {
localVideo.play();
};
// can start once have gotten local video
establishRTCConnection(room);
}, errorHandler)
}
function connect_audio(room) {
// create peer connection
localPeerConnection = new RTCPeerConnection(server);
// create local data channel, send it to remote
navigator.getUserMedia({
video: false,
audio: true
}, function(stream) {
// get and save local stream
trace('Got stream, saving it now and starting RTC conn');
// must add before calling setRemoteDescription() because then
// it triggers 'addstream' event
localPeerConnection.addStream(stream);
localStream = stream;
// show local video
var localVideo = document.getElementById('from-video');
localVideo.srcObject = stream;
localVideo.onloadedmetadata = function(e) {
localVideo.play();
};
// can start once have gotten local video
establishRTCConnection(room);
}, errorHandler)
}
function establishRTCConnection(room) {
// create signalling server
signallingServer = new SignallingServer(room, serverIP);
signallingServer.connect();
// a remote peer has joined room, initiate sdp exchange
signallingServer.onGuestJoined = function() {
trace('guest joined!')
// set local description and send to remote
localPeerConnection.createOffer(function(sessionDescription) {
trace('set local session desc with offer');
localPeerConnection.setLocalDescription(sessionDescription);
// send local sdp to remote
signallingServer.sendSDP(sessionDescription);
});
}
// got sdp from remote
signallingServer.onReceiveSdp = function(sdp) {
// get stream again
localPeerConnection.addStream(localStream);
trace(localStream)
// if local was the caller, set remote desc
if (localIsCaller) {
trace('is caller');
trace('set remote session desc with answer');
localPeerConnection.setRemoteDescription(new RTCSessionDescription(
sdp));
}
// if local is joining a call, set remote sdp and create answer
else {
trace('set remote session desc with offer');
localPeerConnection.setRemoteDescription(new RTCSessionDescription(
sdp), function() {
trace('make answer')
localPeerConnection.createAnswer(function(
sessionDescription) {
// set local description
trace('set local session desc with answer');
localPeerConnection.setLocalDescription(
sessionDescription);
// send local sdp to remote too
signallingServer.sendSDP(sessionDescription);
});
});
}
}
// when received ICE candidate
signallingServer.onReceiveICECandidate = function(candidate) {
trace('Set remote ice candidate');
localPeerConnection.addIceCandidate(new RTCIceCandidate(candidate));
}
// when room is full
signallingServer.onRoomFull = function(room) {
console.log('Room "' + room +
'"" is full! Please join or create another room');
}
// get ice candidates and send them over
// wont get called unless SDP has been exchanged
localPeerConnection.onicecandidate = function(event) {
if (event.candidate) {
//!!! send ice candidate over via signalling channel
trace("Sending candidate");
signallingServer.sendICECandidate(event.candidate);
}
}
// when stream is added to connection, put it in video src
localPeerConnection.ontrac = function(data) {
var remoteVideo = document.getElementById('to-video');
remoteVideo.srcObject = data.stream;
remoteVideo.onloadedmetadata = function(e) {
remoteVideo.play();
};
}
}
function errorHandler(error) {
console.log('Something went wrong!');
console.log(error);
}
function trace(text) {
console.log(text);
}
and another file like signalling.js, adapter.js, socket.io.js
No you can't. You'll need hosting that has nodejs support or one in which you can run a vm.
These scripts are server-side scripts and they need to run on the server at all times.
Making them run client-side makes no sense as there would be no place to connect to.
My goal: send some video stream from one client to another throught node.js server. But I can`t even send video from first cleint to server.
Cleint
var socket = io(":9966");
socket.on('message', function (data) {
console.log(data)
})
function onVideoFail(e) {
console.log('webcam fail!', e);
};
window.URL = window.URL || window.webkitURL;
navigator.getUserMedia = navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia;
var video = document.querySelector('video');
navigator.getUserMedia({video: true}, function(stream) {
console.log(stream);
video.src = window.URL.createObjectURL(stream);
var arrayOfStreams = [stream];
var medias = new MediaStreamRecorder(stream);
medias.ondataavailable = function(blob) {
socket.emit("streaming", blob);
};
medias.start();
socket.emit("streaming", stream);
socket.emit('test', 'mess from 1');
}, onVideoFail);
Server
io.on('connection', function (socket) {
log.info('new con!', socket.id);
socket.send("you connected to server");
socket.on('test', function (data) {
console.log(data);
socket.broadcast.send(data);
});
socket.on('streaming', function (stream) {
log.info("i`m in stream", socket.id);
log.info(stream);
socket.broadcast.emit('streaming', stream);
});
});
I can send text and everything great, but when I send stream to server I get empty value.
What I see on server side
I looked for some tips and found, but still not working. Maybe I missed something.
Can anyone help me?
PS I getting video from video tag
convert your media to base64, this way the server reads it as a string of texts and returns it back
Question is closed. As I red its hard to make live stream. If somebody reading this, check this link https://developer.mozilla.org/en-US/docs/Web/API/MediaRecorder . What you must understand: record little part of video and send it to server. Hope it`s will help.
I am using the code below to record audio in the browser, then use socket.io to send the resulting blob to a node.js server. The data is then saved to a mysql database or as an .ogg file.
The playback from either is strangely garbled at times - in different moments the sound will suddenly accelerate then return to normal. I've not been able to find anything online about this issue.
UPDATE: Further testing leads me to believe it is a hardware/software/compatibility with the Asus D1 soundcard I'm using. recording off of other devices does not result in the same behavior.
var mediaRecorder;
var startRecord = function(recordData){
if (!navigator.getUserMedia)
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia || navigator.msGetUserMedia;
if (navigator.getUserMedia) {
navigator.getUserMedia({audio:true}, success, function(stream) {
alert('Error capturing audio.');
});
} else alert('getUserMedia not supported in this browser.');
function success(stream) {
var chunks = [];
mediaRecorder = new MediaRecorder(stream);
mediaRecorder.start();
mediaRecorder.onstop = function(e) {
stream.getAudioTracks()[0].stop()
var blob = new Blob(chunks, { 'type' : 'audio/ogg; codecs=opus' })
var audioURL = URL.createObjectURL(blob);
if (recordData.id) {
socket.emit('audio', {
'id':recordData.id,
'audio':blob,
'option':recordData.type
});
}
mediaRecorder.ondataavailable = function(e) {
chunks.push(e.data);
}
}
};
var stopRecord = function(recordData){
mediaRecorder.stop();
mediaRecorder.state = 'recording'
};
I'm having an issue with decodeAudioData method using Web Audio API to playback in Chrome (it works fine in Firefox)-
I am sending the audio buffer recorded by media recorder back from the server.
Server side
wss = new WebSocketServer({server: server}, function () {});
wss.on('connection', function connection(ws) {
ws.binaryType = "arraybuffer";
ws.on('message', function incoming(message) {
if ((typeof message) == 'string') {
console.log("string message: ", message);
} else {
console.log("not string: ", message);
ws.send(message);
}
});
});
Client side
window.AudioContext = window.AudioContext||window.webkitAudioContext;
navigator.getUserMedia = (navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia);
var context = new AudioContext();
var mediaRecorder;
var chunks = [];
var startTime = 0;
ws = new WebSocket(url);
ws.binaryType = "arraybuffer";
ws.onmessage = function(message) {
if (message.data instanceof ArrayBuffer) {
context.decodeAudioData(message.data, function(soundBuffer){
playBuffer(soundBuffer);
},function(x) {
console.log("decoding failed", x)
});
} else {
console.log("not arrayBuffer", message.data);
}
};
createMediaRecorder();
function createMediaRecorder() {
if (navigator.getUserMedia) {
console.log('getUserMedia supported.');
var constraints = {
"audio": true
};
var onSuccess = function(stream) {
var options = {
audioBitsPerSecond : 128000,
mimeType : 'audio/webm\;codecs=opus'
};
mediaRecorder = new MediaRecorder(stream, options);
};
var onError = function(err) {
console.log('The following error occured: ' + err);
};
navigator.getUserMedia(constraints, onSuccess, onError);
} else {
alert('getUserMedia not supported on your browser!');
}
}
function playBuffer(buf) {
var source = context.createBufferSource();
source.buffer = buf;
source.connect(context.destination);
if (startTime == 0)
startTime = context.currentTime + 0.1; // add 50ms latency to work well across systems
source.start(startTime);
startTime = startTime + source.buffer.duration;
}
function startRecording() {
mediaRecorder.start();
getRecordedData();
}
function getRecordedData() {
mediaRecorder.ondataavailable = function(e) {
console.log('ondataavailable: ', e.data);
chunks.push(e.data);
};
}
function sendRecordedData() {
var superBuffer = new Blob(chunks, {type: 'audio/ogg'});
ws.send(superBuffer);
}
function stopRecording() {
mediaRecorder.stop();
mediaRecorder.onstop = function(e) {
sendRecordedData();
chunks = [];
};
}
While testing with firefox working fine but with chrome generate the following error:
Uncaught (in promise) DOMException: Unable to decode audio data
Any suggestion will be helpful, thanks in advance.
I encountered the same error. Updating Chrome did not fix it. However, debugging in Firefox instead gave me a much more descriptive error:
The buffer passed to decodeAudioData contains an unknown content type.
Uncaught (in promise) DOMException: MediaDecodeAudioDataUnknownContentType
Uncaught (in promise) DOMException: The given encoding is not supported.
Which by the way was occurring because the .mp3 file I wanted to load wasn't found. So I was making a web request, receiving the 404 HTML page, and trying to load that as an mp3, which failed as an 'unsupported audio format'.
I encountered the same issue. Upgrading Chrome to the latest release, eg 85.0.4183, resolved the issue for me.
I Had the same error with createjs (I used to load up the files).
It was integration problem with Internet Download Manager (IDM) ... I've solved it by disabling IDM !
i start do some test with rtcPeerConnection, i'm a begginer with this tecnologic and i want to know if it is normal:
in the console i print the ice candidate when method onicecandidate is called, but i don't know if is normal have many RTCIceCandidate appearing in the console
here the output console
var isChrome = !!navigator.webkitGetUserMedia;
var STUN = {
url: isChrome
? 'stun:stun.l.google.com:19302'
: 'stun:23.21.150.121'
};
var TURN = {
url: 'turn:homeo#turn.bistri.com:80',
credential: 'homeo'
};
var iceServers = {
iceServers: [STUN, TURN]
};
var sdpConstraints = {
optional: [],
mandatory: {
OfferToReceiveAudio: true,
OfferToReceiveVideo: true
}
};
var video = document.getElementById('thevideo');
var button = document.getElementById('thebutton');
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
RTCPeerConnection = webkitRTCPeerConnection || mozRTCPeerConnection;
var local_stream;
navigator.getUserMedia({video:true, audio:false}, function(stream){
local_stream = stream;
video.src = URL.createObjectURL(stream);
start();
}, function(err){
console.log("The Following error ocurred:"+ err);
});
function start()
{
pc = new RTCPeerConnection(iceServers);
pc.onicecandidate = function(evt)
{
console.log(evt.candidate);
}
pc.createOffer(function(desc)
{
pc.setLocalDescription(desc);
console.log(desc);
},function(err){
console.log("The Following error ocurred:"+ err);
},sdpConstraints);
}
Yes -- that many ICE candidates is normal. (You'll get a similar result from apprtc.appspot.com.)
Note that to display the video you'll need an autoplay attribute on the video element, or video.play() in the gUM success handler.