diff --git a/README.md b/README.md index 2579118d2..684df167e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# livekit-server +# LiveKit - Open source, distributed video/audio rooms based on WebRTC ## Building @@ -8,8 +8,8 @@ Run `./bootstrap.sh` to install mage, then `mage` to build the project ## Creating API keys -LiveKit utilizes JWT based access tokens to ensure secure access to the APIs and Rooms. -Because of this, the server needs a list of valid API keys and secrets to validate the provided tokens. +LiveKit utilizes JWT based access tokens for authentication to all of its APIs. +Because of this, the server needs a list of valid API keys and secrets to validate the provided tokens. For more, see [Authentication](docs/authentication.md). Generate API key/secret pairs with: @@ -21,24 +21,34 @@ Store the generate keys in a YAML file like: ```yaml APIwLeah7g4fuLYDYAJeaKsSE: 8nTlwISkb-63DPP7OH4e.nw.J44JjicvZDiz8J59EoQ+ -... ``` -## Starting the server +## Running the server -With the key file ready, you can start LiveKit with +LiveKit server is a distributed service that is architected for scale. It's self-encapsulated in a single binary, and horizontally scalable by adding more instances. In a production setup, the only external dependency is Redis. LiveKit uses Redis to store room & participant information, and utilizes its pub/sub functionality to coordinate activity between instances. + +### Running for development + +In development mode, LiveKit has no external dependencies. With the key file ready, you can start LiveKit with ``` -./bin/livekit-server --key-file +./bin/livekit-server --key-file --dev ``` +the `--dev` flag turns on log verbosity to make it easier for local debugging/development + +### Running for production + +TBD + ## CLI The CLI provides a few tools that makes working with LiveKit easier: -* Room creation/deletion/etc -* Access token creation -* Joining room as a participant -* Publishing files as tracks to a room + +- Room creation/deletion/etc +- Access token creation +- Joining room as a participant +- Publishing files as tracks to a room ### Setting API key and secret @@ -58,9 +68,11 @@ export LK_API_SECRET= ### Creating a participant token ``` -./bin/livekit-cli create-token --join --r myroom --p +./bin/livekit-cli create-token --join --r myroom --dev --p ``` +`--dev` creates a development token that doesn't expire for a year + ### Joining a participant ``` @@ -70,8 +82,9 @@ export LK_API_SECRET= ### Publishing static files as tracks To use the publish client, download the following files to your computer: -* [happier.ivf](https://www.dropbox.com/s/4ze93d6070s0qj7/happier.ivf?dl=0) - audio track in VP8 -* [happier.ogg](https://www.dropbox.com/s/istrnolnh7avftq/happier.ogg?dl=0) - audio track in ogg + +- [happier.ivf](https://www.dropbox.com/s/4ze93d6070s0qj7/happier.ivf?dl=0) - video track in VP8 +- [happier.ogg](https://www.dropbox.com/s/istrnolnh7avftq/happier.ogg?dl=0) - audio track in ogg Join as a publishing participant @@ -81,20 +94,10 @@ Join as a publishing participant That's it, join the room with another participant and see it receiving those tracks -## Protocol +## APIs & Protocol -LiveKit provides room based audio/video/data channels based on WebRTC. -It provides a set of APIs to manipulate rooms, as well as its own signaling protocol to exchange room and participant information. +`livekit-server` provides two primary services, a `Room` service that allows for room creation & management, and `RTC` service to handle real time communications. -Room APIs are defined in room.proto, it's fairly straight forward with typical CRUD APIs. Room APIs are HTTP, built with Twirp and follows [its the conventions](https://twitchtv.github.io/twirp/docs/routing.html). +Room APIs are defined in [room.proto](proto/room.proto), it's fairly straight forward with typical CRUD APIs. Room APIs are in HTTP, built with Twirp and follows [its the conventions](https://twitchtv.github.io/twirp/docs/routing.html). -The RTC service provides the signaling and everything else when the client interacts with the room. RTC service requires bidirectional -communication between the client and server, and exchanges messages via WebSocket. Messages are encoded in either JSON or binary protobuf, -see `rtc.proto` for the message structure. - -The flow for interaction is: -1. Establish WebSocket to ws://:/rtc -1. Server will send back a `SignalResponse` with a `join` response. It'll include the new participant's details, and what other participants are in the room -1. Client sends a `SignalRequest` with an WebRTC `offer` -1. Server will send back a `SignalResponse` with an `answer` -1. Client and server will exchange ice candidates via `trickle` in the request & responses +The RTC service provides the signaling and everything else when the client interacts with the room. See [RTC Protocol](docs/protocol.md). diff --git a/docs/authentication.md b/docs/authentication.md new file mode 100644 index 000000000..53fb3ba26 --- /dev/null +++ b/docs/authentication.md @@ -0,0 +1,12 @@ +# Authentication + +LiveKit uses access tokens (JWT) to authenticate clients. A pair of API key and secret key is used to authenticate each API holder. + +An access token encapsulate a few pieces of information: + +- Grants: what permissions does this token have +- Issuer: which api key issued the token +- Expiration: how long should it be valid for +- Identity: the participant's identity (when joining a room) + +Access tokens can be created with `livekit-cli`, or any of the livekit server SDKs diff --git a/docs/protocol.md b/docs/protocol.md index a35a25021..7b6e44791 100644 --- a/docs/protocol.md +++ b/docs/protocol.md @@ -19,7 +19,17 @@ When the WebSocket connection is established, server will first provide informat Negotiation is use to describe the offer/answer process in WebRTC. After the initial offer/answer process to establish the connection, negotiations are needed whenever track changes are made to the current session. Because WebRTC is a peer to peer protocol, negotiations can be initiated by either party as needed. -This creates a synchronization headache, as if both sides are initiating negotiations at the exact same time, it creates a race condition in which the peers would receive unexpected responses from the other side. This is called [glare](https://tools.ietf.org/agenda/82/slides/rtcweb-10.pdf). +### Server initiated negotiations + +LiveKit server will need to negotiate the connection with each participant when the participant subscribes to new tracks. + +1. server sends an `offer` to client +2. client calls `setRemoteDescription`, and create an `answer` for the server +3. server receives answer and concludes the negotiation cycle + +### Client initiated negotiations + +Because each of the peers could initiate a negotiation at any point, this creates a synchronization headache. Depending on timing, there could be a race condition in which the peers would receive unexpected responses from the other side. This is called [glare](https://tools.ietf.org/agenda/82/slides/rtcweb-10.pdf). In LiveKit, we've added a layer of synchronization so that negotiations are more deterministic. The server is the authority determining who should be issuing offers in a negotiation cycle. When the client wants to issue an offer to the server, it needs to follow this flow. diff --git a/pkg/rtc/participant.go b/pkg/rtc/participant.go index 040382575..9265dc6ac 100644 --- a/pkg/rtc/participant.go +++ b/pkg/rtc/participant.go @@ -322,6 +322,10 @@ func (p *ParticipantImpl) Close() error { } close(p.rtcpCh) p.onICECandidate = nil + p.peerConn.OnDataChannel(nil) + p.peerConn.OnICECandidate(nil) + p.peerConn.OnNegotiationNeeded(nil) + p.peerConn.OnTrack(nil) p.updateState(livekit.ParticipantInfo_DISCONNECTED) p.responseSink.Close() if p.onClose != nil { diff --git a/sample-prod-config.yaml b/sample-prod-config.yaml new file mode 100644 index 000000000..72efbcf48 --- /dev/null +++ b/sample-prod-config.yaml @@ -0,0 +1,6 @@ +port: 7880 +redis: + address: redis.host:6379 +multi_node: true +keys: + key1: secret1