webrtc: janus: add 'janus-state' property to the sink

This property can be used by applications to track the state of the
signaller, especially to know when the stream is up.

Fix #510

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/-/merge_requests/1505>
This commit is contained in:
Guillaume Desmottes 2024-03-19 16:41:09 +01:00
parent d8b9a7a486
commit 027eead86d
4 changed files with 166 additions and 10 deletions

View file

@ -10126,6 +10126,18 @@
} }
}, },
"properties": { "properties": {
"janus-state": {
"blurb": "The current state of the signaller",
"conditionally-available": false,
"construct": false,
"construct-only": false,
"controllable": false,
"default": "initialized (0)",
"mutable": "null",
"readable": true,
"type": "GstJanusVRWebRTCJanusState",
"writable": false
},
"use-string-ids": { "use-string-ids": {
"blurb": "Use strings instead of u64 for Janus IDs, see strings_ids config option in janus.plugin.videoroom.jcfg", "blurb": "Use strings instead of u64 for Janus IDs, see strings_ids config option in janus.plugin.videoroom.jcfg",
"conditionally-available": false, "conditionally-available": false,
@ -11011,6 +11023,41 @@
} }
} }
}, },
"GstJanusVRWebRTCJanusState": {
"kind": "enum",
"values": [
{
"desc": "Initialized",
"name": "initialized",
"value": "0"
},
{
"desc": "SessionCreated",
"name": "session-created",
"value": "1"
},
{
"desc": "VideoroomAttached",
"name": "videoroom-attached",
"value": "2"
},
{
"desc": "RoomJoined",
"name": "room-joined",
"value": "3"
},
{
"desc": "Negotiating",
"name": "negotiating",
"value": "4"
},
{
"desc": "WebrtcUp",
"name": "webrtc-up",
"value": "5"
}
]
},
"GstLiveKitWebRTCSrcPad": { "GstLiveKitWebRTCSrcPad": {
"hierarchy": [ "hierarchy": [
"GstLiveKitWebRTCSrcPad", "GstLiveKitWebRTCSrcPad",

View file

@ -1,7 +1,10 @@
// SPDX-License-Identifier: MPL-2.0 // SPDX-License-Identifier: MPL-2.0
use crate::signaller::{Signallable, SignallableImpl}; use crate::{
use crate::RUNTIME; signaller::{Signallable, SignallableImpl},
webrtcsink::JanusVRSignallerState,
RUNTIME,
};
use anyhow::{anyhow, Error}; use anyhow::{anyhow, Error};
use async_tungstenite::tungstenite; use async_tungstenite::tungstenite;
@ -439,6 +442,9 @@ impl Signaller {
match reply { match reply {
JsonReply::WebRTCUp => { JsonReply::WebRTCUp => {
gst::trace!(CAT, imp = self, "WebRTC streaming is working!"); gst::trace!(CAT, imp = self, "WebRTC streaming is working!");
self.obj()
.emit_by_name::<()>("state-updated", &[&JanusVRSignallerState::WebrtcUp]);
} }
JsonReply::Success(success) => { JsonReply::Success(success) => {
if let Some(data) = success.data { if let Some(data) = success.data {
@ -491,6 +497,12 @@ impl Signaller {
"Joined room {:?} successfully", "Joined room {:?} successfully",
joined.room joined.room
); );
self.obj().emit_by_name::<()>(
"state-updated",
&[&JanusVRSignallerState::RoomJoined],
);
self.session_requested(); self.session_requested();
} }
VideoRoomData::Event(room_event) => { VideoRoomData::Event(room_event) => {
@ -587,11 +599,23 @@ impl Signaller {
} }
fn set_session_id(&self, session_id: u64) { fn set_session_id(&self, session_id: u64) {
self.state.lock().unwrap().session_id = Some(session_id); {
let mut state = self.state.lock().unwrap();
state.session_id = Some(session_id);
}
self.obj()
.emit_by_name::<()>("state-updated", &[&JanusVRSignallerState::SessionCreated]);
} }
fn set_handle_id(&self, handle_id: u64) { fn set_handle_id(&self, handle_id: u64) {
self.state.lock().unwrap().handle_id = Some(handle_id); {
let mut state = self.state.lock().unwrap();
state.handle_id = Some(handle_id);
}
self.obj().emit_by_name::<()>(
"state-updated",
&[&JanusVRSignallerState::VideoroomAttached],
);
} }
fn attach_plugin(&self) { fn attach_plugin(&self) {
@ -698,6 +722,9 @@ impl Signaller {
return; return;
} }
self.obj()
.emit_by_name::<()>("state-updated", &[&JanusVRSignallerState::Negotiating]);
( (
state.transaction_id.clone().unwrap(), state.transaction_id.clone().unwrap(),
state.session_id.unwrap(), state.session_id.unwrap(),
@ -867,7 +894,26 @@ impl ObjectSubclass for Signaller {
} }
#[glib::derived_properties] #[glib::derived_properties]
impl ObjectImpl for Signaller {} impl ObjectImpl for Signaller {
fn signals() -> &'static [glib::subclass::Signal] {
static SIGNALS: Lazy<Vec<glib::subclass::Signal>> = Lazy::new(|| {
vec![
/**
* GstJanusVRWebRTCSignaller::state-updated:
* @state: the new state.
*
* This signal is emitted when the Janus state of the signaller is updated.
*/
glib::subclass::Signal::builder("state-updated")
.param_types([JanusVRSignallerState::static_type()])
.build(),
]
});
SIGNALS.as_ref()
}
}
// below are Signaller subclasses implementing properties whose type depends of the Janus ID format (u64 or string). // below are Signaller subclasses implementing properties whose type depends of the Janus ID format (u64 or string).
// User can control which signaller is used by setting the `use-string-ids` construct property on `janusvrwebrtcsink`. // User can control which signaller is used by setting the `use-string-ids` construct property on `janusvrwebrtcsink`.

View file

@ -5918,13 +5918,21 @@ pub(super) mod livekit {
#[cfg(feature = "janus")] #[cfg(feature = "janus")]
pub(super) mod janus { pub(super) mod janus {
use super::*; use super::*;
use crate::janusvr_signaller::{JanusVRSignallerStr, JanusVRSignallerU64}; use crate::{
janusvr_signaller::{JanusVRSignallerStr, JanusVRSignallerU64},
webrtcsink::JanusVRSignallerState,
};
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default)]
struct JanusSettings { struct JanusSettings {
use_string_ids: bool, use_string_ids: bool,
} }
#[derive(Debug, Default)]
struct JanusState {
janus_state: JanusVRSignallerState,
}
#[derive(Default, glib::Properties)] #[derive(Default, glib::Properties)]
#[properties(wrapper_type = crate::webrtcsink::JanusVRWebRTCSink)] #[properties(wrapper_type = crate::webrtcsink::JanusVRWebRTCSink)]
pub struct JanusVRWebRTCSink { pub struct JanusVRWebRTCSink {
@ -5940,6 +5948,21 @@ pub(super) mod janus {
*/ */
#[property(name="use-string-ids", get, construct_only, type = bool, member = use_string_ids, blurb = "Use strings instead of u64 for Janus IDs, see strings_ids config option in janus.plugin.videoroom.jcfg")] #[property(name="use-string-ids", get, construct_only, type = bool, member = use_string_ids, blurb = "Use strings instead of u64 for Janus IDs, see strings_ids config option in janus.plugin.videoroom.jcfg")]
settings: Mutex<JanusSettings>, settings: Mutex<JanusSettings>,
/**
* GstJanusVRWebRTCSink:janus-state:
*
* The current state of the signaller.
* Since: plugins-rs-0.14.0
*/
#[property(
name = "janus-state",
// FIXME: can't use `member =` with enums: https://github.com/gtk-rs/gtk-rs-core/issues/1338
get = |self_: &Self| self_.state.lock().unwrap().janus_state,
type = JanusVRSignallerState,
blurb = "The current state of the signaller",
builder(JanusVRSignallerState::Initialized)
)]
state: Mutex<JanusState>,
} }
#[glib::derived_properties] #[glib::derived_properties]
@ -5951,11 +5974,28 @@ pub(super) mod janus {
.upcast_ref::<crate::webrtcsink::BaseWebRTCSink>() .upcast_ref::<crate::webrtcsink::BaseWebRTCSink>()
.imp(); .imp();
if settings.use_string_ids { let signaller: Signallable = if settings.use_string_ids {
let _ = ws.set_signaller(JanusVRSignallerStr::default().upcast()); JanusVRSignallerStr::default().upcast()
} else { } else {
let _ = ws.set_signaller(JanusVRSignallerU64::default().upcast()); JanusVRSignallerU64::default().upcast()
} };
let self_weak = self.downgrade();
signaller.connect("state-updated", false, move |args| {
let self_ = self_weak.upgrade()?;
let janus_state = args[1].get::<JanusVRSignallerState>().unwrap();
{
let mut state = self_.state.lock().unwrap();
state.janus_state = janus_state;
}
self_.obj().notify("janus-state");
None
});
let _ = ws.set_signaller(signaller);
} }
} }

View file

@ -134,6 +134,26 @@ enum WebRTCSinkMitigationMode {
DOWNSAMPLED = 0b00000010, DOWNSAMPLED = 0b00000010,
} }
#[derive(Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy, glib::Enum)]
#[repr(u32)]
#[enum_type(name = "GstJanusVRWebRTCJanusState")]
/// State of the Janus Signaller.
pub enum JanusVRSignallerState {
#[default]
/// Initial state when the signaller is created.
Initialized,
/// The Janus session has been created.
SessionCreated,
/// The session has been attached to the videoroom plugin.
VideoroomAttached,
/// The room has been joined.
RoomJoined,
/// The WebRTC stream is being negotiated.
Negotiating,
/// The WebRTC stream is streaming to Janus.
WebrtcUp,
}
pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> { pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> {
WebRTCSinkPad::static_type().mark_as_plugin_api(gst::PluginAPIFlags::empty()); WebRTCSinkPad::static_type().mark_as_plugin_api(gst::PluginAPIFlags::empty());
BaseWebRTCSink::static_type().mark_as_plugin_api(gst::PluginAPIFlags::empty()); BaseWebRTCSink::static_type().mark_as_plugin_api(gst::PluginAPIFlags::empty());
@ -230,5 +250,8 @@ pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> {
JanusVRWebRTCSink::static_type(), JanusVRWebRTCSink::static_type(),
)?; )?;
#[cfg(feature = "janus")]
JanusVRSignallerState::static_type().mark_as_plugin_api(gst::PluginAPIFlags::empty());
Ok(()) Ok(())
} }