diff --git a/README.md b/README.md index 9a18030c..ffe05bb5 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,16 @@ -# POGO, Web-based Cloud Gaming Service -**SEA**: [http://cloud.webgame2d.com](http://cloud.webgame2d.com) | **US West**: [http://usw.cloud.webgame2d.com](http://usw.cloud.webgame2d.com) | **US East**: [http://use.cloud.webgame2d.com](http://use.cloud.webgame2d.com) | **Europe**: [http://eu.cloud.webgame2d.com](http://eu.cloud.webgame2d.com) | **Instruction**: [Instruction](document/instruction/) -For the best gaming experience, please select the closest region to you. +# Klog, Web-based Cloud Gaming Service +- **SEA**: [http://cloud.webgame2d.com](http://cloud.webgame2d.com) - **US West**: [http://usw.cloud.webgame2d.com](http://usw.cloud.webgame2d.com) +- **US East**: [http://use.cloud.webgame2d.com](http://use.cloud.webgame2d.com) - **Europe**: [http://eu.cloud.webgame2d.com](http://eu.cloud.webgame2d.com) +- [**Game Instruction**](document/instruction/) +For the best gaming experience, please select the closest region to you. **Video demo**: https://www.youtube.com/watch?v=koqWB1VKflo --- -POGO is an open source Cloud Gaming Service building on [WebRTC](https://github.com/pion) using browser as the main platform. +Klog is an open source Cloud Gaming Service building on [WebRTC](https://github.com/pion) using browser as the main platform. -POGO stands for "POcket Gaming Online" aims to bring the most convenient gaming experience to gamer. You can play any games on your browser directly, which is fully compatible on multi-platform like Desktop, Android, IOS. This flexibility enables modern online gaming experience to retro games starting with NES in this current release. +Klog aims to bring the most convenient gaming experience to gamer. You can play any games on your browser directly, which is fully compatible on multi-platform like Desktop, Android, IOS. This flexibility enables modern online gaming experience to retro games starting with NES in this current release. Note: The current state of POGO are not optimized for production. The service will still experience lag under heavy traffic. You can try hosting your own service following the instruction in the next session. @@ -18,9 +20,7 @@ Note: The current state of POGO are not optimized for production. The service wi 1. Cloud gaming: Game logic is handled in server and streamed to user. 2. Cross-platform compatibility: The game is run on webbrowser, the most universal builtin app. No console, plugin, external app or devices are needed. The device must support webRTC to perform streaming. Joystick is also supported. 3. Vertically scaled: Services are distributed. The closest server with highest free resource will be assigned to user. (In development) -4. Collaborative hosting: this is our invented term referring to the whole community can contribute to host the platform. Whenever the server is hosted and able to connect to the coordinator, it can join the cloud-gaming network and Collaboratively serve prod traffic. (In development) -5. Local link: If you host a server on your local machine and play game on other devices close to that, the game will automatically detect running local server and serve the traffic. (In development) -6. Cloud storage: Game state is storing on online storage, so you can come back to continue playing in a game. +4. Cloud storage: Game state is storing on online storage, so you can come back to continue playing in a game. ## Run on local by Docker @@ -35,13 +35,13 @@ Install dependencies * Install [libvpx](https://www.webmproject.org/code/) and [pkg-config](https://www.freedesktop.org/wiki/Software/pkg-config/) ``` # Ubuntu -apt-get install -y pkg-config libvpx-dev +apt-get install -y pkg-config libvpx-dev libopus-dev libopusfile-dev # MacOS -brew install libvpx pkg-config +brew install libvpx pkg-config libopus libopusfile # Windows -... +... not tested yet ... ``` And run @@ -49,8 +49,8 @@ And run * The scripts includes build the binary using Go module ## Documentation -[Design Doc](document/designdoc/) -[Implentation Doc](document/implementation/) +- ✏ [Design Doc](document/designdoc/) +- 💿 [Implementation Doc](document/implementation/) ## Follow up diff --git a/document/designdoc/README.md b/document/designdoc/README.md index fd80fedf..ad3f48ab 100644 --- a/document/designdoc/README.md +++ b/document/designdoc/README.md @@ -1,13 +1,13 @@ # Web-based Cloud Gaming Service Design Document -Web-based Cloud Gaming Service contains multiple workers for gaming streaming and a coordinator (Overlord) for distributing traffic and setup connection. +Web-based Cloud Gaming Service contains multiple workers for gaming stream and a coordinator (Overlord) for distributing traffic and pairing up connection. ## Worker Worker is responsible for streaming game to frontend ![worker](../img/worker.png) -- After Coordinator matches most appropriate server to the user, webRTC peer-to-peer handshake will be conducted. Coordinator will exchange the signature (WebRTC Session Remote Description) between two peers over Web Socket connection. +- After Coordinator matches the most appropriate server to the user, webRTC peer-to-peer handshake will be conducted. The coordinator will exchange the signature (WebRTC Session Remote Description) between two peers over Web Socket connection. - On worker, each user session will spawn a new room running a gaming emulator. Image stream and audio stream from emulator is captured and encoded to WebRTC streaming format. We applied Vp8 for Video compression and Opus for audio compression to ensure the smoothest experience. After finish encoded, these stream is then piped out to user and observers joining that room. - On the other hand, input from users is sent to workers over WebRTC DataChannel. Game logic on the emulator will be updated based on the input stream. - Game state is stored in cloud storage, so all workers can collaborate and keep the same understanding with each other. It allows user can continue from the saved state in the next time. @@ -22,5 +22,4 @@ Overlord is loadbalancer and coordinator, which is in charge of picking the most 2. Overlord will find the most suitable worker to serve the user. 3. Overlord collects all latencies from workers to users as well as CPU usage on each machine. 4. Overlord setup peer-to-peer handshake between worker and user by exchanging Session Description Protocol. -5. A game is hosted on worker and streamed to the user . - +5. A game is hosted on worker and streamed to the user. diff --git a/document/implementation/README.md b/document/implementation/README.md index ed0641ae..ce52ecf1 100644 --- a/document/implementation/README.md +++ b/document/implementation/README.md @@ -3,21 +3,41 @@ ## Code structure ``` . -├── cmd -│ ├── main.go +├── cmd: service entrypoint +│ ├── main.go: Spawn overlord or worker based on flag │ └── main_test.go -├── emulator: emulator internal -│ ├── director.go: coordinator of views -│ └── gameview.go: in game logic -├── overlord: coordinator of workers -├── games: roms list, no code logic ├── static: static file for front end │ ├── js │ │ └── ws.js: client logic │ ├── game.html: frontend with gameboy ui │ └── index_ws.html: raw frontend without ui +├── overlord: coordinator +│ ├── handlers.go: coordinator entrypoint +│ ├── browser.go: router listening to browser +│ └── worker.go: router listening to worker +├── games: roms list, no code logic +├── worker: integration between emulator + webrtc (communication) +│ ├── room: +│ │ ├── room.go: room logic +│ │ └── media.go: video + audio encoding +│ ├── handlers.go: worker entrypoint +│ └── overlord.go: router listening to overlord +├── emulator: emulator internal +│ ├── nes: NES device internal +│ ├── director.go: coordinator of views +│ └── gameview.go: in game logic ├── cws -│ └── cws.go: socket multiplexer library, used for signalling -├── webrtc: webrtc streaming logic -└── worker: integration between emulator + webrtc (communication) +│ └── cws.go: socket multiplexer library, used for signaling +└── webrtc: webrtc streaming logic ``` + +## Room +Room is a fundamental part of the system. Each user session will spawn a room with a game running inside. There is a pipeline to encode images and audio and stream them out from emulator to user. The pipeline also listens to all input and streams to the emulator. + +## Worker +Worker is an instance that can be provisioned to scale up the traffic. There are multiple rooms inside a worker. Worker will listen to overlord events in `overlord.go`. + +## Overlord +Overlord is the coordinator, which handles all communication with workers and frontend. +Overlord will pair up a worker and a user for peer streaming. In WebRTC handshaking, two peers need to exchange their signature (Session Description Protocol) to initiate a peerconnection. +Events come from frontend will be handled in `overlord/browser.go`. Events come from worker will be handled in `overlord/worker.go`. Overlord stays in the middle and relays handshake packages between workers and user. diff --git a/games/1943.nes b/games/1943.nes deleted file mode 100644 index eb7b8566..00000000 Binary files a/games/1943.nes and /dev/null differ diff --git a/games/Battle City.NES b/games/Battle City.NES deleted file mode 100644 index 29ed12ab..00000000 Binary files a/games/Battle City.NES and /dev/null differ diff --git a/games/Bubble Bobble.nes b/games/Bubble Bobble.nes deleted file mode 100644 index 3c3c0c34..00000000 Binary files a/games/Bubble Bobble.nes and /dev/null differ diff --git a/games/Captain America and the Avengers.nes b/games/Captain America and the Avengers.nes deleted file mode 100644 index 8a64f556..00000000 Binary files a/games/Captain America and the Avengers.nes and /dev/null differ diff --git a/games/Chip 'n Dale Rescue Rangers 2.nes b/games/Chip 'n Dale Rescue Rangers 2.nes deleted file mode 100644 index cfc8cbcb..00000000 Binary files a/games/Chip 'n Dale Rescue Rangers 2.nes and /dev/null differ diff --git a/games/Gradius.nes b/games/Gradius.nes deleted file mode 100644 index 29554884..00000000 Binary files a/games/Gradius.nes and /dev/null differ diff --git a/games/Ice Climber.nes b/games/Ice Climber.nes deleted file mode 100644 index 9437c724..00000000 Binary files a/games/Ice Climber.nes and /dev/null differ diff --git a/games/Kirby's Adventure.nes b/games/Kirby's Adventure.nes deleted file mode 100644 index f2ac915a..00000000 Binary files a/games/Kirby's Adventure.nes and /dev/null differ diff --git a/games/Mega Man 2.nes b/games/Mega Man 2.nes deleted file mode 100644 index ea261a3f..00000000 Binary files a/games/Mega Man 2.nes and /dev/null differ diff --git a/games/Mega Man 6.nes b/games/Mega Man 6.nes deleted file mode 100644 index 51e79a4a..00000000 Binary files a/games/Mega Man 6.nes and /dev/null differ diff --git a/games/Metal Gear.nes b/games/Metal Gear.nes deleted file mode 100644 index 0b10e689..00000000 Binary files a/games/Metal Gear.nes and /dev/null differ diff --git a/games/Mike Tyson's Punch-Out!!.nes b/games/Mike Tyson's Punch-Out!!.nes deleted file mode 100644 index 658ba89a..00000000 Binary files a/games/Mike Tyson's Punch-Out!!.nes and /dev/null differ diff --git a/games/Mortal Kombat 4.nes b/games/Mortal Kombat 4.nes deleted file mode 100644 index ee03f073..00000000 Binary files a/games/Mortal Kombat 4.nes and /dev/null differ diff --git a/games/Ninja Gaiden.nes b/games/Ninja Gaiden.nes deleted file mode 100644 index 6ba7a6ac..00000000 Binary files a/games/Ninja Gaiden.nes and /dev/null differ diff --git a/games/Nintendo World Cup.nes b/games/Nintendo World Cup.nes deleted file mode 100644 index 7710515d..00000000 Binary files a/games/Nintendo World Cup.nes and /dev/null differ diff --git a/games/Super Mario Bros 2.nes b/games/Super Mario Bros 2.nes deleted file mode 100644 index 58a7a3d2..00000000 Binary files a/games/Super Mario Bros 2.nes and /dev/null differ diff --git a/games/Super Mario Bros 3.nes b/games/Super Mario Bros 3.nes deleted file mode 100644 index 4402e759..00000000 Binary files a/games/Super Mario Bros 3.nes and /dev/null differ diff --git a/games/Teenage Mutant Ninja Turtles 3.nes b/games/Teenage Mutant Ninja Turtles 3.nes deleted file mode 100644 index c57e9454..00000000 Binary files a/games/Teenage Mutant Ninja Turtles 3.nes and /dev/null differ diff --git a/games/Zelda II.rom b/games/Zelda II.rom deleted file mode 100644 index d66573d2..00000000 Binary files a/games/Zelda II.rom and /dev/null differ diff --git a/pogo b/klog similarity index 71% rename from pogo rename to klog index d88df9eb..91016404 100755 Binary files a/pogo and b/klog differ diff --git a/run_local.sh b/run_local.sh index 89641323..4211633c 100755 --- a/run_local.sh +++ b/run_local.sh @@ -1,8 +1,8 @@ #!/bin/bash -go build -o pogo ./cmd +go build -o klog ./cmd # Run coordinator first -./pogo -overlordhost overlord & +./klog -overlordhost overlord & # Wait till overlord finish initialized # Run a worker connecting to overlord -./pogo -overlordhost ws://localhost:8000/wso +./klog -overlordhost ws://localhost:8000/wso # NOTE: Overlord and worker should be run separately. Local is for demo purpose diff --git a/static/js/global.js b/static/js/global.js index b99ea75e..c2ed838b 100644 --- a/static/js/global.js +++ b/static/js/global.js @@ -9,6 +9,7 @@ const INPUT_STATE_PACKET = 1; const PINGPONGPS = 5; const MENU_TOP_POSITION = 102; +const ICE_TIMEOUT = 2000; /* Global variables @@ -59,3 +60,4 @@ let isLayoutSwitched = false; var gameReady = false; var iceSuccess = true; +var iceSent = false; // TODO: set to false in some init event diff --git a/static/js/ws.js b/static/js/ws.js index e2b6c48e..08372301 100644 --- a/static/js/ws.js +++ b/static/js/ws.js @@ -209,14 +209,25 @@ function startWebRTC() { pc.onicecandidate = event => { if (event.candidate === null) { // send to ws - session = btoa(JSON.stringify(pc.localDescription)); - localSessionDescription = session; - log("Send SDP to remote peer"); - // TODO: Fix curPacketID - conn.send(JSON.stringify({"id": "initwebrtc", "data": session, "packet_id": curPacketID})); + if (!iceSent) { + session = btoa(JSON.stringify(pc.localDescription)); + log("Send SDP to remote peer"); + // TODO: Fix curPacketID + conn.send(JSON.stringify({"id": "initwebrtc", "data": session, "packet_id": curPacketID})); + iceSent = true + } } else { - conn.send(JSON.stringify({"id": "icecandidate", "data": JSON.stringify(event.candidate)})); console.log(JSON.stringify(event.candidate)); + // TODO: tidy up, setTimeout multiple time now + // timeout + setTimeout(() => { + log("Ice gathering timeout, send anyway") + if (!iceSent) { + session = btoa(JSON.stringify(pc.localDescription)); + conn.send(JSON.stringify({"id": "initwebrtc", "data": session, "packet_id": curPacketID})); + iceSent = true; + } + }, ICE_TIMEOUT) } }