connect from secureput iphone app

This commit is contained in:
Keyvan Fatehi
2023-01-16 01:17:09 -08:00
parent 84df7d4feb
commit 9bde383511
10 changed files with 299 additions and 292 deletions

138
server.py
View File

@@ -6,104 +6,94 @@ import logging
import os
import ssl
from typing import OrderedDict
from aiohttp import web
from aiortc import RTCPeerConnection, RTCSessionDescription, RTCRtpCodecCapability
from aiortc import RTCPeerConnection, RTCSessionDescription, RTCIceCandidate, RTCRtpCodecCapability, RTCConfiguration, RTCIceServer
from compressed_vipc_track import VisionIpcTrack
from desktop_stream_track import DesktopStreamTrack
from aiortc.contrib.signaling import BYE
from secureput.secureput_signaling import SecureputSignaling
ROOT = os.path.dirname(__file__)
# optional, for better performance
# try:
# import uvloop
# except ImportError:
# uvloop = None
cams = ["roadEncodeData","wideRoadEncodeData","driverEncodeData"]
cam = 1
async def index(request):
content = open(os.path.join(ROOT, "index.html"), "r").read()
return web.Response(content_type="text/html", text=content)
async def signal(pc, signaling):
await signaling.connect()
async def javascript(request):
content = open(os.path.join(ROOT, "client.js"), "r").read()
return web.Response(content_type="application/javascript", text=content)
while True:
obj = await signaling.receive()
# The peer trickles, but aiortc doesn't https://github.com/aiortc/aiortc/issues/227
# > aioice, the library which aiortc uses for ICE does not trickle ICE candidates:
# > you get all the candidates in one go. As such once you have called setLocalDescription()
# > for your offer or answer, all your ICE candidates are listed in pc.localDescription.
if isinstance(obj, RTCIceCandidate):
pc.addIceCandidate(obj)
async def offer(request):
params = await request.json()
offer = RTCSessionDescription(sdp=params["sdp"], type=params["type"])
if isinstance(obj, RTCSessionDescription):
if pc != None and pc.iceConnectionState != "failed":
await pc.close()
pc = RTCPeerConnection(configuration=RTCConfiguration([RTCIceServer("stun:stun.secureput.com:3478")]))
pc = RTCPeerConnection()
pcs.add(pc)
@pc.on("connectionstatechange")
async def on_connectionstatechange():
print("Connection state is %s" % pc.iceConnectionState)
if pc.iceConnectionState == "failed":
await pc.close()
@pc.on("connectionstatechange")
async def on_connectionstatechange():
print("Connection state is %s" % pc.connectionState)
if pc.connectionState == "failed":
await pc.close()
pcs.discard(pc)
@pc.on('datachannel')
def on_datachannel(channel):
print("data channel!")
@channel.on('message')
async def on_message(message):
print("message!!")
# TODO: stream the microphone
audio = None
# video = VisionIpcTrack(cams[int(args.cam)], args.addr)
video = DesktopStreamTrack()
video_sender = pc.addTrack(video)
await pc.setRemoteDescription(offer)
answer = await pc.createAnswer()
await pc.setLocalDescription(answer)
return web.Response(
content_type="application/json",
text=json.dumps(
{"sdp": pc.localDescription.sdp, "type": pc.localDescription.type}
),
)
pcs = set()
async def on_shutdown(app):
# close peer connections
coros = [pc.close() for pc in pcs]
await asyncio.gather(*coros)
pcs.clear()
await pc.setRemoteDescription(obj)
if obj.type == 'offer':
# TODO: stream the microphone
audio = None
video = VisionIpcTrack(cams[int(cam)], "tici")
# video = DesktopStreamTrack()
pc.addTrack(video)
answer = await pc.createAnswer()
await pc.setLocalDescription(answer)
await signaling.send(pc.localDescription)
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Decode video streams and broadcast via WebRTC")
parser = argparse.ArgumentParser(description="Comma Body WebRTC Service")
parser.add_argument("--addr", default='tici', help="Address of comma three")
# Not implemented (yet?). Geo already made the PoC for this, it should be possible.
# parser.add_argument("--nvidia", action="store_true", help="Use nvidia instead of ffmpeg")
parser.add_argument("--cam", default="0", help="Camera to stream")
parser.add_argument("--cert-file", help="SSL certificate file (for HTTPS)")
parser.add_argument("--key-file", help="SSL key file (for HTTPS)")
parser.add_argument(
"--host", default="0.0.0.0", help="Host for HTTP server (default: 0.0.0.0)"
)
parser.add_argument(
"--port", type=int, default=8080, help="Port for HTTP server (default: 8080)"
)
parser.add_argument("--signaling-server", default="wss://signal.secureput.com", help="Signaling server to use")
parser.add_argument("--stun-server", default="stun:stun.secureput.com:3478", help="STUN server to use")
parser.add_argument("--verbose", "-v", action="count")
args = parser.parse_args()
if args.verbose:
logging.basicConfig(level=logging.DEBUG)
else:
logging.basicConfig(level=logging.INFO)
if args.cert_file:
ssl_context = ssl.SSLContext()
ssl_context.load_cert_chain(args.cert_file, args.key_file)
else:
ssl_context = None
# if uvloop is not None:
# asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
app = web.Application()
app.on_shutdown.append(on_shutdown)
app.router.add_get("/", index)
app.router.add_get("/client.js", javascript)
app.router.add_post("/offer", offer)
web.run_app(app, host=args.host, port=args.port, ssl_context=ssl_context)
pc = RTCPeerConnection(configuration=RTCConfiguration([RTCIceServer(args.stun_server)]))
signaling = SecureputSignaling(args.signaling_server)
coro = signal(pc, signaling)
# run event loop
loop = asyncio.get_event_loop()
try:
loop.run_until_complete(coro)
except KeyboardInterrupt:
pass
finally:
loop.run_until_complete(pc.close())
loop.run_until_complete(signaling.close())