forked from 8xFF/atm0s-media-server
-
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.
- Loading branch information
Showing
76 changed files
with
3,178 additions
and
73 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
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 |
---|---|---|
|
@@ -2,4 +2,5 @@ | |
tarpaulin-report.html | ||
.atm0s | ||
/maxminddb-data | ||
.vscode | ||
.vscode | ||
book |
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,9 @@ | ||
[book] | ||
title = "Atm0s Media Server development and user guide" | ||
src = "docs" | ||
|
||
[preprocessor.mermaid] | ||
command = "mdbook-mermaid" | ||
|
||
[output.html] | ||
additional-js = ["mermaid.min.js", "mermaid-init.js"] |
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,58 @@ | ||
# Summary | ||
|
||
- [Introduction](README.md) | ||
- [Getting started](getting-started/README.md) | ||
- [Installation](getting-started/installation/README.md) | ||
- [Single zone](getting-started/installation/single-zone.md) | ||
- [Multi zones](getting-started/installation/multi-zones.md) | ||
- [Kubernetes](getting-started/installation/kubernetes.md) | ||
|
||
- [Quick Start](getting-started/quick-start/README.md) | ||
- [Whip/Whep](getting-started/quick-start/whip-whep.md) | ||
- [RTMP](getting-started/quick-start/rtmp.md) | ||
- [WebRTC SDK](getting-started/quick-start/webrtc-sdk.md) | ||
- [Sample application](getting-started/quick-start/sample-application.md) | ||
|
||
- [FAQ](getting-started/faq.md) | ||
- [Troubleshooting](getting-started/troubleshooting.md) | ||
|
||
- [User guide](user-guide/README.md) | ||
- [Concepts](user-guide/concepts.md) | ||
- [SDKs](user-guide/sdks.md) | ||
- [Configuration](user-guide/configuration.md) | ||
- [Features](user-guide/features/README.md) | ||
- [Audio Mixer](user-guide/features/audio-mixer.md) | ||
- [Cluster](user-guide/features/cluster.md) | ||
- [Authentication and multi-tenancy](user-guide/features/authentication-and-multi-tenancy.md) | ||
- [Simulcast/Svc](user-guide/features/simulcast-svc.md) | ||
- [Recording](user-guide/features/recording.md) | ||
|
||
- [Integration](user-guide/integration.md) | ||
- [Usage examples](user-guide/usage-examples.md) | ||
- [Upgrade](user-guide/upgrade.md) | ||
|
||
- [Contributor guide](contributor-guide/README.md) | ||
- [Getting Started](contributor-guide/getting-started.md) | ||
- [Architecture](contributor-guide/architecture.md) | ||
- [Features](contributor-guide/features/README.md) | ||
- [Audio Mixer](contributor-guide/features/audio-mixer.md) | ||
- [Simulcast/Svc](contributor-guide/features/simulcast-svc.md) | ||
- [Recording](contributor-guide/features/recording.md) | ||
- [Cluster](contributor-guide/features/cluster.md) | ||
- [Authentication](contributor-guide/features/authentication.md) | ||
|
||
- [Transports](contributor-guide/transports/README.md) | ||
- [WebRTC](contributor-guide/transports/webrtc.md) | ||
- [SIP](contributor-guide/transports/sip.md) | ||
- [RTMP](contributor-guide/transports/rtmp.md) | ||
- [Whip-Whep](contributor-guide/transports/whip-whep.md) | ||
|
||
- [Middlewares](contributor-guide/middlewares/README.md) | ||
- [Mix-minus](contributor-guide/middlewares/mix-minus.md) | ||
- [Logging](contributor-guide/middlewares/logging.md) | ||
- [Whep](contributor-guide/middlewares/whep.md) | ||
|
||
- [Servers](contributor-guide/servers/README.md) | ||
- [Gateway](contributor-guide/servers/gateway.md) | ||
- [Media Server](contributor-guide/servers/media-server.md) | ||
- [Connector](contributor-guide/servers/connector.md) |
This file was deleted.
Oops, something went wrong.
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,13 @@ | ||
# Contributor guide | ||
|
||
This document is intended for developers who want to contribute to atm0s-media-server. It contains information about the project, the codebase, development environment setup, and more. | ||
|
||
## Table of contents | ||
|
||
- [Getting started](./getting-started.md) | ||
- [Architecture](./architecture.md) | ||
- [Features](./features/) | ||
- [Transports](./transports/) | ||
- [Middlewares](./middlewares/) | ||
- [Servers](./servers/) | ||
- [RFCs](./rfcs/) |
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,119 @@ | ||
# Architecture | ||
|
||
To understand atm0s-media-server, this document will introduce some design approaches about it. The document is split into 2 parts: abstract design and implementation design. | ||
|
||
## Abstract design | ||
|
||
Different from other media servers that are based on single node architecture and manual relay between nodes, atm0s-media-server is designed with a global cluster from the start. We don't rely on any single node or single source of data, you can imagine that we have a huge cluster across many zones which supports: | ||
|
||
- Key Value store: supports HashMap, Set, Del, Sub | ||
- Publish and Subscribe: supports publish and subscribe | ||
|
||
For any media server, we only need some base features: | ||
|
||
- Clients connect to the server and join a room | ||
- Clients receive room events: peer joined, left, or stream started, updated, ended | ||
- Clients receive stream data from other peers | ||
|
||
Next, we will show how easy it is to implement with the KeyValue and Pubsub mechanisms. | ||
|
||
KeyValue store: | ||
|
||
- MapID: room identifier | ||
- Key: peer identifier, stream identifier | ||
- Value: peer info, stream info | ||
- Subscriber: each peer in the room | ||
|
||
PubSub: | ||
|
||
- Channel: room/peer/stream as identifier | ||
- Publisher: the peer who publishes the stream` | ||
- Subscriber: the peers who subscribe to the stream | ||
|
||
Each time a peer joins a room, we will set the key-value according to the peer info and the stream it published. Other peers will receive events from the key-value store and subscribe to the stream channel if needed. By doing that, audio and video data will be transferred to the peers. | ||
|
||
When a peer leaves a room, we will remove the key-value and unsubscribe from the stream channel. Other peers will receive events from the key-value store and unsubscribe from the stream channel if needed. | ||
|
||
![How it works](../imgs/architecture/how-it-works.excalidraw.png) | ||
|
||
About PubSub between nodes, atm0s-sdn overlay network ensures both bandwidth saving and smooth data flow. The nodes automatically select the best path between the publisher and subscriber, optimizing bandwidth usage. For example, in the network diagram below, the route path is selected to provide the most optimized and smooth data flow. With this approach, node 1 sends data to node 2 only once, and then node 2 takes care of sending the data to both node 3 and node 4, resulting in an optimized and bandwidth-saving data flow. | ||
|
||
![Why it's fast](../imgs/architecture/why-it-fast.excalidraw.png) | ||
|
||
## Implementations | ||
|
||
To implement the above mechanism, the source code is divided into three main components: | ||
|
||
- Transport: This component handles communication with clients, including SIP, RTMP, and WebRTC (SDK, Whip, Whep). | ||
- Endpoint: The endpoint component is responsible for processing the inner logic of the system, such as managing rooms and handling RPC. Additionally, middleware can be added to the endpoint to implement additional features like logging, audio mixing, and custom behaviors. | ||
- Cluster: The cluster component facilitates communication with the key-value store and pub-sub system. | ||
|
||
The relationship between these components is illustrated in the diagram below: | ||
|
||
![Architecture](../imgs/architecture/implement-layers.excalidraw.png) | ||
|
||
### Transport | ||
|
||
Transport is create with single trait atm0s-media-server-transport::Transport. The trait is defined as bellow: | ||
|
||
```Rust | ||
#[async_trait::async_trait] | ||
pub trait Transport<E, RmIn, RrIn, RlIn, RmOut, RrOut, RlOut> { | ||
fn on_tick(&mut self, now_ms: u64) -> Result<(), TransportError>; | ||
fn on_event(&mut self, now_ms: u64, event: TransportOutgoingEvent<RmOut, RrOut, RlOut>) -> Result<(), TransportError>; | ||
fn on_custom_event(&mut self, now_ms: u64, event: E) -> Result<(), TransportError>; | ||
async fn recv(&mut self, now_ms: u64) -> Result<TransportIncomingEvent<RmIn, RrIn, RlIn>, TransportError>; | ||
async fn close(&mut self, now_ms: u64); | ||
} | ||
``` | ||
|
||
Each transport instance will be managed by the endpoint in a simple way: | ||
|
||
- The endpoint will call `on_tick` periodically, for example, every 100ms. | ||
- The endpoint will pass events to the transport using `on_event`. | ||
- The endpoint will pass custom events to the transport using `on_custom_event`. Custom events are from external sources like RPC and may be removed in the future. | ||
- The endpoint will call `recv` to retrieve events from the transport. | ||
|
||
The event to the Transport is defined as below: | ||
|
||
```Rust | ||
#[derive(PartialEq, Eq, Debug)] | ||
pub enum TransportOutgoingEvent<RE, RR, RL> { | ||
RemoteTrackEvent(TrackId, RemoteTrackOutgoingEvent<RR>), | ||
LocalTrackEvent(TrackId, LocalTrackOutgoingEvent<RL>), | ||
ConfigEgressBitrate { current: u32, desired: u32 }, | ||
LimitIngressBitrate(u32), | ||
Rpc(RE), | ||
} | ||
``` | ||
|
||
The event from Transport is defined as bellow: | ||
|
||
```Rust | ||
#[derive(PartialEq, Eq, Debug)] | ||
pub enum TransportIncomingEvent<RE, RR, RL> { | ||
State(TransportStateEvent), | ||
Continue, | ||
RemoteTrackAdded(TrackName, TrackId, TrackMeta), | ||
RemoteTrackEvent(TrackId, RemoteTrackIncomingEvent<RR>), | ||
RemoteTrackRemoved(TrackName, TrackId), | ||
LocalTrackAdded(TrackName, TrackId, TrackMeta), | ||
LocalTrackEvent(TrackId, LocalTrackIncomingEvent<RL>), | ||
LocalTrackRemoved(TrackName, TrackId), | ||
Rpc(RE), | ||
Stats(TransportStats), | ||
EgressBitrateEstimate(u64), | ||
} | ||
``` | ||
|
||
### Endpoint | ||
|
||
The Endpoint is the core logic of atm0s-media-server. It manages how to process events from the transport and how to communicate with the cluster. The Endpoint is designed with a SAN IO style, where all internal logic is independent of I/O and processed without async/await. It is implemented inside the `packages/endpoint` crate and can be defined as follows: | ||
|
||
![Endpoint](../imgs/architecture/endpoint.excalidraw.png) | ||
|
||
### Task scheduler | ||
|
||
To support a large number of peers, we will have multiple tasks. However, for simplicity, we will only have one task for each endpoint. These tasks are created using `async_std::task::spawn`. The relationship between each task is illustrated in the diagram below: | ||
|
||
![Tasks](../imgs/architecture/tasks.excalidraw.png) |
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,11 @@ | ||
# Features | ||
|
||
In this document, we will explore the implementation of key features of atm0s-media-server. Currently, we have the following features: | ||
|
||
| Feature | Status | | ||
|---------------------------------|--------| | ||
| [Audio-mixer](./audio-mixer.md) | Alpha | | ||
| [Auth/Multi tenancy](./authentication-and-multi-tenancy.md) | Alpha | | ||
| [Simulcast/SVC](./simulcast-svc.md) | Alpha | | ||
| [Recording](./recording.md) | TODO | | ||
| [Cluster](./cluster.md) | Alpha | |
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,57 @@ | ||
# Audio Mixer | ||
|
||
![Audio Mixer](../../imgs/features/audio-mixer.excalidraw.png) | ||
|
||
For additional information on our audio mixer implementation, please consult the [Audio Mixer](/user-guide/features/audio-mixer.md) section in the User Guide documentation. | ||
|
||
We have divided the fundamental virtual mix-minus logic into a distinct module known as the 'audio-mixer' module. This module operates independently and is adaptable for use in any other application. | ||
|
||
To facilitate integration with an endpoint, we have developed middleware designed to seamlessly integrate with the endpoint's pipeline. | ||
|
||
## Abstract Design | ||
|
||
We have developed a new module called "audio-mixer," which receives all audio streams from other peers and selects the loudest audio track to send to the client. For flexibility, we offer two modes: | ||
|
||
- Mixing all audio streams. | ||
- Mixing only the most interesting audio streams. | ||
|
||
The number of output tracks can be configured. | ||
|
||
## Implementation Details | ||
|
||
The core audio-mixer session will involve both input and output interactions: | ||
|
||
**Input types:** | ||
|
||
- `Source added` (source ID) | ||
- `Source pkt` (source ID, audio level, audio data) | ||
- `Source removed` (source ID) | ||
|
||
**Output types:** | ||
|
||
- `Output Pin` (output ID, source ID) | ||
- `Output pkt` (output ID, audio level, audio data) | ||
- `Output UnPin` (Output ID, source ID) | ||
|
||
Each time a source is added, the core checks if there is a free output track. If available, it pins that output track to the respective source. When a source is removed, the core unpins that source from the output track. | ||
|
||
Upon receiving a new audio packet, the core updates the audio level of the corresponding source. If the source wasn't pinned, the core checks if there is a pinned output track with a lower audio level than the source beyond a certain threshold. If found, the core unpins that output track and pins the source to that output track. | ||
|
||
At periodic intervals, the core clears the audio level of all timed-out sources, which haven't received any audio packet within a specified time period. | ||
|
||
## Potential Impact and Risks | ||
|
||
This method relies on the assumption that the audio level of a source does not change significantly in a short period. If the audio level of a source undergoes substantial changes quickly, the core will unpin that source from the output track and pin it to another source, potentially resulting in an audio glitch. | ||
|
||
Another challenge with this method is its dependency on receiving accurate audio level information from the source. If the source fails to send the audio level or provides incorrect information, the core may not function as intended. | ||
|
||
## Future improvements | ||
|
||
To optimize bandwidth usage, we employ a strategy of dividing audio stream data into multiple levels: stream metadata (which includes audio level) and actual audio data. When selecting a source for mixing, we subscribe only to the audio data level, minimizing the data transferred and reducing overall bandwidth consumption. | ||
|
||
Additionally, we can have a normalization step to address the issue of rapid changes in audio levels. This step helps ensure smoother transitions and prevents abrupt fluctuations in audio, enhancing the overall stability of the system. | ||
|
||
## Open Questions | ||
|
||
- Optimizing for Many Sources in a Room: Strategies for efficiently handling scenarios where the room contains numerous sources. | ||
- Handling Rapid Audio Level Changes: Techniques to ensure smooth transitions and prevent disruptions when the audio level of a source changes rapidly. |
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,16 @@ | ||
# Authentication | ||
We can extend with custom authentication by implementing the `SessionTokenSigner` trait. | ||
|
||
```rust | ||
pub trait SessionTokenSigner { | ||
fn sign_media_session(&self, token: &MediaSessionToken) -> String; | ||
fn sign_conn_id(&self, conn_id: &MediaConnId) -> String; | ||
} | ||
|
||
pub trait SessionTokenVerifier { | ||
fn verify_media_session(&self, token: &str) -> Option<MediaSessionToken>; | ||
fn verify_conn_id(&self, token: &str) -> Option<MediaConnId>; | ||
} | ||
``` | ||
|
||
We have a simple static secret signer and verifier in the [`cluster` crate](https://github.com/8xFF/atm0s-media-server/blob/master/packages/cluster/src/implement/secure/jwt_static.rs). |
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,21 @@ | ||
# Cluster | ||
|
||
Cluster feature is implemented following [RFC-0003-media-global-cluster](https://github.com/8xFF/rfcs/pull/3). | ||
More info can be found in user guide [here](../../user-guide/features/cluster.md). | ||
|
||
## Implementation details | ||
|
||
The cluster module is implemented in the `cluster` package. It is responsible for managing the cluster of media servers. | ||
|
||
Each time new peer joined to media-server, cluster will create a new `ClusterEndpoint` to attach to the peer. | ||
|
||
The `ClusterEndpoint` is responsible for managing pubsub channels, and also room information for the peer. | ||
We use event based communication to interact with `ClusterEndpoint`: | ||
|
||
```rust | ||
#[async_trait::async_trait] | ||
pub trait ClusterEndpoint: Send + Sync { | ||
fn on_event(&mut self, event: ClusterEndpointOutgoingEvent) -> Result<(), ClusterEndpointError>; | ||
async fn recv(&mut self) -> Result<ClusterEndpointIncomingEvent, ClusterEndpointError>; | ||
} | ||
``` |
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 @@ | ||
# Recording | ||
|
||
TODO: write about recording queue and compose utils |
Oops, something went wrong.