connection_quality
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
use self::participant::ConnectionQuality;
|
||||||
use self::room_session::{ConnectionState, RoomSession, SessionHandle};
|
use self::room_session::{ConnectionState, RoomSession, SessionHandle};
|
||||||
use crate::proto::data_packet;
|
use crate::proto::data_packet;
|
||||||
use crate::room::id::TrackSid;
|
use crate::room::id::TrackSid;
|
||||||
@@ -76,6 +77,10 @@ pub enum RoomEvent {
|
|||||||
ActiveSpeakersChanged {
|
ActiveSpeakersChanged {
|
||||||
speakers: Vec<ParticipantHandle>,
|
speakers: Vec<ParticipantHandle>,
|
||||||
},
|
},
|
||||||
|
ConnectionQualityChanged {
|
||||||
|
quality: ConnectionQuality,
|
||||||
|
participant: ParticipantHandle,
|
||||||
|
},
|
||||||
DataReceived {
|
DataReceived {
|
||||||
payload: Vec<u8>,
|
payload: Vec<u8>,
|
||||||
kind: data_packet::Kind,
|
kind: data_packet::Kind,
|
||||||
|
|||||||
@@ -60,6 +60,10 @@ impl ParticipantInternalTrait for LocalParticipant {
|
|||||||
fn set_audio_level(&self, level: f32) {
|
fn set_audio_level(&self, level: f32) {
|
||||||
self.shared.set_audio_level(level);
|
self.shared.set_audio_level(level);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_connection_quality(&self, quality: ConnectionQuality) {
|
||||||
|
self.shared.set_connection_quality(quality);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_participant_trait!(LocalParticipant);
|
impl_participant_trait!(LocalParticipant);
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
use crate::proto;
|
||||||
use crate::proto::ParticipantInfo;
|
use crate::proto::ParticipantInfo;
|
||||||
use crate::room::id::{ParticipantIdentity, ParticipantSid, TrackSid};
|
use crate::room::id::{ParticipantIdentity, ParticipantSid, TrackSid};
|
||||||
use crate::room::participant::local_participant::LocalParticipant;
|
use crate::room::participant::local_participant::LocalParticipant;
|
||||||
@@ -7,12 +8,42 @@ use crate::room::room_session::SessionEmitter;
|
|||||||
use livekit_utils::enum_dispatch;
|
use livekit_utils::enum_dispatch;
|
||||||
use parking_lot::{Mutex, RwLock};
|
use parking_lot::{Mutex, RwLock};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::atomic::{AtomicBool, AtomicU32, Ordering};
|
use std::sync::atomic::{AtomicBool, AtomicU32, AtomicU8, Ordering};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
pub mod local_participant;
|
pub mod local_participant;
|
||||||
pub mod remote_participant;
|
pub mod remote_participant;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
||||||
|
#[repr(u8)]
|
||||||
|
pub enum ConnectionQuality {
|
||||||
|
Unknown,
|
||||||
|
Excellent,
|
||||||
|
Good,
|
||||||
|
Poor,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<u8> for ConnectionQuality {
|
||||||
|
fn from(value: u8) -> Self {
|
||||||
|
match value {
|
||||||
|
1 => Self::Excellent,
|
||||||
|
2 => Self::Good,
|
||||||
|
3 => Self::Poor,
|
||||||
|
_ => Self::Unknown,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<proto::ConnectionQuality> for ConnectionQuality {
|
||||||
|
fn from(value: proto::ConnectionQuality) -> Self {
|
||||||
|
match value {
|
||||||
|
proto::ConnectionQuality::Excellent => Self::Excellent,
|
||||||
|
proto::ConnectionQuality::Good => Self::Good,
|
||||||
|
proto::ConnectionQuality::Poor => Self::Poor,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(super) struct ParticipantShared {
|
pub(super) struct ParticipantShared {
|
||||||
pub(super) sid: Mutex<ParticipantSid>,
|
pub(super) sid: Mutex<ParticipantSid>,
|
||||||
@@ -22,6 +53,7 @@ pub(super) struct ParticipantShared {
|
|||||||
pub(super) tracks: RwLock<HashMap<TrackSid, TrackPublication>>,
|
pub(super) tracks: RwLock<HashMap<TrackSid, TrackPublication>>,
|
||||||
pub(super) speaking: AtomicBool,
|
pub(super) speaking: AtomicBool,
|
||||||
pub(super) audio_level: AtomicU32,
|
pub(super) audio_level: AtomicU32,
|
||||||
|
pub(super) connection_quality: AtomicU8,
|
||||||
pub(super) internal_tx: SessionEmitter,
|
pub(super) internal_tx: SessionEmitter,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,6 +73,7 @@ impl ParticipantShared {
|
|||||||
tracks: Default::default(),
|
tracks: Default::default(),
|
||||||
speaking: Default::default(),
|
speaking: Default::default(),
|
||||||
audio_level: Default::default(),
|
audio_level: Default::default(),
|
||||||
|
connection_quality: AtomicU8::new(ConnectionQuality::Unknown as u8),
|
||||||
internal_tx,
|
internal_tx,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -61,6 +94,11 @@ impl ParticipantShared {
|
|||||||
.store(audio_level.to_bits(), Ordering::SeqCst)
|
.store(audio_level.to_bits(), Ordering::SeqCst)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn set_connection_quality(&self, quality: ConnectionQuality) {
|
||||||
|
self.connection_quality
|
||||||
|
.store(quality as u8, Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn add_track_publication(&self, publication: TrackPublication) {
|
pub(crate) fn add_track_publication(&self, publication: TrackPublication) {
|
||||||
self.tracks.write().insert(publication.sid(), publication);
|
self.tracks.write().insert(publication.sid(), publication);
|
||||||
}
|
}
|
||||||
@@ -69,6 +107,7 @@ impl ParticipantShared {
|
|||||||
pub(crate) trait ParticipantInternalTrait {
|
pub(crate) trait ParticipantInternalTrait {
|
||||||
fn set_speaking(&self, speaking: bool);
|
fn set_speaking(&self, speaking: bool);
|
||||||
fn set_audio_level(&self, level: f32);
|
fn set_audio_level(&self, level: f32);
|
||||||
|
fn set_connection_quality(&self, quality: ConnectionQuality);
|
||||||
fn update_info(self: &Arc<Self>, info: ParticipantInfo);
|
fn update_info(self: &Arc<Self>, info: ParticipantInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,6 +118,7 @@ pub trait ParticipantTrait {
|
|||||||
fn metadata(&self) -> String;
|
fn metadata(&self) -> String;
|
||||||
fn is_speaking(&self) -> bool;
|
fn is_speaking(&self) -> bool;
|
||||||
fn audio_level(&self) -> f32;
|
fn audio_level(&self) -> f32;
|
||||||
|
fn connection_quality(&self) -> ConnectionQuality;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@@ -93,6 +133,7 @@ impl ParticipantHandle {
|
|||||||
fnc!(pub(crate), update_info, &Self, [info: ParticipantInfo], ());
|
fnc!(pub(crate), update_info, &Self, [info: ParticipantInfo], ());
|
||||||
fnc!(pub(crate), set_speaking, &Self, [speaking: bool], ());
|
fnc!(pub(crate), set_speaking, &Self, [speaking: bool], ());
|
||||||
fnc!(pub(crate), set_audio_level, &Self, [audio_level: f32], ());
|
fnc!(pub(crate), set_audio_level, &Self, [audio_level: f32], ());
|
||||||
|
fnc!(pub(crate), set_connection_quality, &Self, [quality: ConnectionQuality], ());
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,15 +146,17 @@ impl ParticipantTrait for ParticipantHandle {
|
|||||||
fnc!(metadata, &Self, [], String);
|
fnc!(metadata, &Self, [], String);
|
||||||
fnc!(is_speaking, &Self, [], bool);
|
fnc!(is_speaking, &Self, [], bool);
|
||||||
fnc!(audio_level, &Self, [], f32);
|
fnc!(audio_level, &Self, [], f32);
|
||||||
|
fnc!(connection_quality, &Self, [], ConnectionQuality);
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_participant_trait {
|
macro_rules! impl_participant_trait {
|
||||||
($x:ty) => {
|
($x:ty) => {
|
||||||
use crate::proto::ParticipantInfo;
|
|
||||||
use crate::room::id::{ParticipantIdentity, ParticipantSid};
|
|
||||||
use std::sync::atomic::Ordering;
|
use std::sync::atomic::Ordering;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use $crate::proto::ParticipantInfo;
|
||||||
|
use $crate::room::id::{ParticipantIdentity, ParticipantSid};
|
||||||
|
use $crate::room::participant::ConnectionQuality;
|
||||||
|
|
||||||
impl crate::room::participant::ParticipantTrait for $x {
|
impl crate::room::participant::ParticipantTrait for $x {
|
||||||
fn sid(&self) -> ParticipantSid {
|
fn sid(&self) -> ParticipantSid {
|
||||||
@@ -139,6 +182,10 @@ macro_rules! impl_participant_trait {
|
|||||||
fn audio_level(&self) -> f32 {
|
fn audio_level(&self) -> f32 {
|
||||||
f32::from_bits(self.shared.audio_level.load(Ordering::SeqCst))
|
f32::from_bits(self.shared.audio_level.load(Ordering::SeqCst))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn connection_quality(&self) -> ConnectionQuality {
|
||||||
|
self.shared.connection_quality.load(Ordering::SeqCst).into()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -163,6 +163,10 @@ impl ParticipantInternalTrait for RemoteParticipant {
|
|||||||
fn set_audio_level(&self, level: f32) {
|
fn set_audio_level(&self, level: f32) {
|
||||||
self.shared.set_audio_level(level);
|
self.shared.set_audio_level(level);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_connection_quality(&self, quality: ConnectionQuality) {
|
||||||
|
self.shared.set_connection_quality(quality);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_participant_trait!(RemoteParticipant);
|
impl_participant_trait!(RemoteParticipant);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use super::id::{ParticipantIdentity, ParticipantSid};
|
use super::id::{ParticipantIdentity, ParticipantSid};
|
||||||
use super::participant::local_participant::LocalParticipant;
|
use super::participant::local_participant::LocalParticipant;
|
||||||
use super::participant::remote_participant::RemoteParticipant;
|
use super::participant::remote_participant::RemoteParticipant;
|
||||||
use super::participant::ParticipantHandle;
|
use super::participant::{ConnectionQuality, ParticipantHandle};
|
||||||
use super::participant::{ParticipantInternalTrait, ParticipantTrait};
|
use super::participant::{ParticipantInternalTrait, ParticipantTrait};
|
||||||
use super::{RoomEmitter, RoomError, RoomEvent, RoomResult, SimulateScenario};
|
use super::{RoomEmitter, RoomError, RoomEvent, RoomResult, SimulateScenario};
|
||||||
use crate::proto::{self, participant_info, SpeakerInfo};
|
use crate::proto::{self, participant_info, SpeakerInfo};
|
||||||
@@ -29,17 +29,16 @@ pub enum ConnectionState {
|
|||||||
Disconnected,
|
Disconnected,
|
||||||
Connected,
|
Connected,
|
||||||
Reconnecting,
|
Reconnecting,
|
||||||
|
Unknown,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<u8> for ConnectionState {
|
impl From<u8> for ConnectionState {
|
||||||
type Error = &'static str;
|
fn from(value: u8) -> Self {
|
||||||
|
|
||||||
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
|
||||||
match value {
|
match value {
|
||||||
0 => Ok(ConnectionState::Disconnected),
|
0 => ConnectionState::Disconnected,
|
||||||
1 => Ok(ConnectionState::Connected),
|
1 => ConnectionState::Connected,
|
||||||
2 => Ok(ConnectionState::Reconnecting),
|
2 => ConnectionState::Reconnecting,
|
||||||
_ => Err("invalid ConnectionState"),
|
_ => ConnectionState::Unknown,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -220,6 +219,7 @@ impl SessionInner {
|
|||||||
&& matches!(
|
&& matches!(
|
||||||
event,
|
event,
|
||||||
RoomEvent::TrackPublished { .. }
|
RoomEvent::TrackPublished { .. }
|
||||||
|
| RoomEvent::TrackUnpublished { .. }
|
||||||
| RoomEvent::ParticipantConnected { .. }
|
| RoomEvent::ParticipantConnected { .. }
|
||||||
| RoomEvent::ParticipantDisconnected { .. }
|
| RoomEvent::ParticipantDisconnected { .. }
|
||||||
| RoomEvent::ActiveSpeakersChanged { .. }
|
| RoomEvent::ActiveSpeakersChanged { .. }
|
||||||
@@ -308,6 +308,9 @@ impl SessionInner {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
EngineEvent::SpeakersChanged { speakers } => self.handle_speakers_changed(speakers),
|
EngineEvent::SpeakersChanged { speakers } => self.handle_speakers_changed(speakers),
|
||||||
|
EngineEvent::ConnectionQuality { updates } => {
|
||||||
|
self.handle_connection_quality_update(updates)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -390,6 +393,8 @@ impl SessionInner {
|
|||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Active speakers changed
|
||||||
|
/// Update the participants & sort the active_speakers by audio_level
|
||||||
#[instrument(level = Level::DEBUG)]
|
#[instrument(level = Level::DEBUG)]
|
||||||
fn handle_speakers_changed(&self, speakers_info: Vec<SpeakerInfo>) {
|
fn handle_speakers_changed(&self, speakers_info: Vec<SpeakerInfo>) {
|
||||||
let mut speakers = Vec::new();
|
let mut speakers = Vec::new();
|
||||||
@@ -424,6 +429,38 @@ impl SessionInner {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Handle a connection quality update
|
||||||
|
/// Emit ConnectionQualityChanged event for the concerned participants
|
||||||
|
#[instrument(level = Level::DEBUG)]
|
||||||
|
fn handle_connection_quality_update(&self, updates: Vec<proto::ConnectionQualityInfo>) {
|
||||||
|
for update in updates {
|
||||||
|
let participant = {
|
||||||
|
if update.participant_sid == self.local_participant.sid() {
|
||||||
|
ParticipantHandle::Local(self.local_participant.clone())
|
||||||
|
} else {
|
||||||
|
if let Some(participant) = self.get_participant(&update.participant_sid.into())
|
||||||
|
{
|
||||||
|
ParticipantHandle::Remote(participant)
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let quality: ConnectionQuality = proto::ConnectionQuality::from_i32(update.quality)
|
||||||
|
.unwrap()
|
||||||
|
.into();
|
||||||
|
|
||||||
|
participant.set_connection_quality(quality);
|
||||||
|
let _ =
|
||||||
|
self.internal_tx
|
||||||
|
.send(SessionEvent::Room(RoomEvent::ConnectionQualityChanged {
|
||||||
|
participant,
|
||||||
|
quality,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[instrument(level = Level::DEBUG)]
|
#[instrument(level = Level::DEBUG)]
|
||||||
fn handle_restarting(&self) {
|
fn handle_restarting(&self) {
|
||||||
// Remove existing participants/subscriptions on full reconnect
|
// Remove existing participants/subscriptions on full reconnect
|
||||||
|
|||||||
@@ -178,8 +178,8 @@ impl TrackHandle {
|
|||||||
|
|
||||||
macro_rules! impl_track_trait {
|
macro_rules! impl_track_trait {
|
||||||
($x:ident) => {
|
($x:ident) => {
|
||||||
use crate::room::id::TrackSid;
|
use $crate::room::id::TrackSid;
|
||||||
use crate::room::track::{StreamState, TrackKind, TrackTrait};
|
use $crate::room::track::{StreamState, TrackKind, TrackTrait};
|
||||||
use std::sync::atomic::Ordering;
|
use std::sync::atomic::Ordering;
|
||||||
|
|
||||||
impl TrackTrait for $x {
|
impl TrackTrait for $x {
|
||||||
|
|||||||
@@ -18,7 +18,9 @@ use lazy_static::lazy_static;
|
|||||||
use tokio::sync::{mpsc, oneshot};
|
use tokio::sync::{mpsc, oneshot};
|
||||||
use tracing::{error, info, warn};
|
use tracing::{error, info, warn};
|
||||||
|
|
||||||
use crate::proto::{data_packet, DataPacket, JoinResponse, ParticipantUpdate, SpeakerInfo};
|
use crate::proto::{
|
||||||
|
self as proto, data_packet, DataPacket, JoinResponse, ParticipantUpdate, SpeakerInfo,
|
||||||
|
};
|
||||||
use crate::rtc_engine::lk_runtime::LKRuntime;
|
use crate::rtc_engine::lk_runtime::LKRuntime;
|
||||||
use crate::signal_client::{SignalError, SignalOptions};
|
use crate::signal_client::{SignalError, SignalOptions};
|
||||||
|
|
||||||
@@ -81,6 +83,9 @@ pub enum EngineEvent {
|
|||||||
SpeakersChanged {
|
SpeakersChanged {
|
||||||
speakers: Vec<SpeakerInfo>,
|
speakers: Vec<SpeakerInfo>,
|
||||||
},
|
},
|
||||||
|
ConnectionQuality {
|
||||||
|
updates: Vec<proto::ConnectionQualityInfo>,
|
||||||
|
},
|
||||||
Resuming,
|
Resuming,
|
||||||
Resumed,
|
Resumed,
|
||||||
Restarting,
|
Restarting,
|
||||||
@@ -283,6 +288,12 @@ impl EngineInner {
|
|||||||
.send(EngineEvent::SpeakersChanged { speakers })
|
.send(EngineEvent::SpeakersChanged { speakers })
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
SessionEvent::ConnectionQuality { updates } => {
|
||||||
|
let _ = self
|
||||||
|
.engine_emitter
|
||||||
|
.send(EngineEvent::ConnectionQuality { updates })
|
||||||
|
.await;
|
||||||
|
}
|
||||||
SessionEvent::Connected => {}
|
SessionEvent::Connected => {}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -56,6 +56,9 @@ pub enum SessionEvent {
|
|||||||
SpeakersChanged {
|
SpeakersChanged {
|
||||||
speakers: Vec<proto::SpeakerInfo>,
|
speakers: Vec<proto::SpeakerInfo>,
|
||||||
},
|
},
|
||||||
|
ConnectionQuality{
|
||||||
|
updates: Vec<proto::ConnectionQualityInfo>,
|
||||||
|
},
|
||||||
// TODO(theomonnom): Move entirely the reconnection logic on mod.rs
|
// TODO(theomonnom): Move entirely the reconnection logic on mod.rs
|
||||||
Close {
|
Close {
|
||||||
source: String,
|
source: String,
|
||||||
@@ -420,11 +423,14 @@ impl SessionInner {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
signal_response::Message::SpeakersChanged(speaker) => {
|
signal_response::Message::SpeakersChanged(speaker) => {
|
||||||
let _ = self
|
let _ = self.emitter.send(SessionEvent::SpeakersChanged {
|
||||||
.emitter
|
speakers: speaker.speakers,
|
||||||
.send(SessionEvent::SpeakersChanged {
|
});
|
||||||
speakers: speaker.speakers,
|
}
|
||||||
});
|
signal_response::Message::ConnectionQuality(quality) => {
|
||||||
|
let _ = self.emitter.send(SessionEvent::ConnectionQuality{
|
||||||
|
updates: quality.updates,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user