7. What is WebRTC?
WebRTC (Web Real-Time Communication) is an API
definition drafted by the World Wide Web Consortium
(W3C) that supports browser-to-browser applications
for voice calling, video chat, and P2P file sharing
without the need of either internal or external plugins.
8.
9.
10. You need an adaptor
Implementation in browsers is
currently inconsistent
Some APIs are still in flux
I’ll be using rtcninja
https://github.com/eface2face/rtcninja.js
18. RTCDataChannel
P2P, message boundary based
channel for arbitrary data
Implemented using SCTP, different
reliability choices possible
This is the game-changer
Did I mention it’s P2P?
23. The Protocol
Users enter the roulette when they
connect over WebSocket
3 types of messages: offer_request,
offer and answer
No end message, just disconnect the
WebSocket
24.
25. Shopping for a
framework
Python >= 3.3, because future!
WebSocket support built-in
Async, because blocking is so 2001
New, because hype!
29. class WebSocketHandler:
def __init__(self):
self.waiter = None
!
@asyncio.coroutine
def __call__(self, request):
ws = web.WebSocketResponse(protocols=('callroulette',))
ws.start(request)
!
conn = Connection(ws)
if self.waiter is None:
self.waiter = asyncio.Future()
fs = [conn.read(), self.waiter]
done, pending = yield from asyncio.wait(fs, return_when=asyncio.FIRST_COMPLETED)
if self.waiter not in done:
# the connection was most likely closed
self.waiter = None
return ws
other = self.waiter.result()
self.waiter = None
reading_task = pending.pop()
asyncio.async(self.run_roulette(conn, other, reading_task))
else:
self.waiter.set_result(conn)
!
yield from conn.wait_closed()
!
return ws
30. @asyncio.coroutine
def run_roulette(self, peerA, peerB, initial_reading_task):
log.info('Running roulette: %s, %s' % (peerA, peerB))
!
def _close_connections():
peerA.close()
peerB.close()
!
# request offer
data = dict(type='offer_request');
peerA.write(json.dumps(data))
!
# get offer
# I cannot seem to cancel the reading task that was started before, which is the
# only way one can know if the connection was closed, so use if for the initial
# reading
try:
data = yield from asyncio.wait_for(initial_reading_task, READ_TIMEOUT)
except asyncio.TimeoutError:
data = ''
if not data:
return _close_connections()
!
data = json.loads(data)
if data.get('type') != 'offer' or not data.get('sdp'):
log.warning('Invalid offer received')
return _close_connections()
31. # send offer
data = dict(type='offer', sdp=data['sdp']);
peerB.write(json.dumps(data))
!
# wait for answer
data = yield from peerB.read(timeout=READ_TIMEOUT)
if not data:
return _close_connections()
!
data = json.loads(data)
if data.get('type') != 'answer' or not data.get('sdp'):
log.warning('Invalid answer received')
return _close_connections()
!
# dispatch answer
data = dict(type='answer', sdp=data['sdp']);
peerA.write(json.dumps(data))
!
# wait for end
fs = [peerA.read(), peerB.read()]
yield from asyncio.wait(fs, return_when=asyncio.FIRST_COMPLETED)
!
# close connections
return _close_connections()