publish client-sdk-native (#12)

* Create README.md

* add example

* crates & examples

* fix syntax

* add LICENSE

* thirdparty LICENSE

* rearrange repo

* fix build

* egui versions

* prepare publish

* fix demo compilation

* add test ci

* Update rust.yml

* forgot runs-on

* install protoc before building

* avoid rate limit

* include submodules

* updates to readme

* cache rust builds

Co-authored-by: David Zhao <[email protected]>
Co-authored-by: David Zhao <[email protected]>
This commit is contained in:
Théo Monnom
2023-01-02 20:13:48 +01:00
committed by GitHub
co-authored by David Zhao David Zhao
parent a927baac94
commit a07b3451a3
102 changed files with 893 additions and 344 deletions
+247
View File
@@ -0,0 +1,247 @@
use super::publication::RemoteTrackPublication;
use super::TrackError;
use crate::proto;
use crate::proto::ParticipantInfo;
use crate::room::id::{ParticipantIdentity, ParticipantSid, TrackSid};
use crate::room::participant::local_participant::LocalParticipant;
use crate::room::participant::remote_participant::RemoteParticipant;
use crate::room::publication::{TrackPublication, TrackPublicationTrait};
use crate::room::track::remote_track::RemoteTrackHandle;
use livekit_utils::enum_dispatch;
use livekit_utils::observer::Dispatcher;
use parking_lot::{Mutex, RwLock, RwLockReadGuard};
use proto::data_packet;
use std::collections::HashMap;
use std::sync::atomic::{AtomicBool, AtomicU32, AtomicU8, Ordering};
use std::sync::Arc;
use tokio::sync::mpsc;
pub mod local_participant;
pub mod remote_participant;
#[derive(Debug, Clone)]
pub enum ParticipantEvent {
TrackPublished {
publication: RemoteTrackPublication,
},
TrackUnpublished {
publication: RemoteTrackPublication,
},
TrackSubscribed {
track: RemoteTrackHandle,
publication: RemoteTrackPublication,
},
TrackUnsubscribed {
track: RemoteTrackHandle,
publication: RemoteTrackPublication,
},
TrackSubscriptionFailed {
error: TrackError,
sid: TrackSid,
},
DataReceived {
payload: Arc<Vec<u8>>,
kind: data_packet::Kind,
},
SpeakingChanged {
speaking: bool,
},
TrackMuted {
publication: TrackPublication,
},
TrackUnmuted {
publication: TrackPublication,
},
ConnectionQualityChanged {
quality: ConnectionQuality,
},
}
#[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)]
pub(super) struct ParticipantShared {
pub(super) sid: Mutex<ParticipantSid>,
pub(super) identity: Mutex<ParticipantIdentity>,
pub(super) name: Mutex<String>,
pub(super) metadata: Mutex<String>,
pub(super) tracks: RwLock<HashMap<TrackSid, TrackPublication>>,
pub(super) speaking: AtomicBool,
pub(super) audio_level: AtomicU32,
pub(super) connection_quality: AtomicU8,
pub(super) dispatcher: Mutex<Dispatcher<ParticipantEvent>>,
}
impl ParticipantShared {
pub(super) fn new(
sid: ParticipantSid,
identity: ParticipantIdentity,
name: String,
metadata: String,
) -> Self {
Self {
sid: Mutex::new(sid),
identity: Mutex::new(identity),
name: Mutex::new(name),
metadata: Mutex::new(metadata),
tracks: Default::default(),
speaking: Default::default(),
audio_level: Default::default(),
connection_quality: AtomicU8::new(ConnectionQuality::Unknown as u8),
dispatcher: Default::default(),
}
}
pub(crate) fn update_info(&self, info: ParticipantInfo) {
*self.sid.lock() = info.sid.into();
*self.identity.lock() = info.identity.into();
*self.name.lock() = info.name;
*self.metadata.lock() = info.metadata; // TODO(theomonnom): callback MetadataChanged
}
pub(crate) fn set_speaking(&self, speaking: bool) {
self.speaking.store(speaking, Ordering::SeqCst);
}
pub(crate) fn set_audio_level(&self, audio_level: f32) {
self.audio_level
.store(audio_level.to_bits(), Ordering::SeqCst)
}
pub(crate) fn register_observer(&self) -> mpsc::UnboundedReceiver<ParticipantEvent> {
self.dispatcher.lock().register()
}
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) {
self.tracks.write().insert(publication.sid(), publication);
}
}
pub(crate) trait ParticipantInternalTrait {
fn set_speaking(&self, speaking: bool);
fn set_audio_level(&self, level: f32);
fn set_connection_quality(&self, quality: ConnectionQuality);
fn update_info(self: &Arc<Self>, info: ParticipantInfo, emit_events: bool);
}
pub trait ParticipantTrait {
fn sid(&self) -> ParticipantSid;
fn identity(&self) -> ParticipantIdentity;
fn name(&self) -> String;
fn metadata(&self) -> String;
fn is_speaking(&self) -> bool;
fn audio_level(&self) -> f32;
fn connection_quality(&self) -> ConnectionQuality;
fn tracks(&self) -> RwLockReadGuard<HashMap<TrackSid, TrackPublication>>;
fn register_observer(&self) -> mpsc::UnboundedReceiver<ParticipantEvent>;
}
#[derive(Debug, Clone)]
pub enum Participant {
Local(Arc<LocalParticipant>),
Remote(Arc<RemoteParticipant>),
}
// TODO(theomonnom): Should I provide a WeakParticipant here ?
impl Participant {
enum_dispatch!(
[Local, Remote]
fnc!(pub(crate), update_info, &Self, [info: ParticipantInfo, emit_events: bool], ());
fnc!(pub(crate), set_speaking, &Self, [speaking: bool], ());
fnc!(pub(crate), set_audio_level, &Self, [audio_level: f32], ());
fnc!(pub(crate), set_connection_quality, &Self, [quality: ConnectionQuality], ());
);
}
impl ParticipantTrait for Participant {
enum_dispatch!(
[Local, Remote]
fnc!(sid, &Self, [], ParticipantSid);
fnc!(identity, &Self, [], ParticipantIdentity);
fnc!(name, &Self, [], String);
fnc!(metadata, &Self, [], String);
fnc!(is_speaking, &Self, [], bool);
fnc!(audio_level, &Self, [], f32);
fnc!(connection_quality, &Self, [], ConnectionQuality);
fnc!(tracks, &Self, [], RwLockReadGuard<HashMap<TrackSid, TrackPublication>>);
fnc!(register_observer, &Self, [], mpsc::UnboundedReceiver<ParticipantEvent>);
);
}
macro_rules! impl_participant_trait {
($x:ty) => {
impl crate::room::participant::ParticipantTrait for $x {
fn sid(&self) -> ParticipantSid {
self.shared.sid.lock().clone()
}
fn identity(&self) -> ParticipantIdentity {
self.shared.identity.lock().clone()
}
fn name(&self) -> String {
self.shared.name.lock().clone()
}
fn metadata(&self) -> String {
self.shared.metadata.lock().clone()
}
fn is_speaking(&self) -> bool {
self.shared.speaking.load(Ordering::SeqCst)
}
fn audio_level(&self) -> f32 {
f32::from_bits(self.shared.audio_level.load(Ordering::SeqCst))
}
fn connection_quality(&self) -> ConnectionQuality {
self.shared.connection_quality.load(Ordering::SeqCst).into()
}
fn tracks(&self) -> RwLockReadGuard<HashMap<TrackSid, TrackPublication>> {
self.shared.tracks.read()
}
fn register_observer(&self) -> mpsc::UnboundedReceiver<ParticipantEvent> {
self.shared.register_observer()
}
}
};
}
pub(super) use impl_participant_trait;