-
-
Notifications
You must be signed in to change notification settings - Fork 398
Migrate to async traits for handling event callbacks #522
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
As I've been working on this, I realized that the each fn in the trait has to return |
I was looking into something similar the last day or two. Did anything come of your work here? I like the trait approach, here, actually. I have two other alternatives.
This is the simplest option, and can actually be implemented as a wrapper around the peer. I've done this for the APIs I use in my project. pub struct AsyncRTCPeer {
pub peer: RTCPeerConnection,
}
pub fn on_track<X, Fut>(&self, mut handler: X)
where
X: FnMut(Arc<TrackRemote>, Arc<RTCRtpReceiver>, Arc<RTCRtpTransceiver>) -> Fut
+ Send
+ Sync
+ 'static,
Fut: Future<Output = ()> + Send + 'static,
{
self.on_track(Box::new(move |a, b, c| {
let fut = handler(a, b, c).instrument(info_span!("Peer"));
Box::pin(async move { fut.await })
}));
}
// Usage:
peer.on_track(async |_track, _, _| {
info!("New track added: {:?}", ss.track_id);
}); This is fairly clean, but has the major drawback that every event callback must be
Currently webrtc-rs owns and pumps all of the futures that handle events. Most frameworks like Axum let the user handle this responsibility. ie: let app = Router::new().route("/", get(handler));
let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
.await
.unwrap();
axum::serve(listener, app).await.unwrap(); It might be a nicer interface to allow the peer to be managed and pumped by the user, which would allow for much more control over the lifetime of the peer, general execution, etc. This might look something like: let peer = api.peer()
.on_track(async |track, _, _| { info!("Got a track!"); })
.on_connection_changed(async |track, _, _| { info!("Connection changed."); })
.build();
let result: Result((), PeerError) = peer.run().await; Crucially, I believe this would allow removing the let trackNum = AtomicI8::new();
let peer = api.peer()
.on_track(async |track, _, _| { info!("Got a track! [{}]", &trackNum.fetch_add(1, SeqCst)); })
.build();
let result: Result((), PeerError) = peer.run().await; Axum uses a But this would be a much more complex interface to design, and I'm not an expert at Rust async. |
With the stabilization of async fn in trait as of 1.75, I think it would be more ergonomic to have a single state to handle all events which implements a trait rather than having to register each callback individually, and would also reduce heap allocation. Default implementations for the trait can also allow the same functionality as before, as they all return
impl Future<Output = ()>
.Below is a basic example of what I'm suggesting (keep in mind I have not tested any of the code below):
changing the implementation to something like:
and would change the play-from-disk-h264 example to something like:
I'll follow this up with a pr, but with the scope of how much needs to be changed it might take awhile. Also, as it is a very new feature, I wanted to see if there would be any discussion.
The text was updated successfully, but these errors were encountered: