This is the practice project, contain react-native-webrtc + ios callkit
This project add react-native-webrtc and using it to connect to another peer. Here is described the flow of connection includes 3 component: Stream, PeerConnection(for ICE use) and SocketID(for signal server use). and 2 type of connections: 1. Join, join an existed room, 2. Create & Wait, create a room and wait for join.
Before starting we using https://react-native-webrtc.herokuapp.com to be a single server. The app will connect to it at the begin.
Socket = io.connect(https://react-native-webrtc.herokuapp.com)
After single server connected, init local/self stream
socket.on('connect', () => {
getUserMedia({
audio: true,
video: {
mandatory: {
minWidth: 640, // Provide your own width, height and frame rate here
minHeight: 360,
minFrameRate: 30,
},
facingMode: (isFront ? "user" : "environment"),
optional: (videoSourceId ? [{ sourceId: videoSourceId }] : []),
}
}, stream => {
console.log('getUserMedia success', stream);
callback(stream);
}, logError);
}
- Socket emit join with single server address.
socket.emit('join', "your room id", socketIds => { ... })
- Get socket ID from join callback and create PeerConnection and add local stream
const pc = new RTCPeerConnection(configuration)
pc.addStream(localStream)
- We will get on negotiation needed callback from peer connection then we create offer, set local description and exchange throuh socket
pc.onnegotiationneeded = () => {
pc.createOffer(desc => {
pc.setLocalDescription(desc, () => {
socket.emit('exchange', { 'to': socketId, 'sdp': pc.localDescription });
}, logError);
}, logError)
}
- We will get on ICE candidate callback from peer connection and exchange candidate through socket
pc.onicecandidate = (event) => {
if (event.candidate)
socket.emit('exchange', { 'to': socketId, 'candidate': event.candidate })
}
- We will get on exchange socket then check the exchange data reply candidate, set remote. Note: the callback will be called many times.
const exchange = data => {
const fromId = data.from;
let pc;
if (fromId in pcPeers) {
pc = pcPeers[fromId];
} else {
pc = createPC(fromId, false);
}
if (data.sdp) {
pc.setRemoteDescription(new RTCSessionDescription(data.sdp), () => {
if (pc.remoteDescription.type == "offer")
createAnswer(pc, fromId)
}, logError);
}
if (data.candidate) {
console.log('exchange candidate:', data.candidate);
pc.addIceCandidate(new RTCIceCandidate(data.candidate));
}
}
- Finally, we get the remote stream on add stream through peer connection the whole connection is done.
pc.onaddstream = (event) => {
container.setState({ remoteURL: event.stream.toURL() });
}
- socket emit join then get callback without any socket ID
socket.emit('join', "your room id", socketIds => { ... })
- We will get on change from the single server.
const pc = new RTCPeerConnection(configuration)
const exchange = data => {
if (data.candidate) {
console.log('exchange candidate:', data.candidate);
pc.addIceCandidate(new RTCIceCandidate(data.candidate));
}
}
const exchange = data => {
if (data.sdp) {
pc.setRemoteDescription(new RTCSessionDescription(data.sdp), () => {
console.log(`pc.remoteDescription.type: `, pc.remoteDescription.type)
if (pc.remoteDescription.type == "offer")
createAnswer(pc, fromId)
}, logError);
}
}
- Finally, we get the remote stream on add stream through peer connection the whole connection is done.
pc.onaddstream = (event) => {
container.setState({ remoteURL: event.stream.toURL() });
}
Add react-native-voip-push-notification to project Note:
- Add "App provides Voice over IP services" to Required background modes in info.plist
- Enable /Capabilities/Push Notifications
- Package the main.jsbundle and using it to offline bundle in iOS then we can get push notification event app not open.
Basically is activate our session after callkit activated audio session.
FCM allow user using https to send push , but it will need key, the key in settting ,here is a colud message api key.