-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Bootstap WebRTC PC connection using aiortc
- Loading branch information
1 parent
47cae78
commit b9320cb
Showing
5 changed files
with
140 additions
and
0 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"python.pythonPath": "/Library/Frameworks/Python.framework/Versions/3.7/bin/python3" | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,17 @@ | ||
# Camlio Core | ||
|
||
Core module responsible for processing webcam stream | ||
|
||
## Start engine | ||
|
||
```bash | ||
python engine.py --port 8081 --cert-file secrets/server.crt --key-file secrets/server.key --video_device_index=4 | ||
``` | ||
|
||
### FAQs | ||
|
||
1. How to find the webcam index? | ||
|
||
```bash | ||
ffmpeg -f avfoundation -list_devices true -i "" | ||
``` |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
import argparse | ||
import asyncio | ||
import json | ||
import logging | ||
import os | ||
import platform | ||
import ssl | ||
|
||
import aiohttp_cors | ||
from aiohttp import web | ||
from aiortc import RTCPeerConnection, RTCSessionDescription | ||
from aiortc.contrib.media import MediaPlayer | ||
|
||
from video_stream import CamlioVideoStreamTrack | ||
|
||
ROOT = os.path.dirname(__file__) | ||
|
||
|
||
async def offer(request): | ||
params = await request.json() | ||
offer = RTCSessionDescription(sdp=params["sdp"], type=params["type"]) | ||
|
||
pc = RTCPeerConnection() | ||
pcs.add(pc) | ||
|
||
@pc.on("iceconnectionstatechange") | ||
async def on_iceconnectionstatechange(): | ||
print("ICE connection state is %s" % pc.iceConnectionState) | ||
if pc.iceConnectionState == "failed": | ||
await pc.close() | ||
pcs.discard(pc) | ||
|
||
# open media source | ||
if args.play_from: | ||
player = MediaPlayer(args.play_from) | ||
else: | ||
player = None | ||
|
||
await pc.setRemoteDescription(offer) | ||
for t in pc.getTransceivers(): | ||
if t.kind == "audio" and player and player.audio: | ||
pc.addTrack(player.audio) | ||
elif t.kind == "video": | ||
pc.addTrack(CamlioVideoStreamTrack(args.video_device_index)) | ||
|
||
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() | ||
|
||
|
||
if __name__ == "__main__": | ||
parser = argparse.ArgumentParser(description="Camlio engine") | ||
parser.add_argument("--video-device-index", | ||
help="Index of video camera", type=int, default=0) | ||
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( | ||
"--play-from", help="Read the media from a file and stream it."), | ||
parser.add_argument( | ||
"--port", type=int, default=8080, help="Port for HTTP server (default: 8080)" | ||
) | ||
parser.add_argument("--verbose", "-v", action="count") | ||
args = parser.parse_args() | ||
|
||
if args.verbose: | ||
logging.basicConfig(level=logging.DEBUG) | ||
|
||
if args.cert_file: | ||
ssl_context = ssl.SSLContext() | ||
ssl_context.load_cert_chain(args.cert_file, args.key_file) | ||
else: | ||
ssl_context = None | ||
|
||
app = web.Application() | ||
cors = aiohttp_cors.setup(app, defaults={ | ||
# Allow all to read all CORS-enabled resources from | ||
# *. | ||
"*": aiohttp_cors.ResourceOptions(expose_headers="*", | ||
allow_headers="*"), | ||
}) | ||
app.on_shutdown.append(on_shutdown) | ||
cors.add( | ||
app.router.add_route("POST", "/offer", offer) | ||
) | ||
web.run_app(app, port=args.port, ssl_context=ssl_context) |
Empty file.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import cv2 | ||
import numpy | ||
from aiortc import VideoStreamTrack | ||
from av import VideoFrame | ||
|
||
|
||
class CamlioVideoStreamTrack(VideoStreamTrack): | ||
def __init__(self, video_device_index): | ||
super().__init__() | ||
self.video_capture = cv2.VideoCapture(video_device_index) | ||
|
||
async def recv(self): | ||
try: | ||
pts, time_base = await self.next_timestamp() | ||
ret, raw = self.video_capture.read() | ||
|
||
frame = VideoFrame.from_ndarray(raw, format="bgr24") | ||
frame.pts = pts | ||
frame.time_base = time_base | ||
return frame | ||
except Exception as e: | ||
print(e) |