javascript - How to display remote video with webRTC and socket.io -
i'm following tutorial create private videochat app between 2 peers https://codelabs.developers.google.com/codelabs/webrtc-web/#0
it works try add improvements closer of https://appr.tc/
my main issue can't display 1 camera share same page. want know if it's possible use 2 differents pages each camera in same room , if it's possible, how proceed?
thanks advance differents advices.
the code use:
index.js
'use strict'; var os = require('os'); var nodestatic = require('node-static'); var http = require('http'); var socketio = require('socket.io'); var fileserver = new(nodestatic.server)(); var app = http.createserver(function(req, res) { fileserver.serve(req, res); }).listen(8080); var io = socketio.listen(app); io.sockets.on('connection', function(socket) { // convenience function log server messages on client function log() { var array = ['message server:']; array.push.apply(array, arguments); socket.emit('log', array); } socket.on('message', function(message) { log('client said: ', message); // real app, room-only (not broadcast) socket.broadcast.emit('message', message); }); socket.on('create or join', function(room) { log('received request create or join room ' + room); var numclients = io.sockets.sockets.length; log('room ' + room + ' has ' + numclients + ' client(s)'); if (numclients === 1) { socket.join(room); log('client id ' + socket.id + ' created room ' + room); socket.emit('created', room, socket.id); } else if (numclients === 2) { log('client id ' + socket.id + ' joined room ' + room); io.sockets.in(room).emit('join', room); socket.join(room); socket.emit('joined', room, socket.id); io.sockets.in(room).emit('ready'); } else { // max 2 clients socket.emit('full', room); } }); socket.on('ipaddr', function() { var ifaces = os.networkinterfaces(); (var dev in ifaces) { ifaces[dev].foreach(function(details) { if (details.family === 'ipv4' && details.address !== '127.0.0.1') { socket.emit('ipaddr', details.address); } }); } }); socket.on('bye', function(){ console.log('received bye'); }); });
app.js
'use strict'; var ischannelready = false; var isinitiator = false; var isstarted = false; var localstream; var pc; var remotestream; var turnready; var pcconfig = { 'iceservers': [{ 'urls': 'stun:stun.l.google.com:19302' }] }; // set audio , video regardless of devices present. var sdpconstraints = { offertoreceiveaudio: true, offertoreceivevideo: true }; ///////////////////////////////////////////// var room = 'foo'; // prompt room name: // room = prompt('enter room name:'); var socket = io.connect(); if (room !== '') { socket.emit('create or join', room); console.log('attempted create or join room', room); } socket.on('created', function(room) { console.log('created room ' + room); isinitiator = true; }); socket.on('full', function(room) { console.log('room ' + room + ' full'); }); socket.on('join', function (room){ console.log('another peer made request join room ' + room); console.log('this peer initiator of room ' + room + '!'); ischannelready = true; }); socket.on('joined', function(room) { console.log('joined: ' + room); ischannelready = true; }); socket.on('log', function(array) { console.log.apply(console, array); }); //////////////////////////////////////////////// function sendmessage(message) { console.log('client sending message: ', message); socket.emit('message', message); } // client receives message socket.on('message', function(message) { console.log('client received message:', message); if (message === 'got user media') { maybestart(); } else if (message.type === 'offer') { if (!isinitiator && !isstarted) { maybestart(); } pc.setremotedescription(new rtcsessiondescription(message)); doanswer(); } else if (message.type === 'answer' && isstarted) { pc.setremotedescription(new rtcsessiondescription(message)); } else if (message.type === 'candidate' && isstarted) { var candidate = new rtcicecandidate({ sdpmlineindex: message.label, candidate: message.candidate }); pc.addicecandidate(candidate); } else if (message === 'bye' && isstarted) { handleremotehangup(); } }); //////////////////////////////////////////////////// var localvideo = document.queryselector('#localvideo'); var remotevideo = document.queryselector('#remotevideo'); navigator.mediadevices.getusermedia({ audio: false, video: true }) .then(gotstream) .catch(function(e) { alert('getusermedia() error: ' + e.name); }); function gotstream(stream) { console.log('adding local stream.'); localvideo.src = window.url.createobjecturl(stream); localstream = stream; sendmessage('got user media'); if (isinitiator) { maybestart(); } } var constraints = { video: true }; console.log('getting user media constraints', constraints); if (location.hostname !== 'localhost') { requestturn( 'https://computeengineondemand.appspot.com/turn?username=41784574&key=4080218913' ); } function maybestart() { console.log('>>>>>>> maybestart() ', isstarted, localstream, ischannelready); if (!isstarted && typeof localstream !== 'undefined' && ischannelready) { console.log('>>>>>> creating peer connection'); createpeerconnection(); pc.addstream(localstream); isstarted = true; console.log('isinitiator', isinitiator); if (isinitiator) { docall(); } } } window.onbeforeunload = function() { sendmessage('bye'); }; ///////////////////////////////////////////////////////// function createpeerconnection() { try { pc = new rtcpeerconnection(null); pc.onicecandidate = handleicecandidate; pc.onaddstream = handleremotestreamadded; pc.onremovestream = handleremotestreamremoved; console.log('created rtcpeerconnnection'); } catch (e) { console.log('failed create peerconnection, exception: ' + e.message); alert('cannot create rtcpeerconnection object.'); return; } } function handleicecandidate(event) { console.log('icecandidate event: ', event); if (event.candidate) { sendmessage({ type: 'candidate', label: event.candidate.sdpmlineindex, id: event.candidate.sdpmid, candidate: event.candidate.candidate }); } else { console.log('end of candidates.'); } } function handleremotestreamadded(event) { console.log('remote stream added.'); remotevideo.src = window.url.createobjecturl(event.stream); remotestream = event.stream; } function handlecreateoffererror(event) { console.log('createoffer() error: ', event); } function docall() { console.log('sending offer peer'); pc.createoffer(setlocalandsendmessage, handlecreateoffererror); } function doanswer() { console.log('sending answer peer.'); pc.createanswer().then( setlocalandsendmessage, oncreatesessiondescriptionerror ); } function setlocalandsendmessage(sessiondescription) { // set opus preferred codec in sdp if opus present. // sessiondescription.sdp = preferopus(sessiondescription.sdp); pc.setlocaldescription(sessiondescription); console.log('setlocalandsendmessage sending message', sessiondescription); sendmessage(sessiondescription); } function oncreatesessiondescriptionerror(error) { trace('failed create session description: ' + error.tostring()); } function requestturn(turnurl) { var turnexists = false; (var in pcconfig.iceservers) { if (pcconfig.iceservers[i].url.substr(0, 5) === 'turn:') { turnexists = true; turnready = true; break; } } if (!turnexists) { console.log('getting turn server ', turnurl); // no turn server. 1 computeengineondemand.appspot.com: var xhr = new xmlhttprequest(); xhr.onreadystatechange = function() { if (xhr.readystate === 4 && xhr.status === 200) { var turnserver = json.parse(xhr.responsetext); console.log('got turn server: ', turnserver); pcconfig.iceservers.push({ 'url': 'turn:' + turnserver.username + '@' + turnserver.turn, 'credential': turnserver.password }); turnready = true; } }; xhr.open('get', turnurl, true); xhr.send(); } } function handleremotestreamadded(event) { console.log('remote stream added.'); remotevideo.src = window.url.createobjecturl(event.stream); remotestream = event.stream; } function handleremotestreamremoved(event) { console.log('remote stream removed. event: ', event); } function hangup() { console.log('hanging up.'); stop(); sendmessage('bye'); } function handleremotehangup() { console.log('session terminated.'); stop(); isinitiator = false; } function stop() { isstarted = false; // isaudiomuted = false; // isvideomuted = false; pc.close(); pc = null; } /////////////////////////////////////////// // set opus default audio codec if it's present. function preferopus(sdp) { var sdplines = sdp.split('\r\n'); var mlineindex; // search m line. (var = 0; < sdplines.length; i++) { if (sdplines[i].search('m=audio') !== -1) { mlineindex = i; break; } } if (mlineindex === null) { return sdp; } // if opus available, set default in m line. (i = 0; < sdplines.length; i++) { if (sdplines[i].search('opus/48000') !== -1) { var opuspayload = extractsdp(sdplines[i], /:(\d+) opus\/48000/i); if (opuspayload) { sdplines[mlineindex] = setdefaultcodec(sdplines[mlineindex], opuspayload); } break; } } // remove cn in m line , sdp. sdplines = removecn(sdplines, mlineindex); sdp = sdplines.join('\r\n'); return sdp; } function extractsdp(sdpline, pattern) { var result = sdpline.match(pattern); return result && result.length === 2 ? result[1] : null; } // set selected codec first in m line. function setdefaultcodec(mline, payload) { var elements = mline.split(' '); var newline = []; var index = 0; (var = 0; < elements.length; i++) { if (index === 3) { // format of media starts fourth. newline[index++] = payload; // put target payload first. } if (elements[i] !== payload) { newline[index++] = elements[i]; } } return newline.join(' '); } // strip cn sdp before cn constraints ready. function removecn(sdplines, mlineindex) { var mlineelements = sdplines[mlineindex].split(' '); // scan end convenience of removing item. (var = sdplines.length - 1; >= 0; i--) { var payload = extractsdp(sdplines[i], /a=rtpmap:(\d+) cn\/\d+/i); if (payload) { var cnpos = mlineelements.indexof(payload); if (cnpos !== -1) { // remove cn payload m line. mlineelements.splice(cnpos, 1); } // remove cn line in sdp sdplines.splice(i, 1); } } sdplines[mlineindex] = mlineelements.join(' '); return sdplines; }
Comments
Post a Comment