Skip to content

Commit c9a124b

Browse files
committed
add server.js socket.io
1 parent 1b1bb10 commit c9a124b

File tree

3 files changed

+320
-35
lines changed

3 files changed

+320
-35
lines changed

package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,10 @@
2626
"@material-ui/icons": "^1.1.0",
2727
"prop-types": "^15.6.2",
2828
"react": "^16.4.1",
29-
"react-dom": "^16.4.1"
29+
"react-dom": "^16.4.1",
30+
"express": "^4.11.2",
31+
"open": "0.0.5",
32+
"socket.io": "1.3.4"
3033
},
3134
"devDependencies": {
3235
"babel-core": "^6.26.3",

src/App.js

Lines changed: 244 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React from 'react';
1+
import React, { Component } from 'react';
22
import PropTypes from 'prop-types';
33
import { MuiThemeProvider, createMuiTheme } from '@material-ui/core/styles';
44
import { withStyles } from '@material-ui/core/styles';
@@ -10,48 +10,258 @@ import IconButton from '@material-ui/core/IconButton';
1010
import MenuIcon from '@material-ui/icons/Menu';
1111
import blue from '@material-ui/core/colors/blue';
1212

13+
var socket = require('socket.io-client')('https://localhost:4443');
14+
15+
var RTCPeerConnection;
16+
var RTCSessionDescription;
17+
18+
19+
var pcPeers = {};
20+
var selfView;
21+
var remoteView;
22+
var localStream;
23+
var configuration;
24+
25+
1326
const theme = createMuiTheme({
1427
palette: {
1528
primary: blue,
1629
},
1730
});
1831

19-
const styles = {
20-
root: {
21-
flexGrow: 1,
22-
},
23-
flex: {
24-
flex: 1,
25-
},
26-
menuButton: {
27-
marginLeft: -12,
28-
marginRight: 20,
29-
},
30-
};
32+
export default class App extends Component {
33+
34+
componentDidMount = () => {
35+
36+
remoteView = this.refs['remoteView'];
37+
selfView = this.refs['selfView'];
38+
39+
RTCPeerConnection = window.RTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection || window.msRTCPeerConnection;
40+
RTCSessionDescription = window.RTCSessionDescription || window.mozRTCSessionDescription || window.webkitRTCSessionDescription || window.msRTCSessionDescription;
41+
navigator.getUserMedia = navigator.getUserMedia || navigator.mozGetUserMedia || navigator.webkitGetUserMedia || navigator.msGetUserMedia;
42+
43+
var twilioIceServers = [
44+
{ url: 'stun:global.stun.twilio.com:3478?transport=udp' }
45+
];
46+
configuration = { "iceServers": [{ "url": "stun:stun.l.google.com:19302" }] };
47+
48+
49+
socket.on('exchange', (data) => {
50+
this.exchange(data);
51+
});
52+
socket.on('leave', (socketId) => {
53+
this.leave(socketId);
54+
});
55+
56+
socket.on('connect', (data) => {
57+
console.log('connect');
58+
this.getLocalStream();
59+
});
60+
61+
}
62+
63+
getLocalStream = () => {
64+
65+
var constraints = { audio: true, video: { width: 1280, height: 720 } };
66+
67+
navigator.mediaDevices.getUserMedia(constraints)
68+
.then(function (mediaStream) {
69+
localStream = mediaStream;
70+
selfView.srcObject = mediaStream;
71+
selfView.mute = true;
72+
selfView.onloadedmetadata = function (e) {
73+
selfView.play();
74+
};
75+
})
76+
.catch((err) => {
77+
console.log(err.name + ": " + err.message);
78+
}
79+
);
80+
81+
82+
}
83+
84+
join = (roomID) => {
85+
socket.emit('join', roomID, (socketIds) => {
86+
console.log('join', socketIds);
87+
for (var i in socketIds) {
88+
var socketId = socketIds[i];
89+
this.createPC(socketId, true);
90+
}
91+
});
92+
}
93+
94+
createOffer = (pc, socketId) => {
95+
pc.createOffer((desc) => {
96+
console.log('createOffer', desc);
97+
pc.setLocalDescription(desc, () => {
98+
console.log('setLocalDescription', pc.localDescription);
99+
socket.emit('exchange', { 'to': socketId, 'sdp': pc.localDescription });
100+
}, this.logError);
101+
}, this.logError);
102+
}
103+
104+
createPC = (socketId, isOffer) => {
105+
var pc = new RTCPeerConnection(configuration);
106+
pcPeers[socketId] = pc;
107+
108+
pc.onicecandidate = (event) => {
109+
console.log('onicecandidate', event);
110+
if (event.candidate) {
111+
socket.emit('exchange', { 'to': socketId, 'candidate': event.candidate });
112+
}
113+
};
114+
115+
pc.onnegotiationneeded = () => {
116+
console.log('onnegotiationneeded');
117+
if (isOffer) {
118+
this.createOffer(pc, socketId);
119+
}
120+
}
121+
122+
pc.oniceconnectionstatechange = (event) => {
123+
console.log('oniceconnectionstatechange', event);
124+
if (event.target.iceConnectionState === 'connected') {
125+
this.createDataChannel(pc);
126+
}
127+
};
128+
pc.onsignalingstatechange = (event) => {
129+
console.log('onsignalingstatechange', event);
130+
};
131+
132+
pc.onaddstream = (event) => {
133+
console.log('onaddstream', event);
134+
// var element = document.createElement('video');
135+
// element.id = "remoteView" + socketId;
136+
// element.autoplay = 'autoplay';
137+
// element.src = URL.createObjectURL(event.stream);
138+
// remoteViewContainer.appendChild(element);
139+
140+
remoteView.srcObject = event.stream;
141+
remoteView.onloadedmetadata = function (e) {
142+
remoteView.play();
143+
};
144+
145+
146+
};
147+
pc.addStream(localStream);
148+
149+
return pc;
150+
}
151+
152+
createDataChannel = (pc) => {
153+
if (pc.textDataChannel) {
154+
return;
155+
}
156+
var dataChannel = pc.createDataChannel("text");
157+
158+
dataChannel.onerror = (error) => {
159+
console.log("dataChannel.onerror", error);
160+
};
161+
162+
dataChannel.onmessage = (event) => {
163+
console.log("dataChannel.onmessage:", event.data);
164+
var content = document.getElementById('textRoomContent');
165+
//content.innerHTML = content.innerHTML + '<p>' + socketId + ': ' + event.data + '</p>';
166+
};
167+
168+
dataChannel.onopen = () => {
169+
console.log('dataChannel.onopen');
170+
// var textRoom = document.getElementById('textRoom');
171+
// textRoom.style.display = "block";
172+
};
173+
174+
dataChannel.onclose = () => {
175+
console.log("dataChannel.onclose");
176+
};
177+
178+
pc.textDataChannel = dataChannel;
179+
}
180+
181+
exchange = (data) => {
182+
var fromId = data.from;
183+
var pc;
184+
if (fromId in pcPeers) {
185+
pc = pcPeers[fromId];
186+
} else {
187+
pc = this.createPC(fromId, false);
188+
}
189+
190+
if (data.sdp) {
191+
console.log('exchange sdp', data);
192+
pc.setRemoteDescription(new RTCSessionDescription(data.sdp), () => {
193+
if (pc.remoteDescription.type == "offer")
194+
pc.createAnswer((desc) => {
195+
console.log('createAnswer', desc);
196+
pc.setLocalDescription(desc, () => {
197+
console.log('setLocalDescription', pc.localDescription);
198+
socket.emit('exchange', { 'to': fromId, 'sdp': pc.localDescription });
199+
}, this.logError);
200+
}, this.logError);
201+
}, this.logError);
202+
} else {
203+
console.log('exchange candidate', data);
204+
pc.addIceCandidate(new RTCIceCandidate(data.candidate));
205+
}
206+
}
207+
208+
leave = (socketId) => {
209+
console.log('leave', socketId);
210+
var pc = pcPeers[socketId];
211+
pc.close();
212+
delete pcPeers[socketId];
213+
var video = document.getElementById("remoteView" + socketId);
214+
if (video) video.remove();
215+
}
216+
217+
218+
219+
logError = (error) => {
220+
console.log("logError", error);
221+
}
222+
223+
joinRoomPress = () => {
224+
var roomID = '111111';
225+
if (roomID == "") {
226+
alert('Please enter room ID');
227+
} else {
228+
this.join(roomID);
229+
}
230+
}
231+
232+
textRoomPress() {
233+
var text = "test send text...";//document.getElementById('textRoomInput').value;
234+
if (text == "") {
235+
alert('Enter something');
236+
} else {
237+
//document.getElementById('textRoomInput').value = '';
238+
// var content = document.getElementById('textRoomContent');
239+
// content.innerHTML = content.innerHTML + '<p>' + 'Me' + ': ' + text + '</p>';
240+
for (var key in pcPeers) {
241+
var pc = pcPeers[key];
242+
pc.textDataChannel.send(text);
243+
}
244+
}
245+
}
246+
247+
248+
render() {
249+
const { classes } = this.props;
250+
return (
251+
<MuiThemeProvider theme={theme}>
252+
<div>
253+
<video ref='selfView' autoplay style={{ width: '320px', height: '240px' }}></video>
254+
<video ref='remoteView' autoplay style={{ width: '320px', height: '240px' }}></video>
255+
<Button color="primary" onClick={this.joinRoomPress}>
256+
join room
257+
</Button>
258+
</div>
259+
</MuiThemeProvider>
260+
);
261+
}
31262

32-
function App(props) {
33-
const { classes } = props;
34-
return (
35-
<MuiThemeProvider theme={theme}>
36-
<div className={classes.root}>
37-
<AppBar position="static">
38-
<Toolbar>
39-
<IconButton className={classes.menuButton} color="inherit" aria-label="Menu">
40-
<MenuIcon />
41-
</IconButton>
42-
<Typography variant="title" color="inherit" className={classes.flex}>
43-
Flutter WebRTC Demo
44-
</Typography>
45-
<Button color="inherit">Join</Button>
46-
</Toolbar>
47-
</AppBar>
48-
</div>
49-
</MuiThemeProvider>
50-
);
51263
}
52264

53265
App.propTypes = {
54266
classes: PropTypes.object.isRequired,
55267
};
56-
57-
export default withStyles(styles)(App);

src/server.js

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
var express = require('express');
2+
var app = express();
3+
var fs = require('fs');
4+
var open = require('open');
5+
var options = {
6+
key: fs.readFileSync('../certs/key.pem'),
7+
cert: fs.readFileSync('../certs/cert.pem')
8+
};
9+
var serverPort = (process.env.PORT || 4443);
10+
var https = require('https');
11+
var http = require('http');
12+
var server;
13+
server = https.createServer(options, app);
14+
// if (process.env.LOCAL) {
15+
// server = https.createServer(options, app);
16+
// } else {
17+
// server = http.createServer(app);
18+
// }
19+
var io = require('socket.io')(server);
20+
21+
var roomList = {};
22+
23+
app.get('/', function(req, res){
24+
console.log('get /');
25+
});
26+
server.listen(serverPort, function(){
27+
console.log('server up and running at %s port', serverPort);
28+
if (process.env.LOCAL) {
29+
open('https://localhost:' + serverPort)
30+
}
31+
});
32+
33+
function socketIdsInRoom(name) {
34+
var socketIds = io.nsps['/'].adapter.rooms[name];
35+
if (socketIds) {
36+
var collection = [];
37+
for (var key in socketIds) {
38+
collection.push(key);
39+
}
40+
return collection;
41+
} else {
42+
return [];
43+
}
44+
}
45+
46+
io.on('connection', function(socket){
47+
console.log('connection');
48+
socket.on('disconnect', function(){
49+
console.log('disconnect');
50+
if (socket.room) {
51+
var room = socket.room;
52+
io.to(room).emit('leave', socket.id);
53+
socket.leave(room);
54+
}
55+
});
56+
57+
socket.on('join', function(name, callback){
58+
console.log('join', name);
59+
var socketIds = socketIdsInRoom(name);
60+
callback(socketIds);
61+
socket.join(name);
62+
socket.room = name;
63+
});
64+
65+
66+
socket.on('exchange', function(data){
67+
console.log('exchange', data);
68+
data.from = socket.id;
69+
var to = io.sockets.connected[data.to];
70+
to.emit('exchange', data);
71+
});
72+
});

0 commit comments

Comments
 (0)