I am creating a small WebRTC app that for now used to exchange text message. I have got the WebRTC connection working but Datachannel always remains in "connecting" state and never goes to "Open".
Please tell me what I am missing here.
Following is the JS.
socket.onmessage = function(e){
console.log("Message from signaling server");
writeToScreen('<span class="server">Server: </span>'+e.data);
var data = JSON.parse(e.data);
switch(data.type) {
case "login":
onLogin(data.success);
break;
case "offer":
onOffer(data.offer, data.name);
break;
case "answer":
onAnswer(data.answer);
break;
case "candidate":
onCandidate(data.candidate);
break;
default:
break;
}
}
// Enable send and close button
$('#send').prop('disabled', false);
$('#close').prop('disabled', false);
$('#connect').prop('disabled', true);
}
function close(){
socket.close();
}
function writeToScreen(msg){
var screen = $('#screen');
screen.append('<p>'+msg+'</p>');
screen.animate({scrollTop: screen.height()}, 10);
}
function clearScreen(){
$('#screen').html('');
}
function sendMessage(){
if(!socket || socket == undefined) return false;
var mess = $.trim($('#message').val());
if(mess == '') return;
writeToScreen('<span class="client">Client: </span>'+mess);
socket.send(mess);
// Clear input
$('#message').val('');
}
$(document).ready(function(){
$('#message').focus();
$('#frmInput').submit(function(){
sendMessage();
});
$('#connect').click(function(){
connect();
});
$('#close').click(function(){
close();
});
$('#clear').click(function(){
clearScreen();
});
});
if (!window.RTCPeerConnection) {
window.RTCPeerConnection = window.webkitRTCPeerConnection;
}
var configuration = {
"iceServers": [
{
"urls": "stun:mmt-stun.verkstad.net"
},
{
"urls": "turn:mmt-turn.verkstad.net",
"username": "webrtc",
"credential": "secret"
}
]
};
myConnection = new RTCPeerConnection(configuration,{optional:[{RtpDataChannels: true},{DtlsSrtpKeyAgreement: true}]});
console.log("RTCPeerConnection object was created");
console.log(myConnection);
openDataChannel();
//when the browser finds an ice candidate we send it to another peer
myConnection.onicecandidate = function (event) {
console.log(event.candidate);
if (event.candidate) {
send({
type: "candidate",
candidate: event.candidate
});
}
};
// Datachannel
var mediaConstraints = {
'offerToReceiveAudio': 1,
'offerToReceiveVideo': 1
};
var connectToOtherUsernameBtn = document.getElementById("connectToOtherUsernameBtn");
console.log(connectToOtherUsernameBtn);
connectToOtherUsernameBtn.addEventListener("click", function () {
console.log("ice state : "+myConnection.iceGatheringState);
var otherUsername = connectToOtherUsernameBtn.value;
connectedUser = otherUsername;
if (otherUsername.length > 0) {
//make an offer
myConnection.createOffer(function (offer) {
send({
type: "offer",
offer: offer
});
console.log(offer);
console.log(typeof(offer));
myConnection.setLocalDescription(offer);
console.log("localDescription");
console.log(myConnection.localDescription);
}, function (error) {
alert("An error has occurred.");
console.log(error);
});
}
});
function send(message) {
if (connectedUser) {
message.name = connectedUser;
}
socket.send(JSON.stringify(message));
};
//when somebody wants to call us
function onOffer(offer, name) {
console.log("offer recieved");
connectedUser = name;
myConnection.setRemoteDescription(new RTCSessionDescription(offer));
myConnection.createAnswer(function (answer) {
myConnection.setLocalDescription(answer);
send({
type: "answer",
answer: answer
});
}, function (error) {
alert("oops...error");
console.log(error);
});
console.log("Answer sent");
}
//when another user answers to our offer
function onAnswer(answer) {
console.log("answer recieved");
myConnection.setRemoteDescription(new RTCSessionDescription(answer));
console.log(myConnection.iceConnectionState );
}
//when we got ice candidate from another user
function onCandidate(candidate) {
myConnection.addIceCandidate(new RTCIceCandidate(candidate));
}
});
//data channel
//creating data channel
function openDataChannel() {
console.log("opening Data Channel");
var dataChannelOptions = {
reliable:true,
};
dataChannel = myConnection.createDataChannel("myDataChannel",dataChannelOptions);
dataChannel.onerror = function (error) {
console.log("Error:", error);
};
dataChannel.onmessage = function (event) {
console.log("Got message:", event.data);
};
}
function sendmsg() {
console.log("send message");
var msgInput=document.getElementById("msgInput");
var val = msgInput.value;
console.log(val);
dataChannel.send(val);
}
function checkstatus(){
console.log("Checking Status");
console.log("signalingState: "+myConnection.signalingState);
console.log("iceConnectionState: "+myConnection.iceConnectionState);
console.log("iceGatheringState: "+myConnection.iceGatheringState);
console.log("localDescription: ");
console.log(myConnection.localDescription);
console.log("remoteDescription:");
console.log(myConnection.remoteDescription);
console.log("Connestion id");
console.log(dataChannel.id);
console.log("Connestion readyState");
console.log(dataChannel.readyState);
}
Following is the console log from chrome.
remove {RtpDataChannels: true}
try again and if it works burn the tutorial or book which recommended those "rtp data channels". They are broken.
I had the same problem. my code was working fine on mozilla using localhost signalling server without internet but on chrome i had this problem. Its Trickle ICE problem.
one solution is you may set trickle ice off.
In chrome, may be you need the internet connection to gather the all possible ICE candidates. because in Chrome Datachannel will not get opened untill peer get all possible ICE candidates.
you can try the following link with internet or without internet. you will have brief idea.
https://webrtc.github.io/samples/src/content/peerconnection/trickle-ice/
for further information you can check this
https://webrtcstandards.info/webrtc-trickle-ice/
Related
Anytime I call the session.disconnect() method to remove clients from the session, I get this warning: "OpenTok:Publisher:warn Received connectivity event: "Cancel" without "Attempt"
and this error: "OpenTok:Subscriber:error Invalid state transition: Event 'disconnect' not possible in state 'disconnected'"
Could someone please explain to me what that error means? Thanks in advance.
// Initialize the session
var session = OT.initSession(data['apikey'], data['session_id']);
console.log(session);
// Initialize the publisher for the recipient
var publisherProperties = {insertMode: "append", width: '100%', height: '100%'};
var publisher = OT.initPublisher('publisher', publisherProperties, function (error) {
if (error) {
console.log(`Couldn't initialize the publisher: ${error}`);
} else {
console.log("Receiver publisher initialized.");
}
});
$('#session-modal').modal("show");
// Detect when new streams are created and subscribe to them.
session.on("streamCreated", function (event) {
console.log("New stream in the session");
var subscriberProperties = {insertMode: 'append', width: '100%', height: '100%'};
var subscriber = session.subscribe(event.stream, 'subscriber', subscriberProperties, function(error) {
if (error) {
console.log(`Couldn't subscribe to the stream: ${error}`);
} else {
console.log("Receiver subscribed to the sender's stream");
}
});
});
//When a stream you publish leaves a session, the Publisher object dispatches a streamDestroyed event:
publisher.on("streamDestroyed", function (event) {
console.log("The publisher stopped streaming. Reason: "
+ event.reason);
});
//When a stream, other than your own, leaves a session, the Session object dispatches a streamDestroyed event:
session.on("streamDestroyed", function (event) {
console.log("Stream stopped. Reason: " + event.reason);
session.disconnect();
console.log("called session.disconnect().");
});
session.on({
connectionCreated: function (event) {
connectionCount++;
if (event.connection.connectionId != session.connection.connectionId) {
console.log(`Another client connected. ${connectionCount} total.`);
}
},
connectionDestroyed: function connectionDestroyedHandler(event) {
connectionCount--;
console.log(`A client disconnected. ${connectionCount} total.`);
}
});
// Connect to the session
// If the connection is successful, publish an audio-video stream.
session.connect(data['token'], function(error) {
if (error) {
console.log("Error connecting to the session:", error.name, error.message);
} else {
console.log("Connected to the session.");
session.publish(publisher, function(error) {
if (error) {
console.log(`couldn't publish to the session: ${error}`);
} else {
console.log("The receiver is publishing a stream");
}
});
}
});
// Stop the publisher from streaming to the session if the user dismiss the modal
const stopSession = document.getElementById('stop-session');
stopSession.addEventListener("click", (event) => {
event.preventDefault();
session.disconnect();
});
I see this is kind of old, but wanted to share my solution to avoid this error. I'm not sure what the error means, but I call publisher.destroy() before calling session.disconnect() to avoid the error.
openTokPublisher.destroy();
openTokSession.disconnect();
I highly doubt you can disconnect the client with JavaScript. Here what I did.
// Connect to the session
session.connect(token, function connectCallback(error) {
// Get the connectionId
connectionId = session.connection.connectionId;
and use one of their SDK on the backend
https://tokbox.com/developer/sdks/server/
// Disconnect session
function disconnectSession() { // eslint-disable-line no-unused-vars
if (sessionId && connectionId) {
$.ajax({
url: '/OpenTok/DisconnectSession',
type: 'POST',
data: 'sessionId=' + sessionId + '&connectionId=' + connectionId,
});
}
}
I have simple nodejs app with sockets and I've faced an error where I can't find any solution. So I'm emiting from app to client and nothing happens there. Or client can't receive it - I don't know, because I can't check if it was successfully emited to client. This is the error I got when I tried to debug callback of emit:
Error: Callbacks are not supported when broadcasting
This my app code:
http.listen(6060, function () {
console.log("Listening on *: 6060");
});
io.set('authorization', function (handshakeData, accept) {
var domain = handshakeData.headers.referer.replace('http://', '').replace('https://', '').split(/[/?#]/)[0];
if ('***' == domain) {
accept(null, true);
} else {
return accept('You must be logged in to take an action in this site!', false);
}
});
io.use(function (sock, next) {
var handshakeData = sock.request;
var userToken = handshakeData._query.key;
if (typeof userToken !== null && userToken !== 0 && userToken !== '0' && userToken.length > 0) {
connection.query('***',
[xssfilter.filter(validator.escape(userToken))],
function (error, data) {
if (error) {
debug('Cant receive user data from database by token');
next(new Error('Failed to parse user data! Please login!'));
} else {
// load data to this user.
_updateUsers(xssfilter.filter(validator.escape(userToken)), 'add', data[0], sock.id);
_loadPreData();
next(null, true);
}
});
} else {
debug('Cant receive user token');
next(new Error('Failed to parse user data! Please login!'));
}
sock.on("disconnect", function () {
_updateUsers(false, 'remove', false, sock.id);
});
});
// we need to show people online count
io.emit('online-count', {
count: Object.keys(connectedUsers).length
});
And the function used above:
function _updateUsers(userToken, action, userData, sockedID) {
switch (action) {
case 'add':
connectedUsers[sockedID] = {...};
io.emit('online-count', io.emit('online-count', {
count: Object.keys(connectedUsers).length
}););
break;
case 'remove':
delete connectedUsers[sockedID];
io.emit('online-count', io.emit('online-count', {
count: Object.keys(connectedUsers).length
}););
break;
}
}
so after emiting online-count I should accept it on the client side as I'm doing it:
var socket;
socket = io(globalData.socketConn, {query: "key=" + globalData.userData.token});
socket.on('connect', function (data) {
console.log('Client side successfully connected with APP.');
});
socket.on('error', function (err) {
error('danger', 'top', err);
});
socket.on('online-count', function (data) {
console.log('Got online count: ' + data.count);
$('#online_count').html(data.count);
});
but the problem is with this online-count.. Nothing happens and it seems that it's not was even sent from node app. Any suggestions?
The problem was with my logic - I was sending online count only if new user were connecting/disconnecting. Problem were solved by adding function to repeat itself every few seconds and send online count to client side.
Dear friends I am trying to build test application which allows to connect a browser window to itself (streming video data from user's camera).The final result is to get two video streams on the page, one coming from the camera directly and the other coming from a WebRTC connection that the browser has made locally.
I guess the problem is that onaddstream method is not invoked when RTCPeerconnection object is instantiated therefore the second screen does not recieve url from window.URL.createObjectURL(e.stream);
function hasUserMedia() {
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
return !!navigator.getUserMedia;
}
function hasRTCPeerConnection() {
window.RTCPeerConnection = window.RTCPeerConnection || window.webkitRTCPeerConnection || window.mozRTCPeerConnection;
return !!window.RTCPeerConnection;
}
var yourVideo = document.querySelector('#yours'),
theirVideo = document.querySelector('#theirs'),
yourConnection, theirConnection;
if (hasUserMedia()) {
navigator.getUserMedia({ video: true, audio: false }, function (stream) {
yourVideo.src = window.URL.createObjectURL(stream);
if (hasRTCPeerConnection()) {
startPeerConnection(stream);
} else {
alert("Sorry, your browser does not support WebRTC.");
}
}, function (error) {
console.log(error);
});
} else {
alert("Sorry, your browser does not support WebRTC.");
}
function startPeerConnection(stream) {
var configuration = {
"iceServers": [{ "url": "stun:192.168.1.100:9876" }] // this is address of a local server
};
yourConnection = new mozRTCPeerConnection(configuration);
theirConnection = new mozRTCPeerConnection(configuration);
console.log(theirConnection);
// Setup stream listening
yourConnection.addStream(stream);
theirConnection.onaddstream = function (e) {
theirVideo.src = window.URL.createObjectURL(e.stream);
};
// Setup ice handling
yourConnection.onicecandidate = function (event) {
if (event.candidate) {
theirConnection.addIceCandidate(new RTCIceCandidate(event.candidate));
}
};
theirConnection.onicecandidate = function (event) {
if (event.candidate) {
yourConnection.addIceCandidate(new RTCIceCandidate(event.candidate));
}
};
// Begin the offer
yourConnection.createOffer(function (offer) {
yourConnection.setLocalDescription(offer);
theirConnection.setRemoteDescription(offer);
theirConnection.createAnswer(function (offer) {
theirConnection.setLocalDescription(offer);
yourConnection.setRemoteDescription(offer);
});
});
};
Here is the full code : https://gist.github.com/johannesMatevosyan/8e4529fdcc53dd711479
This is how it looks in browser: http://screencast.com/t/6dthclGcm
Your onaddstream event is not triggering because your connection is not started yet, you will have to get the offer/answer process done before that event can be triggered. I tried your code in Firefox 41.0.2 and the offer wasn't getting created because you are missing the error callback methods, try with the following:
function error () { console.log('There was an error'); };
yourConnection.createOffer(function (offer) { console.log('Offer:'); console.log(offer);
yourConnection.setLocalDescription(offer);
theirConnection.setRemoteDescription(offer);
theirConnection.createAnswer(function (answer) { console.log('Answer:'); console.log(answer);
theirConnection.setLocalDescription(answer);
yourConnection.setRemoteDescription(answer);
}, error);
}, error);
I am struggling to send a stream of data being consumed via pusher-client-node to the client using Socket.IO.
I am receiving my data in Node.JS like this:
var API_KEY = 'cb65d0a7a72cd94adf1f';
var pusher = new Pusher(API_KEY, {
encrypted: true
});
var channel = pusher.subscribe("ticker.160");
channel.bind("message", function (data) {
//console.log(data);
});
My data, which comes in continuously, looks like that:
{ channel: 'ticker.160',
trade:
{ timestamp: 1420031543,
datetime: '2014-12-31 08:12:23 EST',
marketid: '160',
topsell: { price: '0.00007650', quantity: '106.26697381' }}
My Socket.IO code looks like this:
/**
* Socket.io
*/
var io = require("socket.io").listen(server, {log: true});
var users = [];
var stream = channel.bind("message", function (data) {
console.log(data);
});
io.on("connection", function (socket) {
// The user it's added to the array if it doesn't exist
if(users.indexOf(socket.id) === -1) {
users.push(socket.id);
}
// Log
logConnectedUsers();
socket.emit('someevent', { attr: 'value' } )
stream.on("newdata", function(data) {
// only broadcast when users are online
if(users.length > 0) {
// This emits the signal to the user that started
// the stream
socket.emit('someevent', { attr: 'value' } )
}
else {
// If there are no users connected we destroy the stream.
// Why would we keep it running for nobody?
stream.destroy();
stream = null;
}
});
// This handles when a user is disconnected
socket.on("disconnect", function(o) {
// find the user in the array
var index = users.indexOf(socket.id);
if(index != -1) {
// Eliminates the user from the array
users.splice(index, 1);
}
logConnectedUsers();
});
});
// A log function for debugging purposes
function logConnectedUsers() {
console.log("============= CONNECTED USERS ==============");
console.log("== :: " + users.length);
console.log("============================================");
}
I am quite new to Node.JS and Socket.IO and struggle to use my pusher stream in Node.JS. Therefore my question: How to connect my Socket.IO code with my Pusher code?
You need to use socket/io rooms ...
server:
var channel = pusher.subscribe("ticker.160"); //subscribe to pusher
//pass messages from pusher to the matching room in socket.io
channel.bind("message", function (data) {
io.to('ticker.160').emit('room-message', {room:'ticker.160', data:data});
});
...
io.on("connection", function (socket) {
...
socket.on('join', function(room){
socket.join(room);
});
socket.on('leave', function(room){
socket.leave(room);
});
});
client:
io.emit('join','ticker.160');
io.on('room-message', function(message){
switch(message.room) {
case 'ticker.160': return doSomething(message.data);
...
}
});
var connectionHandler = function(socket) {
var player = null;
socket.on('login', function(data) {
player = {
data: okeyServer.playerJoin(data),
socket: socket
};
socket.emit('welcome');
});
socket.on('info server', function(data) {
var info = okeyServer.Info();
socket.emit('info server', info);
});
socket.on('join game', function (data) {
var gameid = data.gameid;
var side = data.side;
okeyServer.playerJoinGame(player, gameid, side);
});
socket.on('disconnect', function () {
okeyServer.playerLeave(player);
io.sockets.emit('player leave', player);
});
}
I am trying to do a multiplayer game app with socket.io. When player connects, i want a 'login' message to be sent first. and i initialize the player variable for further use.
Other messages uses the player variable later.
How can i make sure client sent a 'login' message before making other requests.
I can check if player is null on every request where i need player but that seems ugly.
You could install the other listeners from within the login listener:
var connectionHandler = function(socket) {
var player = null;
socket.on('login', function(data) {
// If we already have a player, just return a `welcome` message.
if (player !== null) {
return socket.emit('welcome');
}
// Store player.
player = {
data: okeyServer.playerJoin(data),
socket: socket
};
// Emit welcome message.
socket.emit('welcome');
// Set up the rest of the listeners.
socket.on('info server', function(data) {
var info = okeyServer.Info();
socket.emit('info server', info);
});
socket.on('join game', function (data) {
var gameid = data.gameid;
var side = data.side;
okeyServer.playerJoinGame(player, gameid, side);
});
socket.on('disconnect', function () {
okeyServer.playerLeave(player);
io.sockets.emit('player leave', player);
});
});
};
This assumes that a login message is only ever emitted once by the client during the lifetime of the connection. If that's not the case, you need to make some changes.