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": {
"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": {
"blurb": "Use strings instead of u64 for Janus IDs, see strings_ids config option in janus.plugin.videoroom.jcfg",
"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": {
"hierarchy": [
"GstLiveKitWebRTCSrcPad",

View file

@ -1,7 +1,10 @@
// SPDX-License-Identifier: MPL-2.0
use crate::signaller::{Signallable, SignallableImpl};
use crate::RUNTIME;
use crate::{
signaller::{Signallable, SignallableImpl},
webrtcsink::JanusVRSignallerState,
RUNTIME,
};
use anyhow::{anyhow, Error};
use async_tungstenite::tungstenite;
@ -439,6 +442,9 @@ impl Signaller {
match reply {
JsonReply::WebRTCUp => {
gst::trace!(CAT, imp = self, "WebRTC streaming is working!");
self.obj()
.emit_by_name::<()>("state-updated", &[&JanusVRSignallerState::WebrtcUp]);
}
JsonReply::Success(success) => {
if let Some(data) = success.data {
@ -491,6 +497,12 @@ impl Signaller {
"Joined room {:?} successfully",
joined.room
);
self.obj().emit_by_name::<()>(
"state-updated",
&[&JanusVRSignallerState::RoomJoined],
);
self.session_requested();
}
VideoRoomData::Event(room_event) => {
@ -587,11 +599,23 @@ impl Signaller {
}
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) {
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) {
@ -698,6 +722,9 @@ impl Signaller {
return;
}
self.obj()
.emit_by_name::<()>("state-updated", &[&JanusVRSignallerState::Negotiating]);
(
state.transaction_id.clone().unwrap(),
state.session_id.unwrap(),
@ -867,7 +894,26 @@ impl ObjectSubclass for Signaller {
}
#[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).
// 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")]
pub(super) mod janus {
use super::*;
use crate::janusvr_signaller::{JanusVRSignallerStr, JanusVRSignallerU64};
use crate::{
janusvr_signaller::{JanusVRSignallerStr, JanusVRSignallerU64},
webrtcsink::JanusVRSignallerState,
};
#[derive(Debug, Clone, Default)]
struct JanusSettings {
use_string_ids: bool,
}
#[derive(Debug, Default)]
struct JanusState {
janus_state: JanusVRSignallerState,
}
#[derive(Default, glib::Properties)]
#[properties(wrapper_type = crate::webrtcsink::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")]
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]
@ -5951,11 +5974,28 @@ pub(super) mod janus {
.upcast_ref::<crate::webrtcsink::BaseWebRTCSink>()
.imp();
if settings.use_string_ids {
let _ = ws.set_signaller(JanusVRSignallerStr::default().upcast());
let signaller: Signallable = if settings.use_string_ids {
JanusVRSignallerStr::default().upcast()
} 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,
}
#[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> {
WebRTCSinkPad::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(),
)?;
#[cfg(feature = "janus")]
JanusVRSignallerState::static_type().mark_as_plugin_api(gst::PluginAPIFlags::empty());
Ok(())
}