5,337
edits
No edit summary |
|||
Line 2: | Line 2: | ||
It supports audio streams, video streams, and data streams but has a complicated API and handshake which needs to be performed over an existing connection such as WebSockets to a server accessible from both peers. | It supports audio streams, video streams, and data streams but has a complicated API and handshake which needs to be performed over an existing connection such as WebSockets to a server accessible from both peers. | ||
==Background (JavaScript)== | |||
To get started, first read this background section, then look into WebRTC examples in JavaScript. | |||
WebRTC is a real-time P2P communications protocol which supports audio, video, and data. | |||
For P2P applications to work, they need to first negotiation a connection using an intermediary server. | |||
This signalling is typically done through a WebSocket but can also be done using AJAX via Socket.IO. | |||
===MediaStream=== | |||
The purpose of MediaStream to to access the user's camera, microphone, or screen. | |||
This is done using [https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia MediaDevices.getUserMedia] | |||
===RTCPeerConnection=== | |||
Below is from [https://www.html5rocks.com/en/tutorials/webrtc/basics/ HTML5Rocks]. | |||
<syntaxhighlight lang="javascript"> | |||
// handles JSON.stringify/parse | |||
const signaling = new SignalingChannel(); | |||
const constraints = {audio: true, video: true}; | |||
const configuration = {iceServers: [{urls: 'stuns:stun.example.org'}]}; | |||
const pc = new RTCPeerConnection(configuration); | |||
// send any ice candidates to the other peer | |||
pc.onicecandidate = ({candidate}) => signaling.send({candidate}); | |||
// let the "negotiationneeded" event trigger offer generation | |||
pc.onnegotiationneeded = async () => { | |||
try { | |||
await pc.setLocalDescription(await pc.createOffer()); | |||
// send the offer to the other peer | |||
signaling.send({desc: pc.localDescription}); | |||
} catch (err) { | |||
console.error(err); | |||
} | |||
}; | |||
// once remote track media arrives, show it in remote video element | |||
pc.ontrack = (event) => { | |||
// don't set srcObject again if it is already set. | |||
if (remoteView.srcObject) return; | |||
remoteView.srcObject = event.streams[0]; | |||
}; | |||
// call start() to initiate | |||
async function start() { | |||
try { | |||
// get local stream, show it in self-view and add it to be sent | |||
const stream = | |||
await navigator.mediaDevices.getUserMedia(constraints); | |||
stream.getTracks().forEach((track) => | |||
pc.addTrack(track, stream)); | |||
selfView.srcObject = stream; | |||
} catch (err) { | |||
console.error(err); | |||
} | |||
} | |||
signaling.onmessage = async ({desc, candidate}) => { | |||
try { | |||
if (desc) { | |||
// if we get an offer, we need to reply with an answer | |||
if (desc.type === 'offer') { | |||
await pc.setRemoteDescription(desc); | |||
const stream = | |||
await navigator.mediaDevices.getUserMedia(constraints); | |||
stream.getTracks().forEach((track) => | |||
pc.addTrack(track, stream)); | |||
await pc.setLocalDescription(await pc.createAnswer()); | |||
signaling.send({desc: pc.localDescription}); | |||
} else if (desc.type === 'answer') { | |||
await pc.setRemoteDescription(desc); | |||
} else { | |||
console.log('Unsupported SDP type.'); | |||
} | |||
} else if (candidate) { | |||
await pc.addIceCandidate(candidate); | |||
} | |||
} catch (err) { | |||
console.error(err); | |||
} | |||
}; | |||
</syntaxhighlight> | |||
===RTCDataChannel=== | |||
<syntaxhighlight lang="javascript"> | |||
const localConnection = new RTCPeerConnection(servers); | |||
const remoteConnection = new RTCPeerConnection(servers); | |||
const sendChannel = | |||
localConnection.createDataChannel('sendDataChannel'); | |||
// ... | |||
remoteConnection.ondatachannel = (event) => { | |||
receiveChannel = event.channel; | |||
receiveChannel.onmessage = onReceiveMessage; | |||
receiveChannel.onopen = onReceiveChannelStateChange; | |||
receiveChannel.onclose = onReceiveChannelStateChange; | |||
}; | |||
function onReceiveMessage(event) { | |||
document.querySelector("textarea#send").value = event.data; | |||
} | |||
document.querySelector("button#send").onclick = () => { | |||
var data = document.querySelector("textarea#send").value; | |||
sendChannel.send(data); | |||
}; | |||
</syntaxhighlight> | |||
==JavaScript API== | |||
==Native APIs (C++)== | ==Native APIs (C++)== |