-
Notifications
You must be signed in to change notification settings - Fork 195
Conversation
sendrecv/gst-rust/src/main.rs
Outdated
} | ||
|
||
fn sdp_message_as_text(offer: gstreamer_webrtc::WebRTCSessionDescription) -> Option<String> { | ||
unsafe { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sdroege/gstreamer-rs#108 (comment) for why this is necessary currently. We should fix that before merging this PR :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've added those now here sdroege/gstreamer-rs@85ca3b9
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lovely timing, as mine was incorrect: maxmcd/gstreamer-rs@dd0918b
:)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A mutable borrow is not needed here as all these are immutable fields after all, and from_glib_none
is needed here because we don't take ownership of the field (otherwise we would steal it from the struct). Ideally we would just borrow it, but there's no borrowing mechanism in glib-rs
at this point that could be used for this (and generally borrowing from GLib types is dangerous by default except for some special cases), so we have to copy here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let me know if my version works and if there are any other problems :) And thanks again for working on this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Your version works perfectly. Replaced the unsafe call.
sendrecv/gst-rust/src/main.rs
Outdated
return AppState::PeerConnecting; | ||
} | ||
|
||
fn register_with_server(app_state: &Arc<AtomicUsize>, out: &ws::Sender) -> AppState { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might be nicer to move the app state into a struct for extensibility later instead of directly passing around that single integer everywhere (and maybe wrap that struct into an Rc<Mutex<_>>
)
sendrecv/gst-rust/src/main.rs
Outdated
webrtc | ||
.emit( | ||
"set-local-description", | ||
&[&offer.to_value(), &promise.to_value()], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm what's the point of the promise if it's not used anywhere afterwards?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was mostly parroting the original c implementation: webrtc-sendrecv.c#L252-L255
It does seem though that no promise is allowed: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-bad/html/gst-plugins-bad-plugins-webrtcbin.html#GstWebRTCBin-set-local-description
On that point, I couldn't figure out how to pass null in a situation like this. Is there some stand-in in the library?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should be able to pass &None::<gst::Promise>
here
sendrecv/gst-rust/src/main.rs
Outdated
}); | ||
let options = gst::Structure::new_empty("options"); | ||
webrtc_clone | ||
.emit("create-offer", &[&options.to_value(), &promise.to_value()]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The to_value()
in all the emit
calls should not be needed, only the &
sendrecv/gst-rust/src/main.rs
Outdated
sink.sync_state_with_parent().unwrap(); | ||
gst::Element::link_many(&[&q, &conv, &resample, &sink]).unwrap(); | ||
} else { | ||
pipe.clone() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could move this dynamic_cast
outside the if
and have it only once then, storing the bin
in a local variable
sendrecv/gst-rust/src/main.rs
Outdated
queue ! | ||
application/x-rtp,media=audio,encoding-name=OPUS,payload=97 ! sendrecv. | ||
", | ||
).unwrap(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Explicitly creating the elements would seem nicer than string programming, but I guess it's fine :)
sendrecv/gst-rust/src/main.rs
Outdated
.unwrap(); | ||
|
||
let ret = pipe.set_state(gst::State::Playing); | ||
assert_ne!(ret, gst::StateChangeReturn::Failure); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could also do into_result().unwrap()
on the return value
sendrecv/gst-rust/src/main.rs
Outdated
x if x == AppState::ServerRegistering as usize => AppState::ServerRegisteringError, | ||
x if x == AppState::PeerConnecting as usize => AppState::PeerConnectionError, | ||
x if x == AppState::PeerConnected as usize => AppState::PeerCallError, | ||
x if x == AppState::PeerCallNegotiating as usize => AppState::PeerCallError, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See above, if you make the app struct a Rc<Mutex<_>>
then you could store the state directly as an enum and match properly on it, exhaustively
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we get away with Rc
with the promises? I assumed that would behave the same way as spawning a new thread and a sync::Arc
would be needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, Arc
is needed, sorry :)
sendrecv/gst-rust/src/main.rs
Outdated
.unwrap(); | ||
self.update_state(AppState::PeerCallStarted); | ||
} | ||
if json_msg.get("ice").is_some() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we could use serde-json
here for directly converting between a Rust struct and JSON?
Looks quite nice, thanks :) I have no opinions about the Docker stuff and how the webrtc library is used is for someone else to review. From the Rust side, in addition to the comments above it might be nice to do proper error handling in various places instead of just unwrapping/expecting |
Thanks so much for the detailed feedback @sdroege! |
I'm done with edits for the moment. The mutex stuff is a little messy in places and it's still quite panicky. Had a difficult time consolidating the async nature of the code with proper error handling. Also, cleaned up docker and added peer-id/server flag support to gain parity with the c version. |
So this is working and basically equivalent with the C version now, and could get another full review? |
signalling/Dockerfile
Outdated
RUN sed -i 's/sslctx.load_cert_chain(chain_pem, keyfile=key_pem)/pass/g' \ | ||
./simple-server.py | ||
RUN sed -i 's/ssl=sslctx,//g' \ | ||
./simple-server.py |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe you want to add an option to simple-server.py
to not use ssl instead? If you set ssl=None
when calling serve()
, it's the same as not passing an sslctx.
sendrecv/gst/Dockerfile
Outdated
RUN sed -i 's/wss:\/\/webrtc.nirbheek.in:8443/ws:\/\/signalling:8443/g' \ | ||
/opt/webrtc-sendrecv.c | ||
RUN sed -i 's/strict_ssl = TRUE/strict_ssl = FALSE/g' \ | ||
/opt/webrtc-sendrecv.c |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here, too. I think it would be generally useful for people (while running local servers) if we do that.
@sdroege yes absolutely |
That's fine. The alternative would be something like this https://github.com/sdroege/gstreamer-rs/blob/f4d57a66522183d4927b47af422e8f321182111f/examples/src/bin/playbin.rs#L27-L35 (there's basically the same API for enums) |
For how to integrate |
You could basically have another thread that does the ws stuff, and the main thread runs the The other way around, calling things from elsewhere into the ws thread/event loop does not seem to be possible from a short look over the API. But maybe you also don't need that? Otherwise there are some tokio based websocket libraries that might be possible to use, but that complicates everything quite a lot :) |
Not sure how I'm missing this. How would I create a message for the bus and what MessageView type would you recommend using for posting websocket messages to the bus? |
You would use See https://github.com/sdroege/gstreamer-rs/blob/db3fe694154c697afdaf3efb6ec65332546942e0/tutorials/src/bin/basic-tutorial-5.rs#L264-L267 for an example involving an element, you can simply do You can catch the message on the bus like https://github.com/sdroege/gstreamer-rs/blob/db3fe694154c697afdaf3efb6ec65332546942e0/tutorials/src/bin/basic-tutorial-5.rs#L241-L244, for example. |
Rewrote the script with rust-websocket and have better error handling with no panics and (I think) much less blocking. Much happier with where this is now, doesn't seem to be fighting against itself as much. The error handling within the callback closures is a little hacky, and looking at some of the gstreamer-rs examples my bus/loop setup could be a little cleaner. Ready for another round of feedback/review. |
sendrecv/gst-rust/src/main.rs
Outdated
MessageView::Element(_) => {} | ||
MessageView::Tag(_) => {} | ||
MessageView::NewClock(_) => {} | ||
MessageView::Warning(warning) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You also want to handle Error
messages, but all the others above are not really needed :) An Error
message is always fatal
sendrecv/gst-rust/src/main.rs
Outdated
println!("Got error message! {}", msg); | ||
return self.handle_error(); | ||
} | ||
let json_msg: JsonMsg = serde_json::from_str(&msg).unwrap(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of unwrapping, failing to deserialize the JSON should probably just be an error like other errors
Looks very good, apart from the minor things above I didn't see anything wrong while shortly looking over it. Will do another proper review in the next days but this looks like it's done. Much better with the other websocket library, and the need for 2 threads instead of 1 for that can probably be refactored later (e.g. by using the tokio-based async API on it). But that's for later |
sendrecv/gst-rust/src/main.rs
Outdated
} | ||
} | ||
|
||
fn app_state_lt(&self, state: AppState, error_msg: &'static str) -> bool { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe this could mirror the Ord
trait a bit more and be called app_state_cmp
and return a std::cmp::Ordering
. But details. Just lt
seems a bit short :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me, thanks a lot for your work :)
All merged now :) |
Nice! Thanks so much for your patience and feedback @sdroege |
@maxmcd , nice work, as far as I can tell this only works when the signalling server is launched with |
@MathieuDuponchelle correct, at least that's what I used when I worked on this, I'm sure you could get ssl working again. This is somewhat documented here: https://github.com/centricular/gstwebrtc-demos/blob/master/signalling/Dockerfile The priority was getting a quick docker demo working so would check the dockerfiles and docker-compose file for quick reference on how to run. |
This will need some refactoring to do all the ws communication on a single thread via tokio/futures instead of splitting the socket in its sender and receiver side |
@maxmcd would you be interested in working on this? In any case, we should probably open a new issue for this :) |
Yep, would be happy to. |
Great, let us know how it goes and if you need help or want someone else to take over |
There's more work to be done here (No flag support, no cleanup, a few shortcuts) but the rust script seems fully functional. Wanted to inquire about two things:
Can complete the rust code and clean up/document docker-compose upon confirmation of #2.