WebRTC: Sound not muting - can anyone see an error? - audio

I have inserted a mute button into my WebRTC Video chat page but I cannot get it to work. If I click it in the browser I get a console message that the sound has been muted but there is still sound.
The Constraints variables:
var constraints = {
video: true,
audio: true,
};
If I change audio to false here there will be no sound.
Code on Mute Button:
function muteVideoBtnClick() {
if(constraints.audio == true) {
constraints.audio = false;
console.log('Audio: ' + constraints.audio);
} else {
constraints.audio = true;
console.log('Audio: ' + constraints.audio);
}
}
The Only other place where the constraints variables are used:
function pageReady() {
uuid = uuid(); //CB Universal Unique Identifier
//CB Create the variables for local and remote video
localVideo = document.getElementById('localVideo');
remoteVideo = document.getElementById('remoteVideo');
//CB Create the connection using websocket (443 as it is a secure connection)
serverConnection = new WebSocket('wss://' + window.location.hostname + ':443');
serverConnection.onmessage = gotMessageFromServer;
// CB Checks thats getUserMedia works and then runs getUserMedia if it works and displays an error
//if it doesnt work
if(navigator.mediaDevices.getUserMedia) {
navigator.mediaDevices.getUserMedia(constraints).then(getUserMediaSuccess).catch(errorHandler);
} else {
alert('Your browser does not support getUserMedia API');
}
}
I would be very grateful if anyone has any suggestions.
Kind regards,
Claire
The Full code:
var localVideo;
var remoteVideo;
var peerConnection;
var uuid;
var rooms = [];//CB 31/07
var constraints = {
video: true,
audio: true,
};
var peerConnectionConfig = {
'iceServers': [
{'urls': 'stun:stun.services.mozilla.com'},
{'urls': 'stun:stun.l.google.com:19302'},
]
};
function pageReady() {
uuid = uuid(); //CB Universal Unique Identifier
//CB Create the variables for local and remote video
localVideo = document.getElementById('localVideo');
remoteVideo = document.getElementById('remoteVideo');
//CB Create the connection using websocket (443 as it is a secure connection)
serverConnection = new WebSocket('wss://' + window.location.hostname + ':443');
serverConnection.onmessage = gotMessageFromServer;
// CB Checks thats getUserMedia works and then runs getUserMedia if it works and displays an error
//if it doesnt work
if(navigator.mediaDevices.getUserMedia) {
navigator.mediaDevices.getUserMedia(constraints).then(getUserMediaSuccess).catch(errorHandler);
} else {
alert('Your browser does not support getUserMedia API');
}
}
//CB if it is possible to run gerUserMedia then gets the local video stream
function getUserMediaSuccess(stream) {
localStream = stream;
localVideo.src = window.URL.createObjectURL(stream); //Depreciated!!!!!
//localVideo.srcObject = stream;
}
//CB this function starts the call
function start(isCaller) {
peerConnection = new RTCPeerConnection(peerConnectionConfig);
peerConnection.onicecandidate = gotIceCandidate;
peerConnection.onaddstream = gotRemoteStream;
//peerConnection.ontrack = gotRemoteStream;
peerConnection.addStream(localStream);
if(isCaller) {
peerConnection.createOffer().then(createdDescription).catch(errorHandler);
}
}
//Added by CB for Pause Button 20/07
function pauseVideoBtnClick() {
var btn = document.getElementById("pause_video_btn");
if (isVideoPaused()) {
pauseVideo(false);
btn.innerHTML = "Pause Video";
} else {
pauseVideo(true);
btn.innerHTML = "Resume Video";
}
}
//Added by CB for Pause Button 20/07
function isVideoPaused() {
return !(localStream.getVideoTracks()[0].enabled);
}
//Added by CB for Pause Button 20/07
function pauseVideo (pause) {
localStream.getVideoTracks()[0].enabled = !pause;
};
//Added by CB for mute button 29/07 - DOESNT WORK YET
function muteVideoBtnClick() {
if(constraints.audio == true) {
constraints.audio = false;
console.log('Audio: ' + constraints.audio);
} else {
constraints.audio = true;
console.log('Audio: ' + constraints.audio);
}
}
//End of added code
function gotMessageFromServer(message) {
if(!peerConnection) start(false);
var signal = JSON.parse(message.data);
// Ignore messages from ourself
if(signal.uuid == uuid) return;
if(signal.sdp) {
peerConnection.setRemoteDescription(new RTCSessionDescription(signal.sdp)).then(function() {
// Only create answers in response to offers
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 gotIceCandidate(event) {
if(event.candidate != null) {
serverConnection.send(JSON.stringify({'ice': event.candidate, 'uuid': uuid}));
}
}
function createdDescription(description) {
console.log('got description');
peerConnection.setLocalDescription(description).then(function() {
serverConnection.send(JSON.stringify({'sdp': peerConnection.localDescription, 'uuid': uuid}));
}).catch(errorHandler);
}
function gotRemoteStream(event) {
console.log('got remote stream');
remoteVideo.src = window.URL.createObjectURL(event.stream);
//remoteVideo.src = event.stream;
}
function errorHandler(error) {
console.log(error);
}
// CB A UUID (Universal Unique Identifier) is a 128-bit number used to uniquely identify some object or entity on the Internet.
// Taken from http://stackoverflow.com/a/105074/515584
// Strictly speaking, it's not a real UUID, but it gets the job done here
function uuid() {
function s4() {
return Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1);
}
return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4();
}

You are changing the constraints to the getUserMedia call (after doing the call). You are not changing the resulting stream which is stored in the localStream variable. Try this:
localStream.getAudioTracks()[0].enabled = false;

Related

How to migrate SSE chat node express to node hapi

I was testing a SSE node express chat in localhost.It was working perfectly. I was including a chat_server in a demo with hapijs as modular server...and it complain about the express syntax. How can I migrate the code to the right syntax in hapijs?
I am trying to solve changing writeHead and write methods because it's complaing about and adding stream package after searching answers in internet.
/*
* Request handlers
*/
function handleGetChat(req, res) {
console.log('handleGetChat received.');
// res(chatStream).code(200).type('text/event-stream').header('Connection', 'keep-alive').header('Cache-Control','no-cache');
// chatStream.write('\n');
(function(clientId) {
clients[clientId] = res;
clientNames[clientId] = req.params.name;
console.log('name {$req.params.name}');
req.on("close", () => {
delete clients[clientId];
actUserName = "";
sendText(clientNames[clientId] + " disconnected!", false);
delete clientNames[clientId];
});
})(++clientId);
sendText(req.params.name + " connected!", false);
let allMates = "";
for (cliId in clientNames) {
allMates += `${clientNames[cliId]}`;
if (cliId < clientId) allMates += " ";
}
sendText(`logged in [${allMates}]`, false);
}
let sendText = (text, showUserName = true) => {
for (clientId in clients) {
allMates += `${clientNames[cliId]}`;
if (cliId < clientId) allMates += " ";
}
sendText(logged in [${allMates}], false);
}
let sendText = (text, showUserName = true) => {
for (clientId in clients) {
let data = "";
let date = new Date();
let timestamp = `[${date.getHours()}:${date.getMinutes()}]`;
if (showUserName) {
data = `data: ${timestamp} <${actUserName}> ${text}\n\n`;
} else {
data = `data: ${timestamp} ${text}\n\n`;
}
//chatStream.push('data: ' + "\n\n");
}
};
function handleWriteChat(req, res) {
actUserName = req.body.name;
sendText(req.body.text);
res.json({ success: true });
}
The commented lines in the code above are the lines with syntax error in hapi. I was already changing the originals write and writeHead with chatstream.

Create webrtc video, voice call and file transfer using node js step by step Q-A

If any one need to add information or edit some information they are welcome.
Hi,
First of all this questions main target is shear my experience to other developers who finding good tutorials about webrtc.i'm not going to explain about webrtc. In this i add scourse code that working webrtc Video, voice call and file transfer example tested by me.
I get webrtc information from https://webrtc.org/ and get nodejs
from https://nodejs.org/en/
Ok let get start
Is web rtc need ssl certificated?
If you doing experiment in you local PC server no need. but when you add the to live server Yes you need it.
How i get ssl certificate?
one of my friend help me to get that SSl. there plenty of tutorials for you read and watch
How i get turn and stun server?
if you go production level you need to setup those server , but for test your project you can get stun server and turn servers for free.
For Stun server - https://gist.github.com/zziuni/3741933
For Turn server - Use this link and create free one ( http://numb.viagenie.ca/ ).
I add my working code as a an answer below
This is Working code for webrtc with node js
This code and comment that in code not by me. They already there when i got the code. I cant find code original owner. but i thanks that developer.If some found that developer please edit this and add that developer link :)
var express = require('express');
var socket = require('socket.io');
var app = express();
var fs = require('fs');
var https = require('https');
// link your https certicate path
var options = {
key: fs.readFileSync('/../../etc/ssl/private/apache-selfsigned.key'),
cert: fs.readFileSync('/../../etc/ssl/certs/apache-selfsigned.crt')
};
var main = https.createServer(options, app);
var server = main.listen(8443, function() {
console.log('server up and running at %s port', 8443);
});
/*var server = app.listen(443, function () {
});*/
app.use(express.static('public'));
var io = socket(server);
/*************************/
/*** INTERESTING STUFF ***/
/*************************/
var channels = {};
var sockets = {};
/**
* Users will connect to the signaling server, after which they'll issue a "join"
* to join a particular channel. The signaling server keeps track of all sockets
* who are in a channel, and on join will send out 'addPeer' events to each pair
* of users in a channel. When clients receive the 'addPeer' even they'll begin
* setting up an RTCPeerConnection with one another. During this process they'll
* need to relay ICECandidate information to one another, as well as SessionDescription
* information. After all of that happens, they'll finally be able to complete
* the peer connection and will be streaming audio/video between eachother.
*/
io.on('connection', function (socket) {
var channel;
socket.channels = {};
sockets[socket.id] = socket;
console.log("[" + socket.id + "] connection accepted");
socket.on('disconnect', function () {
for (var channel in socket.channels) {
part(channel);
}
console.log("[" + socket.id + "] disconnected");
delete sockets[socket.id];
});
socket.on('join-room', function (config) {
if (config) {
channel = config.channel;
var userdata = config.userdata;
var userID = config.userdata.userID;
if (channel in socket.channels) {
console.log("[" + socket.id + "] ERROR: already joined ", channel);
return;
}
if (!(channel in channels)) {
channels[channel] = {};
}
for (id in channels[channel]) {
channels[channel][id].emit('addPeer-room', {'peer_id': socket.id, 'should_create_offer': false});
socket.emit('addPeer-room', {'peer_id': id, 'should_create_offer': true});
console.log("what is this id -> ", id);
}
console.log(config.userdata.name, ' joining room', config.channel);
socket.join(config.channel);
socket.broadcast.in(config.channel).emit('room-users', config);
channels[channel][socket.id] = socket;
socket.channels[channel] = channel;
}
});
function part(channel) {
console.log("[" + socket.id + "] part ");
if (!(channel in socket.channels)) {
console.log("[" + socket.id + "] ERROR: not in ", channel);
return;
}
delete socket.channels[channel];
delete channels[channel][socket.id];
for (id in channels[channel]) {
channels[channel][id].emit('removePeer', {'peer_id': socket.id});
socket.emit('removePeer', {'peer_id': id});
}
}
socket.on('part', part);
socket.on('relayICECandidate-room', function (config) {
var peer_id = config.peer_id;
var ice_candidate = config.ice_candidate;
console.log("[" + socket.id + "] relaying ICE candidate to [" + peer_id + "] ", ice_candidate);
if (peer_id in sockets) {
sockets[peer_id].emit('iceCandidate-room', {'peer_id': socket.id, 'ice_candidate': ice_candidate});
}
});
socket.on('relaySessionDescription-room', function (config) {
var peer_id = config.peer_id;
var session_description = config.session_description;
console.log("[" + socket.id + "] relaying session description to [" + peer_id + "] ", session_description);
if (peer_id in sockets) {
sockets[peer_id].emit('sessionDescription-room', {
'peer_id': socket.id,
'session_description': session_description
});
}
});
// this for file transfer
socket.on('file-send-room', function (file) {
console.log(file);
socket.to(channel).emit('file-out-room', file);
});
socket.on('file-send-room-result', function (file) {
console.log(file);
socket.to(channel).emit('file-out-room-result', file);
});
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script src="https://cdn.socket.io/socket.io-1.4.5.js"></script>
<script>
function getParameterByName(name, url) {
if (!url) url = window.location.href;
name = name.replace(/[\[\]]/g, "\\$&");
var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
results = regex.exec(url);
if (!results) return null;
if (!results[2]) return '';
return decodeURIComponent(results[2].replace(/\+/g, " "));
}
var fileInput = document.querySelector('input#fileInput');
var downloadAnchor = document.querySelector('a#download');
// this function use to get url parameters
var room = getParameterByName('room');
var userID = getParameterByName('userid');
var name = getParameterByName('name');
/** CONFIG **/
var SIGNALING_SERVER = "https://xxx.xx.xx.xxx:8443"; //your node server addres or IP adress
var USE_AUDIO = true;
var USE_VIDEO = true;
var MUTE_AUDIO_BY_DEFAULT = false;
/** You should probably use a different stun server doing commercial stuff **/
/** Also see: https://gist.github.com/zziuni/3741933 **/
var ICE_SERVERS = [
{urls: "stun:stun.l.google.com:19302"},{
urls: 'turn:numb.viagenie.ca:3478',
credential: '12344', //your password
username: 'your#email.com'
}
];
var socket = null;
/* our socket.io connection to our webserver */
var local_media_stream = null;
/* our own microphone / webcam */
var peers = {};
/* keep track of our peer connections, indexed by peer_id (aka socket.io id) */
var peer_media_elements = {};
/* keep track of our <video>/<audio> tags, indexed by peer_id */
$(document).ready(function (a) {
socket = io(SIGNALING_SERVER);
socket = io();
//----------------------------------------------------------------------->>>>> Files Send Start
const BYTES_PER_CHUNK = 1200;
var file;
var currentChunk;
var fileInput = $('input[type=file]');
var fileReader = new FileReader();
function readNextChunk() {
var start = BYTES_PER_CHUNK * currentChunk;
var end = Math.min(file.size, start + BYTES_PER_CHUNK);
fileReader.readAsArrayBuffer(file.slice(start, end));
}
fileReader.onload = function () {
socket.emit('file-send-room-result', fileReader.result);
//p2pConnection.send( fileReader.result );
currentChunk++;
if (BYTES_PER_CHUNK * currentChunk < file.size) {
readNextChunk();
}
};
fileInput.on('change', function () {
file = fileInput[0].files[0];
currentChunk = 0;
// send some metadata about our file
// to the receiver
socket.emit('file-send-room', JSON.stringify({
fileName: file.name,
fileSize: file.size
}));
readNextChunk();
});
var incomingFileInfo;
var incomingFileData;
var bytesReceived;
var downloadInProgress = false;
socket.on('file-out-room', function (data) {
startDownload(data);
console.log(data);
});
socket.on('file-out-room-result', function (data) {
progressDownload(data);
console.log(data); });
function startDownload(data) {
incomingFileInfo = JSON.parse(data.toString());
incomingFileData = [];
bytesReceived = 0;
downloadInProgress = true;
console.log('incoming file <b>' + incomingFileInfo.fileName + '</b> of ' + incomingFileInfo.fileSize + ' bytes');
}
function progressDownload(data) {
bytesReceived += data.byteLength;
incomingFileData.push(data);
console.log('progress: ' + ((bytesReceived / incomingFileInfo.fileSize ) * 100).toFixed(2) + '%');
if (bytesReceived === incomingFileInfo.fileSize) {
endDownload();
}
}
function endDownload() {
downloadInProgress = false;
var blob = new Blob(incomingFileData);
var a = document.createElement("a");
document.body.appendChild(a);
a.style = "display: none";
var blob = new Blob(incomingFileData);
var url = window.URL.createObjectURL(blob);
a.href = url;
a.download = incomingFileInfo.fileName;
a.click();
window.URL.revokeObjectURL(url);
}
//==================================================================<<< Filse Send End
//------------------------ Funtion
function join_chat_channel(channel, userdata) {
socket.emit('join-room', {"channel": channel, "userdata": userdata});
}
socket.on('connect', function (userID) {
console.log("Connected to signaling server");
setup_local_media(function () {
/* once the user has given us access to their
* microphone/camcorder, join the channel and start peering up */
join_chat_channel(room, {'name': name, 'userID': userID});
});
});
socket.on('room-user', function (data) {
console.log(data);
$("#online-user").append('<tr><td>Name = ' + data.userdata.name + ' <br> User ID= ' + data.userdata.userID + '</td><td><button class="call" id="' + data.userdata.userID + '">Call</button></td></tr>');
});
$('body').on('click', '.call', function () {
var callerID = $(this).attr('id');
socket.emit('call', {"callToId": callerID, "callFromId": userID});
});
/**
* When we join a group, our signaling server will send out 'addPeer' events to each pair
* of users in the group (creating a fully-connected graph of users, ie if there are 6 people
* in the channel you will connect directly to the other 5, so there will be a total of 15
* connections in the network).
*/
socket.on('addPeer-room', function (config) {
console.log('Signaling server said to add peer:', config);
var peer_id = config.peer_id;
if (peer_id in peers) {
/* This could happen if the user joins multiple channels where the other peer is also in. */
console.log("Already connected to peer ", peer_id);
return;
}
var peer_connection = new RTCPeerConnection(
{"iceServers": ICE_SERVERS},
{"optional": [{"DtlsSrtpKeyAgreement": true}]} /* this will no longer be needed by chrome
* eventually (supposedly), but is necessary
* for now to get firefox to talk to chrome */
);
peers[peer_id] = peer_connection;
peer_connection.onicecandidate = function (event) {
if (event.candidate) {
socket.emit('relayICECandidate-room', {
'peer_id': peer_id,
'ice_candidate': {
'sdpMLineIndex': event.candidate.sdpMLineIndex,
'candidate': event.candidate.candidate
}
});
}
}
peer_connection.onaddstream = function (event) {
console.log("onAddStream", event);
var remote_media = USE_VIDEO ? $("<video>") : $("<audio>");
remote_media.attr("autoplay", "autoplay");
if (MUTE_AUDIO_BY_DEFAULT) {
remote_media.attr("muted", "true");
}
remote_media.attr("controls", "");
peer_media_elements[peer_id] = remote_media;
$('body').append(remote_media);
attachMediaStream(remote_media[0], event.stream);
}
/* Add our local stream */
peer_connection.addStream(local_media_stream);
/* Only one side of the peer connection should create the
* offer, the signaling server picks one to be the offerer.
* The other user will get a 'sessionDescription' event and will
* create an offer, then send back an answer 'sessionDescription' to us
*/
if (config.should_create_offer) {
console.log("Creating RTC offer to ", peer_id);
peer_connection.createOffer(
function (local_description) {
console.log("Local offer description is: ", local_description);
peer_connection.setLocalDescription(local_description,
function () {
socket.emit('relaySessionDescription-room',
{'peer_id': peer_id, 'session_description': local_description});
console.log("Offer setLocalDescription succeeded");
},
function () {
Alert("Offer setLocalDescription failed!");
}
);
},
function (error) {
console.log("Error sending offer: ", error);
});
}
});
/**
* Peers exchange session descriptions which contains information
* about their audio / video settings and that sort of stuff. First
* the 'offerer' sends a description to the 'answerer' (with type
* "offer"), then the answerer sends one back (with type "answer").
*/
socket.on('sessionDescription-room', function (config) {
console.log('Remote description received: ', config);
var peer_id = config.peer_id;
var peer = peers[peer_id];
var remote_description = config.session_description;
console.log(config.session_description);
var desc = new RTCSessionDescription(remote_description);
var stuff = peer.setRemoteDescription(desc,
function () {
console.log("setRemoteDescription succeeded");
if (remote_description.type == "offer") {
console.log("Creating answer");
peer.createAnswer(
function (local_description) {
console.log("Answer description is: ", local_description);
peer.setLocalDescription(local_description,
function () {
socket.emit('relaySessionDescription-room',
{'peer_id': peer_id, 'session_description': local_description});
console.log("Answer setLocalDescription succeeded");
},
function () {
Alert("Answer setLocalDescription failed!");
}
);
},
function (error) {
console.log("Error creating answer: ", error);
console.log(peer);
});
}
},
function (error) {
console.log("setRemoteDescription error: ", error);
}
);
console.log("Description Object: ", desc);
});
/**
* The offerer will send a number of ICE Candidate blobs to the answerer so they
* can begin trying to find the best path to one another on the net.
*/
socket.on('iceCandidate-room', function (config) {
var peer = peers[config.peer_id];
var ice_candidate = config.ice_candidate;
peer.addIceCandidate(new RTCIceCandidate(ice_candidate));
});
/**
* When a user leaves a channel (or is disconnected from the
* signaling server) everyone will recieve a 'removePeer' message
* telling them to trash the media channels they have open for those
* that peer. If it was this client that left a channel, they'll also
* receive the removePeers. If this client was disconnected, they
* wont receive removePeers, but rather the
* signaling_socket.on('disconnect') code will kick in and tear down
* all the peer sessions.
*/
socket.on('removePeer-room', function (config) {
console.log('Signaling server said to remove peer:', config);
var peer_id = config.peer_id;
if (peer_id in peer_media_elements) {
peer_media_elements[peer_id].remove();
}
if (peer_id in peers) {
peers[peer_id].close();
}
delete peers[peer_id];
delete peer_media_elements[config.peer_id];
});
});
function setup_local_media(callback, errorback) {
if (local_media_stream != null) { /* ie, if we've already been initialized */
if (callback) callback();
return;
}
/* Ask user for permission to use the computers microphone and/or camera,
* attach it to an <audio> or <video> tag if they give us access. */
console.log("Requesting access to local audio / video inputs");
navigator.getUserMedia = ( navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia);
attachMediaStream = function (element, stream) {
console.log('DEPRECATED, attachMediaStream will soon be removed.');
element.srcObject = stream;
};
navigator.getUserMedia({"audio": USE_AUDIO, "video": USE_VIDEO},
function (stream) { /* user accepted access to a/v */
console.log("Access granted to audio/video");
local_media_stream = stream;
var local_media = USE_VIDEO ? $("<video>") : $("<audio>");
local_media.attr("autoplay", "autoplay");
local_media.attr("muted", "true");
/* always mute ourselves by default */
local_media.attr("controls", "");
$('body').append(local_media);
attachMediaStream(local_media[0], stream);
if (callback) callback();
},
function () { /* user denied access to a/v */
console.log("Access denied for audio/video");
alert("You chose not to provide access to the camera/microphone, demo will not work.");
if (errorback) errorback();
});
}
</script>
</head>
<body>
<form id="fileInfo">
<input type="file" id="fileInput" name="files"/>
</form>
<a id="download"></a>
</body>
</html>

RecordRTC upload video to node js server

I am using RecordRTC from recording webrtc meeting. After implementing recording, when I test this application if both client are on the same system then its working fine. When I test this application on different system it isn't working fine and meeting is not recorded.
Here this is my code from stop recording client side.
recordRTC.stopRecording(function (videoURL) {
console.log('recordRTC.stopRecording Function inside');
SelectedFile = recordRTC.getBlob();
$('#uploadForm').append('#attachmentFileId', recordRTC.getBlob());
StartUpload();
});
var FReader;
var Name = "Meeting" + "_" + Date.now() + ".webm";
function StartUpload()
{
FReader = new FileReader();
FReader.onload = function (evnt)
{
socket.emit('Upload', { 'Name': Name, Data: evnt.target.result });
}
socket.emit('Start', { 'Name': Name, 'Size': SelectedFile.size });
}
socket.on('MoreData', function (data)
{
var Place = data['Place'] * 524288; //The Next Blocks Starting Position
var NewFile; //The Variable that will hold the new Block of Data
if (SelectedFile.webkitSlice)
NewFile = SelectedFile.webkitSlice(Place, Place + Math.min(524288, (SelectedFile.size - Place)));
else
NewFile = SelectedFile.slice(Place, Place + Math.min(524288, (SelectedFile.size - Place)));
FReader.readAsBinaryString(NewFile);
});
Server Side Code
I get this from here.
socket.on('Start', function (data) { //data contains the variables that we passed through in the html file
var Name = data['Name'];
Files[Name] = { //Create a new Entry in The Files Variable
FileSize : data['Size'],
Data : "",
Downloaded : 0
}
var Place = 0;
try{
var Stat = fs.statSync('Temp/' + Name);
if(Stat.isFile())
{
Files[Name]['Downloaded'] = Stat.size;
Place = Stat.size / 524288;
}
}
catch(er){} //It's a New File
fs.open("Temp/" + Name, 'a', 0755, function(err, fd){
if(err)
{
console.log(err);
}
else
{
Files[Name]['Handler'] = fd; //We store the file handler so we can write to it later
socket.emit('MoreData', { 'Place' : Place, Percent : 0 });
}
});
});
socket.on('Upload', function (data){
var Name = data['Name'];
Files[Name]['Downloaded'] += data['Data'].length;
Files[Name]['Data'] += data['Data'];
if(Files[Name]['Downloaded'] == Files[Name]['FileSize']) //If File is Fully Uploaded
{
fs.write(Files[Name]['Handler'], Files[Name]['Data'], null, 'Binary', function(err, Writen){
var input = fs.createReadStream("Temp/" + Name);
var output = fs.createWriteStream("Video/" + Name);
//util.pump(readableStream, writableStream, [callback])
//Deprecated: Use readableStream.pipe(writableStream)
input.pipe(output);
input.on("end", function() {
console.log("end");
fs.unlink("Temp/" + Name, function ()
{ //This Deletes The Temporary File
console.log("unlink this file:",Name );
//socket.emit('Done', {'Image' : 'Video/' + Name + '.jpg'});
});
});
});
}
else if(Files[Name]['Data'].length > 10485760){ //If the Data Buffer reaches 10MB
fs.write(Files[Name]['Handler'], Files[Name]['Data'], null, 'Binary', function(err, Writen){
Files[Name]['Data'] = ""; //Reset The Buffer
var Place = Files[Name]['Downloaded'] / 524288;
var Percent = (Files[Name]['Downloaded'] / Files[Name]['FileSize']) * 100;
socket.emit('MoreData', { 'Place' : Place, 'Percent' : Percent});
});
}
else
{
var Place = Files[Name]['Downloaded'] / 524288;
var Percent = (Files[Name]['Downloaded'] / Files[Name]['FileSize']) * 100;
socket.emit('MoreData', { 'Place' : Place, 'Percent' : Percent});
}
});
If both clients are on same machine/system its working fine, but if both clients are on different system then meeting is not recorded.

Knockout-2.2.0, subscribe get value before change AND new value

jsfiddle link: http://jsfiddle.net/T8ee7/
When I call Knockout's subscribe method is there a way I can get both the previous and new value? Right now, I can only call get these values separately.
I want to trigger some code if the old and new value are different.
I suppose I could do the following, but it can get messy...
(http://jsfiddle.net/MV3fN/)
var sv = sv || {};
sv.PagedRequest = function (pageNumber, pageSize) {
this.pageNumber = ko.observable(pageNumber || 1);
this.numberOfPages = ko.observable(1);
this.pageSize = ko.observable(pageSize || sv.DefaultPageSize);
};
var _pagedRequest = new sv.PagedRequest();
var oldValue;
_pagedRequest.pageNumber.subscribe(function (previousValue) {
console.log("old: " + previousValue);
oldValue = previousValue;
}, _pagedRequest, "beforeChange");
_pagedRequest.pageNumber.subscribe(function (newValue) {
console.log("new: " + newValue);
if (oldValue != newValue) {
console.log("value changed!");
}
});
_pagedRequest.pageNumber(10);
_pagedRequest.pageNumber(20);
​
I prefer using an observable extender.
http://jsfiddle.net/neonms92/xybGG/
Extender:
ko.extenders.withPrevious = function (target) {
// Define new properties for previous value and whether it's changed
target.previous = ko.observable();
target.changed = ko.computed(function () { return target() !== target.previous(); });
// Subscribe to observable to update previous, before change.
target.subscribe(function (v) {
target.previous(v);
}, null, 'beforeChange');
// Return modified observable
return target;
}
Example Usage:
// Define observable using 'withPrevious' extension
self.hours = ko.observable().extend({ withPrevious: 1 });
// Subscribe to observable like normal
self.hours.subscribe(function () {
if (!self.hours.changed()) return; // Cancel if value hasn't changed
print('Hours changed from ' + self.hours.previous() + ' to ' + self.hours());
});
This seems to work for me
ko.observable.fn.beforeAndAfterSubscribe = function (callback, target) {
var _oldValue;
this.subscribe(function (oldValue) {
_oldValue = oldValue;
}, null, 'beforeChange');
this.subscribe(function (newValue) {
callback.call(target, _oldValue, newValue);
});
};
See more at: http://ideone.com/NPpNcB#sthash.wJn57567.dpuf
http://jsfiddle.net/MV3fN/3/
var sv = sv || {};
sv.PagedRequest = function (pageNumber, pageSize) {
var self = this;
self.pageNumber = ko.observable(pageNumber || 1);
self.numberOfPages = ko.observable(1);
self.pageSize = ko.observable(pageSize || sv.DefaultPageSize);
self.pageNumber.subscribe(function (previousValue) {
console.log(previousValue);
console.log(self.pageNumber.arguments[0]);
if (previousValue != _pagedRequest.pageNumber.arguments[0]) {
console.log('value changed');
}
else {
//This won't get executed because KO doesn't
//call the function if the value doesn't change
console.log('not changed');
}
}, _pagedRequest, "beforeChange");
};
var _pagedRequest = new sv.PagedRequest();
_pagedRequest.pageNumber(10);
_pagedRequest.pageNumber(20);
_pagedRequest.pageNumber(20);
_pagedRequest.pageNumber(5);
I don't know if you're really supposed to use arguments[0], but it seems to work.
You could also set up your own method to accomplish this in a much cleaner way:
http://jsfiddle.net/PXKgr/2/
...
self.setPageNumber = function(page) {
console.log(self.pageNumber());
console.log(page);
if (self.pageNumber() != page) {
console.log('value changed');
}
else {
console.log('not changed');
}
self.pageNumber(page);
};
...
_pagedRequest.setPageNumber(10);
_pagedRequest.setPageNumber(20);
_pagedRequest.setPageNumber(20);
_pagedRequest.setPageNumber(5);

Handling byte streams in node.js

For education purposes I am creating a little chat with node.js using TCP.
I am using the windows console to connect with my node server but when I am typing all the characters are streamed one by one. They don't arive as strings. How can I manage to handle those streams so my users don't can write complete words.
My Code:
var net = require("net");
Array.prototype.remove = function(e) {
for (var i = 0; i < this.length; i++) {
if (e == this[i]) { return this.splice(i, 1); }
}
};
function Chatter(stream) {
this.name = null;
this.stream = stream;
}
var chatters = [];
var server = net.createServer(function(stream) {
var chatter = new Chatter(stream);
chatters.push(chatter);
stream.setTimeout(0);
stream.setEncoding("utf8");
stream.addListener("connect", function(){
stream.write("Hallo, wer bist du?:\n");
});
stream.addListener("data", function (data) {
if(chatter.name == null) {
chatter.name = data.match(/\S+/);
stream.write("....................\n");
chatters.forEach(function(c){
if (c != chatter) {
c.stream.write(chatter.name + " ist dem Chat beigetreten!\n");
}
});
return;
}
var command = data.match(/^\/(.*)/);
if (command) {
if (command[1] == 'users') {
chatters.forEach(function(c) {
stream.write("- " + c.name + "\n");
});
}
else if (command[1] == 'quit') {
stream.end();
}
}
chatters.forEach(function(c) {
if(c != chatter) {
c.stream.write(chatter.name + ": " + data);
}
});
});
stream.addListener("end", function(){
chatters.remove(chatter);
chatters.forEach(function(c) {
c.stream.write(chatter.name + " hat den Chat verlassen.\n");
});
stream.end();
});
});
server.listen(8000);
For the record that code is from this site
ADDITION:
setEncoding('utf8') is supposed to change the emiting of data, but it doesn't work for me :-(
The solution to your problem is to store all received characters in a buffer and when an END_OF_NICK character is encountered (say, \n), use the buffer as the name.
var buffer = ""; // stores received characters
stream.addListener("data", function (data) {
if(chatter.name == null) { // still receiving characters for the name
buffer += data; // append received characters to the buffer
if (buffer.indexOf('\n') == -1) return; // if there's no END_OF_NICK character, keep waiting for it
chatter.name = buffer.match(/\S+/); // use the name in the buffer
// ...
}

Resources