added TURN support
This commit is contained in:
parent
bed8d156dc
commit
7190086673
|
@ -116,3 +116,7 @@ The dependency `gstreamer` is licensed under the GNU Lesser General Public Licen
|
||||||
Any kinds of contributions are welcome as a pull request.
|
Any kinds of contributions are welcome as a pull request.
|
||||||
|
|
||||||
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in these crates by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
|
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in these crates by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
|
||||||
|
|
||||||
|
## Acknowledgements
|
||||||
|
|
||||||
|
`gst-meet` development is sponsored by [AVStack](https://www.avstack.io/). We provide globally-distributed, scalable, managed Jitsi Meet backends.
|
|
@ -21,12 +21,7 @@ use xmpp_parsers::{
|
||||||
BareJid, Element, FullJid, Jid,
|
BareJid, Element, FullJid, Jid,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{jingle::JingleSession, source::MediaType, stanza_filter::StanzaFilter, xmpp};
|
||||||
jingle::JingleSession,
|
|
||||||
source::MediaType,
|
|
||||||
stanza_filter::StanzaFilter,
|
|
||||||
xmpp,
|
|
||||||
};
|
|
||||||
|
|
||||||
static DISCO_INFO: Lazy<DiscoInfoResult> = Lazy::new(|| DiscoInfoResult {
|
static DISCO_INFO: Lazy<DiscoInfoResult> = Lazy::new(|| DiscoInfoResult {
|
||||||
node: None,
|
node: None,
|
||||||
|
@ -36,7 +31,6 @@ static DISCO_INFO: Lazy<DiscoInfoResult> = Lazy::new(|| DiscoInfoResult {
|
||||||
Feature::new(ns::JINGLE_RTP_VIDEO),
|
Feature::new(ns::JINGLE_RTP_VIDEO),
|
||||||
Feature::new(ns::JINGLE_ICE_UDP),
|
Feature::new(ns::JINGLE_ICE_UDP),
|
||||||
Feature::new(ns::JINGLE_DTLS),
|
Feature::new(ns::JINGLE_DTLS),
|
||||||
|
|
||||||
// not supported yet: rtx
|
// not supported yet: rtx
|
||||||
// Feature::new("urn:ietf:rfc:4588"),
|
// Feature::new("urn:ietf:rfc:4588"),
|
||||||
|
|
||||||
|
|
|
@ -280,7 +280,9 @@ impl JitsiConnection {
|
||||||
}
|
}
|
||||||
|
|
||||||
let iq = Iq::from_get(generate_id(), xmpp::extdisco::ServicesQuery {})
|
let iq = Iq::from_get(generate_id(), xmpp::extdisco::ServicesQuery {})
|
||||||
.with_from(Jid::Full(locked_inner.jid.as_ref().context("missing jid")?.clone()))
|
.with_from(Jid::Full(
|
||||||
|
locked_inner.jid.as_ref().context("missing jid")?.clone(),
|
||||||
|
))
|
||||||
.with_to(Jid::Bare(locked_inner.xmpp_domain.clone()));
|
.with_to(Jid::Bare(locked_inner.xmpp_domain.clone()));
|
||||||
tx.send(iq.into()).await?;
|
tx.send(iq.into()).await?;
|
||||||
locked_inner.state = DiscoveringExternalServices;
|
locked_inner.state = DiscoveringExternalServices;
|
||||||
|
|
|
@ -34,6 +34,7 @@ use crate::{
|
||||||
};
|
};
|
||||||
|
|
||||||
const DEFAULT_STUN_PORT: u16 = 3478;
|
const DEFAULT_STUN_PORT: u16 = 3478;
|
||||||
|
const DEFAULT_TURNS_PORT: u16 = 5349;
|
||||||
|
|
||||||
pub(crate) struct JingleSession {
|
pub(crate) struct JingleSession {
|
||||||
pipeline: gstreamer::Pipeline,
|
pipeline: gstreamer::Pipeline,
|
||||||
|
@ -198,7 +199,10 @@ impl JingleSession {
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(remote_fingerprint) = dtls_fingerprint {
|
if let Some(remote_fingerprint) = dtls_fingerprint {
|
||||||
warn!("Remote DTLS fingerprint (verification not implemented yet): {:?}", remote_fingerprint);
|
warn!(
|
||||||
|
"Remote DTLS fingerprint (verification not implemented yet): {:?}",
|
||||||
|
remote_fingerprint
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut dtls_cert_params = CertificateParams::new(vec!["gst-meet".to_owned()]);
|
let mut dtls_cert_params = CertificateParams::new(vec!["gst-meet".to_owned()]);
|
||||||
|
@ -225,13 +229,23 @@ impl JingleSession {
|
||||||
debug!("audio SSRC: {}", audio_ssrc);
|
debug!("audio SSRC: {}", audio_ssrc);
|
||||||
debug!("video SSRC: {}", video_ssrc);
|
debug!("video SSRC: {}", video_ssrc);
|
||||||
|
|
||||||
|
let ice_agent = nice::Agent::new(&conference.glib_main_context, nice::Compatibility::Rfc5245);
|
||||||
|
ice_agent.set_ice_tcp(false);
|
||||||
|
ice_agent.set_upnp(false);
|
||||||
|
let ice_stream_id = ice_agent.add_stream(1);
|
||||||
|
let ice_component_id = 1;
|
||||||
|
|
||||||
let maybe_stun = conference
|
let maybe_stun = conference
|
||||||
.external_services
|
.external_services
|
||||||
.iter()
|
.iter()
|
||||||
.find(|svc| svc.r#type == "stun");
|
.find(|svc| svc.r#type == "stun");
|
||||||
|
|
||||||
let stun_addr = if let Some(stun) = maybe_stun {
|
let stun_addr = if let Some(stun) = maybe_stun {
|
||||||
lookup_host(format!("{}:{}", stun.host, stun.port.unwrap_or(DEFAULT_STUN_PORT)))
|
lookup_host(format!(
|
||||||
|
"{}:{}",
|
||||||
|
stun.host,
|
||||||
|
stun.port.unwrap_or(DEFAULT_STUN_PORT)
|
||||||
|
))
|
||||||
.await?
|
.await?
|
||||||
.next()
|
.next()
|
||||||
}
|
}
|
||||||
|
@ -240,21 +254,38 @@ impl JingleSession {
|
||||||
};
|
};
|
||||||
debug!("STUN address: {:?}", stun_addr);
|
debug!("STUN address: {:?}", stun_addr);
|
||||||
|
|
||||||
let ice_agent = nice::Agent::new(&conference.glib_main_context, nice::Compatibility::Rfc5245);
|
|
||||||
ice_agent.set_ice_tcp(false);
|
|
||||||
if let Some((stun_addr, stun_port)) = stun_addr.map(|sa| (sa.ip().to_string(), sa.port())) {
|
if let Some((stun_addr, stun_port)) = stun_addr.map(|sa| (sa.ip().to_string(), sa.port())) {
|
||||||
ice_agent.set_stun_server(Some(&stun_addr));
|
ice_agent.set_stun_server(Some(&stun_addr));
|
||||||
ice_agent.set_stun_server_port(stun_port as u32);
|
ice_agent.set_stun_server_port(stun_port as u32);
|
||||||
}
|
}
|
||||||
ice_agent.set_upnp(false);
|
|
||||||
ice_agent.connect_component_state_changed(|_, a, b, c| {
|
let maybe_turn = conference
|
||||||
debug!("ICE component-state-changed {} {} {}", a, b, c);
|
.external_services
|
||||||
});
|
.iter()
|
||||||
ice_agent.connect_new_selected_pair(|_, a, b, c, d| {
|
.find(|svc| svc.r#type == "turns");
|
||||||
debug!("ICE new-selected-pair {} {} {} {}", a, b, c, d);
|
|
||||||
});
|
if let Some(turn_server) = maybe_turn {
|
||||||
let ice_stream_id = ice_agent.add_stream(1);
|
let maybe_addr = lookup_host(format!(
|
||||||
let ice_component_id = 1;
|
"{}:{}",
|
||||||
|
turn_server.host,
|
||||||
|
turn_server.port.unwrap_or(DEFAULT_TURNS_PORT)
|
||||||
|
))
|
||||||
|
.await?
|
||||||
|
.next();
|
||||||
|
|
||||||
|
if let Some(addr) = maybe_addr {
|
||||||
|
debug!("TURN address: {:?}", addr);
|
||||||
|
ice_agent.set_relay_info(
|
||||||
|
ice_stream_id,
|
||||||
|
ice_component_id,
|
||||||
|
&addr.ip().to_string(),
|
||||||
|
addr.port() as u32,
|
||||||
|
turn_server.username.as_deref().unwrap_or_default(),
|
||||||
|
turn_server.password.as_deref().unwrap_or_default(),
|
||||||
|
nice::RelayType::Tls,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if !ice_agent.attach_recv(
|
if !ice_agent.attach_recv(
|
||||||
ice_stream_id,
|
ice_stream_id,
|
||||||
|
@ -716,8 +747,7 @@ impl JingleSession {
|
||||||
});
|
});
|
||||||
description.ssrcs = vec![ssrc];
|
description.ssrcs = vec![ssrc];
|
||||||
|
|
||||||
let mut transport = IceUdpTransport::new()
|
let mut transport = IceUdpTransport::new().with_fingerprint(Fingerprint {
|
||||||
.with_fingerprint(Fingerprint {
|
|
||||||
hash: Algo::Sha_256,
|
hash: Algo::Sha_256,
|
||||||
setup: Some(Setup::Active),
|
setup: Some(Setup::Active),
|
||||||
value: fingerprint.clone(),
|
value: fingerprint.clone(),
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
pub mod conference;
|
pub mod conference;
|
||||||
pub mod connection;
|
pub mod connection;
|
||||||
mod jingle;
|
mod jingle;
|
||||||
mod xmpp;
|
|
||||||
mod pinger;
|
mod pinger;
|
||||||
pub mod source;
|
pub mod source;
|
||||||
mod stanza_filter;
|
mod stanza_filter;
|
||||||
mod util;
|
mod util;
|
||||||
|
mod xmpp;
|
||||||
|
|
||||||
pub use crate::{
|
pub use crate::{
|
||||||
conference::{JitsiConference, JitsiConferenceConfig, Participant},
|
conference::{JitsiConference, JitsiConferenceConfig, Participant},
|
||||||
|
|
|
@ -1,10 +1,7 @@
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
use anyhow::{bail, Context, Result};
|
use anyhow::{bail, Context, Result};
|
||||||
use xmpp_parsers::{
|
use xmpp_parsers::{iq::IqGetPayload, Element};
|
||||||
Element,
|
|
||||||
iq::IqGetPayload,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::xmpp::ns;
|
use crate::xmpp::ns;
|
||||||
|
|
||||||
|
@ -56,17 +53,21 @@ impl TryFrom<Element> for ServicesResult {
|
||||||
Ok(ServicesResult {
|
Ok(ServicesResult {
|
||||||
services: elem
|
services: elem
|
||||||
.children()
|
.children()
|
||||||
.map(|child| Ok(Service {
|
.map(|child| {
|
||||||
|
Ok(Service {
|
||||||
r#type: child.attr("type").context("missing type attr")?.to_owned(),
|
r#type: child.attr("type").context("missing type attr")?.to_owned(),
|
||||||
name: child.attr("name").map(ToOwned::to_owned),
|
name: child.attr("name").map(ToOwned::to_owned),
|
||||||
host: child.attr("host").context("missing host attr")?.to_owned(),
|
host: child.attr("host").context("missing host attr")?.to_owned(),
|
||||||
port: child.attr("port").map(|p| p.parse()).transpose()?,
|
port: child.attr("port").map(|p| p.parse()).transpose()?,
|
||||||
transport: child.attr("transport").map(ToOwned::to_owned),
|
transport: child.attr("transport").map(ToOwned::to_owned),
|
||||||
restricted: child.attr("restricted").map(|b| b.to_lowercase() == "parse" || b == "1"),
|
restricted: child
|
||||||
|
.attr("restricted")
|
||||||
|
.map(|b| b.to_lowercase() == "parse" || b == "1"),
|
||||||
username: child.attr("username").map(ToOwned::to_owned),
|
username: child.attr("username").map(ToOwned::to_owned),
|
||||||
password: child.attr("password").map(ToOwned::to_owned),
|
password: child.attr("password").map(ToOwned::to_owned),
|
||||||
expires: child.attr("expires").map(ToOwned::to_owned),
|
expires: child.attr("expires").map(ToOwned::to_owned),
|
||||||
}))
|
})
|
||||||
|
})
|
||||||
.collect::<Result<_>>()?,
|
.collect::<Result<_>>()?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue