17 releases (4 breaking)

new 0.4.0 May 6, 2025
0.3.5 Apr 29, 2025
0.3.1 Mar 27, 2025
0.3.0 Feb 27, 2025
0.0.5 Nov 18, 2024

#61 in Video

Download history 9/week @ 2025-01-15 118/week @ 2025-01-22 122/week @ 2025-01-29 12/week @ 2025-02-05 3/week @ 2025-02-19 167/week @ 2025-02-26 2/week @ 2025-03-05 131/week @ 2025-03-26 6/week @ 2025-04-02 351/week @ 2025-04-09 81/week @ 2025-04-16 67/week @ 2025-04-23 147/week @ 2025-04-30

647 downloads per month

Apache-2.0

160KB
3.5K SLoC

Rheomesh

Build docs.rs Crates.io GitHub

Rheomesh is a WebRTC SFU library that provides a simple API for building real-time communication applications. This provides an SDK to help you build a WebRTC SFU server. Here is an example SFU server for video streaming.

Install

Add your Cargo.toml like this:

[dependencies]
rheomesh = { version = "0" }

Usage

Create router and transports

First of all, please create a worker and router. Worker accomodates multiple routers. You only need to launch one worker per server. Router accommodates multiple transports and they can communicate with each other. That means transports belonging to the same Router can send/receive their media. Router is like a meeting room.

use rheomesh::worker::Worker;
use rheomesh::config::{WorkerConfig};

//...

async fn new() {
  let worker = Worker::new(WorkerConfig::default()).await.unwrap();
  let config = MediaConfig::default();
  let mut w = worker.lock().await;
  let router = w.new_router(config);
}

Next, please create publish and subscribe transports.

use rheomesh::config::WebRTCTransportConfig

async fn new() {
  //...
  let mut config = WebRTCTransportConfig::default();
  config.configuration.ice_servers = vec![RTCIceServer {
    urls: vec!["stun:stun.l.google.com:19302".to_owned()],
    ..Default::default()
  }];
  let publish_transport = router.lock().await.create_publish_transport(config.clone()).await;
  let subscribe_transport = router.lock().await.create_subscribe_transport(config.clone()).await;
}

Handle publish events

Bind on_ice_candidate callback

publish_transport
  .on_ice_candidate(Box::new(move |candidate| {
      let init = candidate.to_json().expect("failed to parse candidate");
      // Send `init` message to client. The client have to call `addIceCandidate` method with this parameter.
  }))
  .await;

Please send init to client. The corresponding client-side handler is here.

Handle RTCIceCandidateInit

On the other hand, you will receive RTCIceCandidateInit message from client, here.

let _ = publish_transport
  .add_ice_candidate(candidate)
  .await
  .expect("failed to add ICE candidate");

Handle offer message

Then, server will receive offer from client, the corresponding client-side handler is here.

let answer = publish_transport
  .get_answer(offer)
  .await
  .expect("failed to connect publish_transport");
// Send `answer` message to client. The client have to call `setAnswer` method.

Please send answer to client. The corresponding client-side handler is here.

Publish

Finally, please handle publish event with publisher_id. You can obtain publisher_id from publisher object in client-side.

let publisher = publish_transport.publish(publisher_id).await;

Handle subscribe events

Bind on_ice_candidate and on_negotiation_needed callback

subscribe_transport
  .on_ice_candidate(Box::new(move |candidate| {
      let init = candidate.to_json().expect("failed to parse candidate");
      // Send `init` message to client. The client have to call `addIceCandidate` method with this parameter.
  }))
    .await;
subscribe_transport
  .on_negotiation_needed(Box::new(move |offer| {
    // Send `offer` message to client. The client have to call `setOffer` method.
  }))

Please send init to client. The corresponding client-side handler is here.

Handle RTCIceCandidateInit

On the other hand, you will receive RTCIceCandidateInit message from client, here.

let _ = subscribe_transport
  .add_ice_candidate(candidate)
  .await
  .expect("failed to add ICE candidate");

Subscribe

Then, please call subscribe method.

let (subscriber, offer) = subscribe_transport
  .subscribe(track_id)
  .await
  .expect("failed to connect subscribe_transport");
// Send `offer` message to client. The client have to call `setOffer` method.

Please send offer message to client. The corresponding client-side handler is here.

Handle answer message

Finally, server will receive answer from client, the corresponding client-side handler is here.

let _ = subscribe_transport
  .set_answer(answer)
  .await
  .expect("failed to set answer");

Dependencies

~35–48MB
~1M SLoC