-
Notifications
You must be signed in to change notification settings - Fork 32
/
App.js
executable file
·114 lines (92 loc) · 3.29 KB
/
App.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
import Socket from 'socket.io-client';
import {StyleSheet} from 'react-native';
import React, {useRef, useState, useEffect} from 'react';
import {
RTCView,
RTCPeerConnection,
RTCIceCandidate,
mediaDevices,
} from 'react-native-webrtc';
const config = {
iceServers: [
{
urls: ['stun:stun.l.google.com:19302'],
},
],
};
const styles = StyleSheet.create({
viewer: {
flex: 1,
display: 'flex',
backgroundColor: '#4F4',
},
});
const App = () => {
// you have to keep the peer connections without re-rendering
// every time a peer connects/disconnects
const peerConnections = useRef(new Map());
const [stream, setStream] = useState(null);
const [socket] = useState(Socket.connect('ws://8f9e54dd.ngrok.io')); // replace with your host machine's IP or public url
useEffect(() => {
socket.on('connect', () => {
if (stream) socket.emit('broadcaster');
socket.on('watcher', async id => {
const connectionBuffer = new RTCPeerConnection(config);
stream.getTracks.forEach(track =>
connectionBuffer.addTrack(track, stream),
);
connectionBuffer.onicecandidate = ({candidate}) => {
if (candidate) socket.emit('candidate', id, candidate);
};
const localDescription = await connectionBuffer.createOffer();
await connectionBuffer.setLocalDescription(localDescription);
socket.emit('offer', id, connectionBuffer.localDescription);
peerConnections.current.set(id, connectionBuffer);
});
socket.on('candidate', (id, candidate) => {
const candidateBuffer = new RTCIceCandidate(candidate);
const connectionBuffer = peerConnections.current.get(id);
connectionBuffer.addIceCandidate(candidateBuffer);
});
socket.on('answer', (id, remoteOfferDescription) => {
const connectionBuffer = peerConnections.current.get(id);
connectionBuffer.setRemoteDescription(remoteOfferDescription);
});
socket.on('disconnectPeer', id => {
peerConnections.current.get(id).close();
peerConnections.current.delete(id);
});
});
return () => {
if (socket.connected) socket.close(); // close the socket if the view is unmounted
};
}, [socket, stream]);
useEffect(() => {
if (!stream) {
(async () => {
const availableDevices = await mediaDevices.enumerateDevices();
const {deviceId: sourceId} = availableDevices.find(
// once we get the stream we can just call .switchCamera() on the track to switch without re-negotiating
// ref: https://github.com/react-native-webrtc/react-native-webrtc#mediastreamtrackprototype_switchcamera
device => device.kind === 'videoinput' && device.facing === 'front',
);
const streamBuffer = await mediaDevices.getUserMedia({
audio: true,
video: {
mandatory: {
// Provide your own width, height and frame rate here
minWidth: 500,
minHeight: 300,
minFrameRate: 30,
},
facingMode: 'user',
optional: [{sourceId}],
},
});
setStream(streamBuffer);
})();
}
}, [stream]);
return <RTCView streamURL={stream?.toURL()} style={styles.viewer} />;
};
export default App;