Last active
January 30, 2022 12:02
-
-
Save Iftimie/8981086790636460947633bc1055774e to your computer and use it in GitHub Desktop.
WebRTC 2
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export const CHAT_CHANNEL = "chat" | |
export function waitForAllICE(peerConnection) { | |
return waitForEvent((fulfill) => { | |
peerConnection.onicecandidate = (iceEvent) => { | |
if (iceEvent.candidate === null) | |
fulfill() | |
} | |
}) | |
} | |
export function waitForEvent(user_function) { | |
return new Promise((fulfill, reject) => { | |
user_function(fulfill) | |
setTimeout(() => reject("Waited too long"), 60000) | |
}) | |
} | |
export function addConnectionStateHandler(peerConnection) { | |
peerConnection.onconnectionstatechange = function () { | |
console.log(peerConnection.connectionState) | |
}; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from django.urls import path | |
from . import views | |
from django.conf.urls import include | |
import django_eventstream | |
urlpatterns = [ | |
path('offer', views.offer, name='offer'), | |
path('answer', views.answer, name='answer'), | |
path('clear', views.clear, name='clear'), | |
path('events/', include(django_eventstream.urls), { | |
'channels': ['testchannel'] | |
}), | |
path('home/<user>', views.home, name='home'), | |
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from django.http import JsonResponse | |
from django.shortcuts import render | |
from django.views.decorators.csrf import csrf_exempt | |
from django_eventstream import send_event | |
from django.http.response import HttpResponse | |
import json | |
storage = { | |
"user1_chat_offer": '""', | |
"user2_chat_offer": '""' | |
} | |
@csrf_exempt | |
def offer(request): | |
if request.method == "POST": | |
request_body = json.loads(request.body) | |
received_offer = json.dumps(request_body['offer']) | |
user = request_body['user'] | |
if "user1" == user: | |
storage["user1_chat_offer"] = received_offer | |
returned_offer = storage["user2_chat_offer"] | |
else: | |
storage["user2_chat_offer"] = received_offer | |
returned_offer = storage["user1_chat_offer"] | |
peer_offer_sdp = json.loads(returned_offer) | |
return JsonResponse({'offer': peer_offer_sdp}) | |
@csrf_exempt | |
def answer(request): | |
if request.method == "POST": | |
request_body = json.loads(request.body) | |
send_event('testchannel', 'message', request_body['answer']) | |
return HttpResponse("ok") | |
@csrf_exempt | |
def clear(request): | |
if request.method == "POST": | |
storage["user1_chat_offer"] = '""' | |
storage["user2_chat_offer"] = '""' | |
return HttpResponse("ok") | |
def home(request, user): | |
return render(request, 'mainapp/index.html', {"user": user}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<html> | |
<head> | |
<title>WebRTC</title> | |
<script type="module" src="index.js"></script> | |
</head> | |
<body> | |
<h1>Check the console</h1> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as common from './common.js'; | |
console.log("\n".repeat(10)) | |
async function start() { | |
const [peerConnection, dataChannel] = initializeBeforeCreatingOffer() | |
await prepareOfferSDP(peerConnection) | |
const remoteOfferString = prompt("Peer offer (skip if caller peer)"); | |
if (remoteOfferString) { | |
await beCallee(remoteOfferString, peerConnection) | |
} else { | |
await beCaller(peerConnection, dataChannel) | |
} | |
} | |
function initializeBeforeCreatingOffer() { | |
const peerConnection = new RTCPeerConnection() | |
common.addConnectionStateHandler(peerConnection) | |
const dataChannel = peerConnection.createDataChannel(common.CHAT_CHANNEL) | |
dataChannel.onmessage = function (e) { | |
console.log("Received message: ", e.data) | |
}; | |
return [peerConnection, dataChannel] | |
} | |
async function prepareOfferSDP(peerConnection) { | |
const localOffer = await peerConnection.createOffer() | |
await peerConnection.setLocalDescription(localOffer) | |
await common.waitForAllICE(peerConnection) | |
const localOfferWithICECandidates = peerConnection.localDescription | |
console.log("localOfferWithICECandidates:") | |
console.log(JSON.stringify(localOfferWithICECandidates)) | |
} | |
async function beCallee(remoteOfferString, peerConnection) { | |
await receiveOfferSDP(peerConnection, remoteOfferString) | |
await sendAnswerSDP(peerConnection) | |
const dataChannel = await waitForDataChannel(peerConnection) | |
console.log("Sending message, check the other tab") | |
dataChannel.send("World") | |
} | |
async function receiveOfferSDP(peerConnection, remoteOfferString) { | |
const remoteOffer = new RTCSessionDescription(JSON.parse(remoteOfferString)) | |
await peerConnection.setRemoteDescription(remoteOffer) | |
} | |
async function sendAnswerSDP(peerConnection) { | |
const localAnswer = await peerConnection.createAnswer() | |
peerConnection.setLocalDescription(localAnswer) | |
await common.waitForAllICE(peerConnection) | |
const localAnswerWithICECandidates = peerConnection.localDescription | |
console.log("localAnswerWithICECandidates:") | |
console.log(JSON.stringify(localAnswerWithICECandidates)) | |
} | |
function waitForDataChannel(peerConnection) { | |
return common.waitForEvent((fulfill) => { | |
peerConnection.ondatachannel = function (e) { | |
const dataChannel = e.channel | |
dataChannel.onmessage = function (e) { | |
console.log("Received message: ", e.data) | |
}; | |
fulfill(dataChannel) | |
} | |
}) | |
} | |
async function beCaller(peerConnection, dataChannel) { | |
await receiveAnswerSDP(peerConnection) | |
await sendMessage(dataChannel) | |
} | |
async function receiveAnswerSDP(peerConnection) { | |
console.log("Will wait for answer") | |
const remoteAnswerString = prompt("Peer answer"); | |
const remoteAnswer = JSON.parse(remoteAnswerString) | |
peerConnection.setRemoteDescription(remoteAnswer) | |
} | |
async function sendMessage(dataChannel) { | |
await waitForDataChannelOpen(dataChannel) | |
console.log("Sending message. Check the other tab") | |
dataChannel.send("Hello") | |
} | |
function waitForDataChannelOpen(dataChannel) { | |
return common.waitForEvent((fulfill) => { | |
dataChannel.onopen = function() { | |
if (dataChannel.readyState == "open") { | |
fulfill() | |
} | |
}; | |
}) | |
} | |
start() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment