feat: server sdk (#47)
* New webrtc build scripts (Still not integrated within the SDK) * New livekit-api crate (Integrate the server sdk protocol of livekit) * Moved livekit-utils to livekit-protocol
This commit is contained in:
@@ -36,6 +36,11 @@ jobs:
|
||||
rustup update --no-self-update stable
|
||||
rustup target add ${{ matrix.target }}
|
||||
|
||||
- if: ${{ matrix.target == 'aarch64-pc-windows-msvc' }}
|
||||
run: |
|
||||
echo "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\Llvm\x64\bin" >> $GITHUB_PATH
|
||||
shell: bash
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
[submodule "livekit/protocol"]
|
||||
path = livekit/protocol
|
||||
path = livekit-protocol/protocol
|
||||
url = https://github.com/livekit/protocol
|
||||
|
||||
Generated
+363
-320
File diff suppressed because it is too large
Load Diff
+2
-1
@@ -1,7 +1,8 @@
|
||||
[workspace]
|
||||
members = [
|
||||
"livekit",
|
||||
"livekit-utils",
|
||||
"livekit-api",
|
||||
"livekit-protocol",
|
||||
"livekit-ffi",
|
||||
"livekit-webrtc",
|
||||
"webrtc-sys"
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
[package]
|
||||
name = "livekit-api"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
jsonwebtoken = {version = "8", default-features = false }
|
||||
thiserror = "1.0"
|
||||
serde = {version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
livekit-protocol = { path = "../livekit-protocol", version = "0.1.0" }
|
||||
sha2 = "0.10.6"
|
||||
reqwest = { version = "0.11", features=["json"] }
|
||||
url = "2.3.1"
|
||||
prost = "0.11.9"
|
||||
@@ -0,0 +1,260 @@
|
||||
use crate::get_env_keys;
|
||||
use jsonwebtoken::{self, DecodingKey, EncodingKey, Header};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::env;
|
||||
use std::fmt::Debug;
|
||||
use std::ops::Add;
|
||||
use std::time::Duration;
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
use thiserror::Error;
|
||||
|
||||
pub const DEFAULT_TTL: Duration = Duration::from_secs(3600 * 6); // 6 hours
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum AccessTokenError {
|
||||
#[error("Invalid API Key or Secret Key")]
|
||||
InvalidKeys,
|
||||
#[error("Invalid environment")]
|
||||
InvalidEnv(#[from] env::VarError),
|
||||
#[error("invalid claims: {0}")]
|
||||
InvalidClaims(&'static str),
|
||||
#[error("failed to encode jwt")]
|
||||
Encoding(#[from] jsonwebtoken::errors::Error),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct VideoGrants {
|
||||
// actions on rooms
|
||||
pub room_create: bool,
|
||||
pub room_list: bool,
|
||||
pub room_record: bool,
|
||||
|
||||
// actions on a particular room
|
||||
pub room_admin: bool,
|
||||
pub room_join: bool,
|
||||
pub room: String,
|
||||
|
||||
// permissions within a room
|
||||
pub can_publish: bool,
|
||||
pub can_subscribe: bool,
|
||||
pub can_publish_data: bool,
|
||||
|
||||
// TrackSource types that a participant may publish.
|
||||
// When set, it supercedes CanPublish. Only sources explicitly set here can be published
|
||||
pub can_publish_sources: Vec<String>, // keys keep track of each source
|
||||
|
||||
// by default, a participant is not allowed to update its own metadata
|
||||
pub can_update_own_metadata: bool,
|
||||
|
||||
// actions on ingresses
|
||||
pub ingress_admin: bool, // applies to all ingress
|
||||
|
||||
// participant is not visible to other participants (useful when making bots)
|
||||
pub hidden: bool,
|
||||
|
||||
// indicates to the room that current participant is a recorder
|
||||
pub recorder: bool,
|
||||
}
|
||||
|
||||
impl Default for VideoGrants {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
room_create: false,
|
||||
room_list: false,
|
||||
room_record: false,
|
||||
room_admin: false,
|
||||
room_join: false,
|
||||
room: "".to_string(),
|
||||
can_publish: true,
|
||||
can_subscribe: true,
|
||||
can_publish_data: true,
|
||||
can_publish_sources: Vec::default(),
|
||||
can_update_own_metadata: false,
|
||||
ingress_admin: false,
|
||||
hidden: false,
|
||||
recorder: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Claims {
|
||||
pub exp: usize, // Expiration
|
||||
pub iss: String, // ApiKey
|
||||
pub nbf: usize,
|
||||
pub sub: String, // Identity
|
||||
|
||||
pub name: String,
|
||||
pub video: VideoGrants,
|
||||
pub sha256: String, // Used to verify the integrity of the message body
|
||||
pub metadata: String,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct AccessToken {
|
||||
api_key: String,
|
||||
api_secret: String,
|
||||
claims: Claims,
|
||||
}
|
||||
|
||||
impl Debug for AccessToken {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
// Don't show api_secret here
|
||||
f.debug_struct("AccessToken")
|
||||
.field("api_key", &self.api_key)
|
||||
.field("claims", &self.claims)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl AccessToken {
|
||||
pub fn with_api_key(api_key: &str, api_secret: &str) -> Self {
|
||||
let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
|
||||
Self {
|
||||
api_key: api_key.to_owned(),
|
||||
api_secret: api_secret.to_owned(),
|
||||
claims: Claims {
|
||||
exp: now.add(DEFAULT_TTL).as_secs() as usize,
|
||||
iss: api_key.to_owned(),
|
||||
nbf: now.as_secs() as usize,
|
||||
sub: Default::default(),
|
||||
name: Default::default(),
|
||||
video: VideoGrants::default(),
|
||||
sha256: Default::default(),
|
||||
metadata: Default::default(),
|
||||
},
|
||||
}
|
||||
}
|
||||
pub fn new() -> Result<Self, AccessTokenError> {
|
||||
// Try to get the API Key and the Secret Key from the environment
|
||||
let (api_key, api_secret) = get_env_keys()?;
|
||||
Ok(Self::with_api_key(&api_key, &api_secret))
|
||||
}
|
||||
|
||||
pub fn with_ttl(mut self, ttl: Duration) -> Self {
|
||||
let time = SystemTime::now().duration_since(UNIX_EPOCH).unwrap() + ttl;
|
||||
self.claims.exp = time.as_secs() as usize;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_grants(mut self, grants: VideoGrants) -> Self {
|
||||
self.claims.video = grants;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_identity(mut self, identity: &str) -> Self {
|
||||
self.claims.sub = identity.to_owned();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_name(mut self, name: &str) -> Self {
|
||||
self.claims.name = name.to_owned();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_metadata(mut self, metadata: &str) -> Self {
|
||||
self.claims.metadata = metadata.to_owned();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_sha256(mut self, sha256: &str) -> Self {
|
||||
self.claims.sha256 = sha256.to_owned();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn to_jwt(self) -> Result<String, AccessTokenError> {
|
||||
if self.api_key.is_empty() || self.api_secret.is_empty() {
|
||||
return Err(AccessTokenError::InvalidKeys);
|
||||
}
|
||||
|
||||
if self.claims.video.room_join && self.claims.sub.is_empty() {
|
||||
return Err(AccessTokenError::InvalidClaims(
|
||||
"token grants room_join but doesn't have an identity",
|
||||
));
|
||||
}
|
||||
|
||||
Ok(jsonwebtoken::encode(
|
||||
&Header::new(jsonwebtoken::Algorithm::HS256),
|
||||
&self.claims,
|
||||
&EncodingKey::from_secret(self.api_secret.as_ref()),
|
||||
)?)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct TokenVerifier {
|
||||
api_key: String,
|
||||
api_secret: String,
|
||||
}
|
||||
|
||||
impl Debug for TokenVerifier {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("TokenVerifier")
|
||||
.field("api_key", &self.api_key)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl TokenVerifier {
|
||||
pub fn with_api_key(api_key: &str, api_secret: &str) -> Self {
|
||||
Self {
|
||||
api_key: api_key.to_owned(),
|
||||
api_secret: api_secret.to_owned(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new() -> Result<Self, AccessTokenError> {
|
||||
let (api_key, api_secret) = get_env_keys()?;
|
||||
Ok(Self::with_api_key(&api_key, &api_secret))
|
||||
}
|
||||
|
||||
pub fn verify(&self, token: &str) -> Result<Claims, AccessTokenError> {
|
||||
let mut validation = jsonwebtoken::Validation::new(jsonwebtoken::Algorithm::HS256);
|
||||
validation.validate_exp = true;
|
||||
validation.validate_nbf = true;
|
||||
validation.set_issuer(&[&self.api_key]);
|
||||
|
||||
let token = jsonwebtoken::decode::<Claims>(
|
||||
token,
|
||||
&DecodingKey::from_secret(self.api_secret.as_ref()),
|
||||
&validation,
|
||||
)?;
|
||||
|
||||
Ok(token.claims)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{AccessToken, TokenVerifier, VideoGrants};
|
||||
use std::time::Duration;
|
||||
|
||||
const TEST_API_KEY: &str = "myapikey";
|
||||
const TEST_API_SECRET: &str = "thiskeyistotallyunsafe";
|
||||
|
||||
#[test]
|
||||
fn test_access_token() {
|
||||
let token = AccessToken::with_api_key(TEST_API_KEY, TEST_API_SECRET)
|
||||
.with_ttl(Duration::from_secs(60))
|
||||
.with_identity("test")
|
||||
.with_name("test")
|
||||
.with_grants(VideoGrants::default())
|
||||
.to_jwt()
|
||||
.unwrap();
|
||||
|
||||
let verifier = TokenVerifier::with_api_key(TEST_API_KEY, TEST_API_SECRET);
|
||||
let claims = verifier.verify(&token).unwrap();
|
||||
|
||||
assert_eq!(claims.sub, "test");
|
||||
assert_eq!(claims.name, "test");
|
||||
assert_eq!(claims.iss, TEST_API_KEY);
|
||||
|
||||
let incorrect_issuer = TokenVerifier::with_api_key("incorrect", TEST_API_SECRET);
|
||||
assert!(incorrect_issuer.verify(&token).is_err());
|
||||
|
||||
let incorrect_token = TokenVerifier::with_api_key(TEST_API_KEY, "incorrect");
|
||||
assert!(incorrect_token.verify(&token).is_err());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
pub mod access_token;
|
||||
pub mod services;
|
||||
pub mod webhook_receiver;
|
||||
|
||||
pub(crate) fn get_env_keys() -> Result<(String, String), std::env::VarError> {
|
||||
let api_key = std::env::var("LIVEKIT_API_KEY")?;
|
||||
let api_secret = std::env::var("LIVEKIT_API_SECRET")?;
|
||||
Ok((api_key, api_secret))
|
||||
}
|
||||
@@ -0,0 +1,423 @@
|
||||
use super::{ServiceBase, ServiceResult, LIVEKIT_PACKAGE};
|
||||
use crate::services::twirp_client::TwirpClient;
|
||||
use crate::{access_token::VideoGrants, get_env_keys};
|
||||
use livekit_protocol as proto;
|
||||
|
||||
#[derive(Default, Clone, Debug)]
|
||||
pub struct RoomCompositeOptions {
|
||||
pub layout: String,
|
||||
pub encoding: encoding::EncodingOptions,
|
||||
pub audio_only: bool,
|
||||
pub video_only: bool,
|
||||
pub custom_base_url: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Clone, Debug)]
|
||||
pub struct WebOptions {
|
||||
pub encoding: encoding::EncodingOptions,
|
||||
pub audio_only: bool,
|
||||
pub video_only: bool,
|
||||
}
|
||||
|
||||
#[derive(Default, Clone, Debug)]
|
||||
pub struct TrackCompositeOptions {
|
||||
pub encoding: encoding::EncodingOptions,
|
||||
pub audio_track_id: String,
|
||||
pub video_track_id: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum EgressOutput {
|
||||
File(proto::EncodedFileOutput),
|
||||
Stream(proto::StreamOutput),
|
||||
Segments(proto::SegmentedFileOutput),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum TrackEgressOutput {
|
||||
File(proto::DirectFileOutput),
|
||||
WebSocket(String),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum EgressListFilter {
|
||||
All,
|
||||
Egress(String),
|
||||
Room(String),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct EgressListOptions {
|
||||
pub filter: EgressListFilter,
|
||||
pub active: bool,
|
||||
}
|
||||
|
||||
const SVC: &'static str = "Egress";
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct EgressClient {
|
||||
base: ServiceBase,
|
||||
client: TwirpClient,
|
||||
}
|
||||
|
||||
impl EgressClient {
|
||||
pub fn with_api_key(host: &str, api_key: &str, api_secret: &str) -> Self {
|
||||
Self {
|
||||
base: ServiceBase::with_api_key(api_key, api_secret),
|
||||
client: TwirpClient::new(host, LIVEKIT_PACKAGE, None),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(host: &str) -> ServiceResult<Self> {
|
||||
let (api_key, api_secret) = get_env_keys()?;
|
||||
Ok(Self::with_api_key(host, &api_key, &api_secret))
|
||||
}
|
||||
|
||||
pub async fn start_room_composite_egress(
|
||||
&self,
|
||||
room: &str,
|
||||
outputs: Vec<EgressOutput>,
|
||||
options: RoomCompositeOptions,
|
||||
) -> ServiceResult<proto::EgressInfo> {
|
||||
let (file_outputs, stream_outputs, segment_outputs) = get_outputs(outputs);
|
||||
self.client
|
||||
.request(
|
||||
SVC,
|
||||
"StartRoomCompositeEgress",
|
||||
proto::RoomCompositeEgressRequest {
|
||||
room_name: room.to_string(),
|
||||
layout: options.layout,
|
||||
audio_only: options.audio_only,
|
||||
video_only: options.video_only,
|
||||
options: Some(proto::room_composite_egress_request::Options::Advanced(
|
||||
options.encoding.into(),
|
||||
)),
|
||||
custom_base_url: options.custom_base_url,
|
||||
file_outputs,
|
||||
stream_outputs,
|
||||
segment_outputs,
|
||||
output: None, // Deprecated
|
||||
},
|
||||
self.base.auth_header(VideoGrants {
|
||||
room_record: true,
|
||||
..Default::default()
|
||||
})?,
|
||||
)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
pub async fn start_web_egress(
|
||||
&self,
|
||||
url: &str,
|
||||
outputs: Vec<EgressOutput>,
|
||||
options: WebOptions,
|
||||
) -> ServiceResult<proto::EgressInfo> {
|
||||
let (file_outputs, stream_outputs, segment_outputs) = get_outputs(outputs);
|
||||
self.client
|
||||
.request(
|
||||
SVC,
|
||||
"StartWebEgress",
|
||||
proto::WebEgressRequest {
|
||||
url: url.to_string(),
|
||||
options: Some(proto::web_egress_request::Options::Advanced(
|
||||
options.encoding.into(),
|
||||
)),
|
||||
audio_only: options.audio_only,
|
||||
video_only: options.video_only,
|
||||
file_outputs,
|
||||
stream_outputs,
|
||||
segment_outputs,
|
||||
output: None, // Deprecated
|
||||
},
|
||||
self.base.auth_header(VideoGrants {
|
||||
room_record: true,
|
||||
..Default::default()
|
||||
})?,
|
||||
)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
pub async fn start_track_composite_egress(
|
||||
&self,
|
||||
room: &str,
|
||||
outputs: Vec<EgressOutput>,
|
||||
options: TrackCompositeOptions,
|
||||
) -> ServiceResult<proto::EgressInfo> {
|
||||
let (file_outputs, stream_outputs, segment_outputs) = get_outputs(outputs);
|
||||
self.client
|
||||
.request(
|
||||
SVC,
|
||||
"StartTrackCompositeEgress",
|
||||
proto::TrackCompositeEgressRequest {
|
||||
room_name: room.to_string(),
|
||||
options: Some(proto::track_composite_egress_request::Options::Advanced(
|
||||
options.encoding.into(),
|
||||
)),
|
||||
audio_track_id: options.audio_track_id,
|
||||
video_track_id: options.video_track_id,
|
||||
file_outputs,
|
||||
stream_outputs,
|
||||
segment_outputs,
|
||||
output: None, // Deprecated
|
||||
},
|
||||
self.base.auth_header(VideoGrants {
|
||||
room_record: true,
|
||||
..Default::default()
|
||||
})?,
|
||||
)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
pub async fn start_track_egress(
|
||||
&self,
|
||||
room: &str,
|
||||
output: TrackEgressOutput,
|
||||
track_id: &str,
|
||||
) -> ServiceResult<proto::EgressInfo> {
|
||||
self.client
|
||||
.request(
|
||||
SVC,
|
||||
"StartTrackEgress",
|
||||
proto::TrackEgressRequest {
|
||||
room_name: room.to_string(),
|
||||
output: match output {
|
||||
TrackEgressOutput::File(f) => {
|
||||
Some(proto::track_egress_request::Output::File(f))
|
||||
}
|
||||
TrackEgressOutput::WebSocket(url) => {
|
||||
Some(proto::track_egress_request::Output::WebsocketUrl(url))
|
||||
}
|
||||
},
|
||||
track_id: track_id.to_string(),
|
||||
},
|
||||
self.base.auth_header(VideoGrants {
|
||||
room_record: true,
|
||||
..Default::default()
|
||||
})?,
|
||||
)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
pub async fn update_layout(
|
||||
&self,
|
||||
egress_id: &str,
|
||||
layout: &str,
|
||||
) -> ServiceResult<proto::EgressInfo> {
|
||||
self.client
|
||||
.request(
|
||||
SVC,
|
||||
"UpdateLayout",
|
||||
proto::UpdateLayoutRequest {
|
||||
egress_id: egress_id.to_owned(),
|
||||
layout: layout.to_owned(),
|
||||
},
|
||||
self.base.auth_header(VideoGrants {
|
||||
room_record: true,
|
||||
..Default::default()
|
||||
})?,
|
||||
)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
pub async fn update_stream(
|
||||
&self,
|
||||
egress_id: &str,
|
||||
add_output_urls: Vec<String>,
|
||||
remove_output_urls: Vec<String>,
|
||||
) -> ServiceResult<proto::EgressInfo> {
|
||||
self.client
|
||||
.request(
|
||||
SVC,
|
||||
"UpdateStream",
|
||||
proto::UpdateStreamRequest {
|
||||
egress_id: egress_id.to_owned(),
|
||||
add_output_urls,
|
||||
remove_output_urls,
|
||||
},
|
||||
self.base.auth_header(VideoGrants {
|
||||
room_record: true,
|
||||
..Default::default()
|
||||
})?,
|
||||
)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
pub async fn list_egress(
|
||||
&self,
|
||||
options: EgressListOptions,
|
||||
) -> ServiceResult<Vec<proto::EgressInfo>> {
|
||||
let mut room_name = String::default();
|
||||
let mut egress_id = String::default();
|
||||
|
||||
match options.filter {
|
||||
EgressListFilter::Room(room) => room_name = room,
|
||||
EgressListFilter::Egress(egress) => egress_id = egress,
|
||||
_ => {}
|
||||
}
|
||||
|
||||
let resp: proto::ListEgressResponse = self
|
||||
.client
|
||||
.request(
|
||||
SVC,
|
||||
"ListEgress",
|
||||
proto::ListEgressRequest {
|
||||
room_name,
|
||||
egress_id,
|
||||
active: options.active,
|
||||
},
|
||||
self.base.auth_header(VideoGrants {
|
||||
room_record: true,
|
||||
..Default::default()
|
||||
})?,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(resp.items)
|
||||
}
|
||||
|
||||
pub async fn stop_egress(&self, egress_id: &str) -> ServiceResult<proto::EgressInfo> {
|
||||
self.client
|
||||
.request(
|
||||
SVC,
|
||||
"StopEgress",
|
||||
proto::StopEgressRequest {
|
||||
egress_id: egress_id.to_owned(),
|
||||
},
|
||||
self.base.auth_header(VideoGrants {
|
||||
room_record: true,
|
||||
..Default::default()
|
||||
})?,
|
||||
)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
fn get_outputs(
|
||||
outputs: Vec<EgressOutput>,
|
||||
) -> (
|
||||
Vec<proto::EncodedFileOutput>,
|
||||
Vec<proto::StreamOutput>,
|
||||
Vec<proto::SegmentedFileOutput>,
|
||||
) {
|
||||
let mut file_outputs = Vec::new();
|
||||
let mut stream_outputs = Vec::new();
|
||||
let mut segment_outputs = Vec::new();
|
||||
|
||||
for output in outputs {
|
||||
match output {
|
||||
EgressOutput::File(f) => file_outputs.push(f),
|
||||
EgressOutput::Stream(s) => stream_outputs.push(s),
|
||||
EgressOutput::Segments(s) => segment_outputs.push(s),
|
||||
}
|
||||
}
|
||||
|
||||
(file_outputs, stream_outputs, segment_outputs)
|
||||
}
|
||||
|
||||
pub mod encoding {
|
||||
use super::*;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct EncodingOptions {
|
||||
pub width: i32,
|
||||
pub height: i32,
|
||||
pub depth: i32,
|
||||
pub framerate: i32,
|
||||
pub audio_codec: proto::AudioCodec,
|
||||
pub audio_bitrate: i32,
|
||||
pub audio_frequency: i32,
|
||||
pub video_codec: proto::VideoCodec,
|
||||
pub video_bitrate: i32,
|
||||
pub keyframe_interval: f64,
|
||||
}
|
||||
|
||||
impl From<EncodingOptions> for proto::EncodingOptions {
|
||||
fn from(opts: EncodingOptions) -> Self {
|
||||
Self {
|
||||
width: opts.width,
|
||||
height: opts.height,
|
||||
depth: opts.depth,
|
||||
framerate: opts.framerate,
|
||||
audio_codec: opts.audio_codec as i32,
|
||||
audio_bitrate: opts.audio_bitrate,
|
||||
audio_frequency: opts.audio_frequency,
|
||||
video_codec: opts.video_codec as i32,
|
||||
video_bitrate: opts.video_bitrate,
|
||||
key_frame_interval: opts.keyframe_interval,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl EncodingOptions {
|
||||
const fn new() -> Self {
|
||||
Self {
|
||||
width: 1920,
|
||||
height: 1080,
|
||||
depth: 24,
|
||||
framerate: 30,
|
||||
audio_codec: proto::AudioCodec::Opus,
|
||||
audio_bitrate: 128,
|
||||
audio_frequency: 44100,
|
||||
video_codec: proto::VideoCodec::H264Main,
|
||||
video_bitrate: 4500,
|
||||
keyframe_interval: 0.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for EncodingOptions {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
pub const H264_720P_30: EncodingOptions = EncodingOptions {
|
||||
width: 1280,
|
||||
height: 720,
|
||||
video_bitrate: 3000,
|
||||
..EncodingOptions::new()
|
||||
};
|
||||
pub const H264_720P_60: EncodingOptions = EncodingOptions {
|
||||
width: 1280,
|
||||
height: 720,
|
||||
framerate: 60,
|
||||
..EncodingOptions::new()
|
||||
};
|
||||
pub const H264_1080P_30: EncodingOptions = EncodingOptions::new();
|
||||
pub const H264_1080P_60: EncodingOptions = EncodingOptions {
|
||||
framerate: 60,
|
||||
video_bitrate: 6000,
|
||||
..EncodingOptions::new()
|
||||
};
|
||||
pub const PORTRAIT_H264_720P_30: EncodingOptions = EncodingOptions {
|
||||
width: 720,
|
||||
height: 1280,
|
||||
video_bitrate: 3000,
|
||||
..EncodingOptions::new()
|
||||
};
|
||||
pub const PORTRAIT_H264_720P_60: EncodingOptions = EncodingOptions {
|
||||
width: 720,
|
||||
height: 1280,
|
||||
framerate: 60,
|
||||
..EncodingOptions::new()
|
||||
};
|
||||
pub const PORTRAIT_H264_1080P_30: EncodingOptions = EncodingOptions {
|
||||
width: 1080,
|
||||
height: 1920,
|
||||
..EncodingOptions::new()
|
||||
};
|
||||
pub const PORTRAIT_H264_1080P_60: EncodingOptions = EncodingOptions {
|
||||
width: 1080,
|
||||
height: 1920,
|
||||
framerate: 60,
|
||||
video_bitrate: 6000,
|
||||
..EncodingOptions::new()
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
use super::{ServiceBase, ServiceResult, LIVEKIT_PACKAGE};
|
||||
use crate::services::twirp_client::TwirpClient;
|
||||
use crate::{access_token::VideoGrants, get_env_keys};
|
||||
use livekit_protocol as proto;
|
||||
|
||||
#[derive(Default, Clone, Debug)]
|
||||
pub struct IngressOptions {
|
||||
pub name: String,
|
||||
pub room_name: String,
|
||||
pub participant_identity: String,
|
||||
pub participant_name: String,
|
||||
pub audio: proto::IngressAudioOptions,
|
||||
pub video: proto::IngressVideoOptions,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum IngressListFilter {
|
||||
All,
|
||||
Room(String),
|
||||
}
|
||||
|
||||
const SVC: &'static str = "Ingress";
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct IngressClient {
|
||||
base: ServiceBase,
|
||||
client: TwirpClient,
|
||||
}
|
||||
|
||||
impl IngressClient {
|
||||
pub fn with_api_key(host: &str, api_key: &str, api_secret: &str) -> Self {
|
||||
Self {
|
||||
base: ServiceBase::with_api_key(api_key, api_secret),
|
||||
client: TwirpClient::new(host, LIVEKIT_PACKAGE, None),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(host: &str) -> ServiceResult<Self> {
|
||||
let (api_key, api_secret) = get_env_keys()?;
|
||||
Ok(Self::with_api_key(host, &api_key, &api_secret))
|
||||
}
|
||||
|
||||
pub async fn create_ingress(
|
||||
&self,
|
||||
input_type: proto::IngressInput,
|
||||
options: IngressOptions,
|
||||
) -> ServiceResult<proto::IngressInfo> {
|
||||
self.client
|
||||
.request(
|
||||
SVC,
|
||||
"CreateIngress",
|
||||
proto::CreateIngressRequest {
|
||||
input_type: input_type as i32,
|
||||
name: options.name,
|
||||
room_name: options.room_name,
|
||||
participant_identity: options.participant_identity,
|
||||
participant_name: options.participant_name,
|
||||
audio: Some(options.audio),
|
||||
video: Some(options.video),
|
||||
},
|
||||
self.base.auth_header(VideoGrants {
|
||||
ingress_admin: true,
|
||||
..Default::default()
|
||||
})?,
|
||||
)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
pub async fn update_ingress(
|
||||
&self,
|
||||
ingress_id: &str,
|
||||
options: IngressOptions,
|
||||
) -> ServiceResult<proto::IngressInfo> {
|
||||
self.client
|
||||
.request(
|
||||
SVC,
|
||||
"UpdateIngress",
|
||||
proto::UpdateIngressRequest {
|
||||
ingress_id: ingress_id.to_owned(),
|
||||
name: options.name,
|
||||
room_name: options.room_name,
|
||||
participant_identity: options.participant_identity,
|
||||
participant_name: options.participant_name,
|
||||
audio: Some(options.audio),
|
||||
video: Some(options.video),
|
||||
},
|
||||
self.base.auth_header(VideoGrants {
|
||||
ingress_admin: true,
|
||||
..Default::default()
|
||||
})?,
|
||||
)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
pub async fn list_ingress(
|
||||
&self,
|
||||
filter: IngressListFilter,
|
||||
) -> ServiceResult<Vec<proto::IngressInfo>> {
|
||||
let resp: proto::ListIngressResponse = self
|
||||
.client
|
||||
.request(
|
||||
SVC,
|
||||
"ListIngress",
|
||||
proto::ListIngressRequest {
|
||||
room_name: match filter{
|
||||
IngressListFilter::All => Default::default(),
|
||||
IngressListFilter::Room(room) => room,
|
||||
},
|
||||
},
|
||||
self.base.auth_header(VideoGrants {
|
||||
ingress_admin: true,
|
||||
..Default::default()
|
||||
})?,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(resp.items)
|
||||
}
|
||||
|
||||
pub async fn delete_ingress(&self, ingress_id: &str) -> ServiceResult<proto::IngressInfo> {
|
||||
self.client
|
||||
.request(
|
||||
SVC,
|
||||
"DeleteIngress",
|
||||
proto::DeleteIngressRequest {
|
||||
ingress_id: ingress_id.to_owned(),
|
||||
},
|
||||
self.base.auth_header(VideoGrants {
|
||||
ingress_admin: true,
|
||||
..Default::default()
|
||||
})?,
|
||||
)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
use crate::access_token::{AccessToken, AccessTokenError, VideoGrants};
|
||||
use reqwest::header::{HeaderMap, HeaderValue, AUTHORIZATION};
|
||||
use std::fmt::Debug;
|
||||
use thiserror::Error;
|
||||
|
||||
pub mod room;
|
||||
pub mod egress;
|
||||
pub mod ingress;
|
||||
|
||||
mod twirp_client;
|
||||
|
||||
pub const LIVEKIT_PACKAGE: &'static str = "livekit";
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ServiceError {
|
||||
#[error("invalid environment: {0}")]
|
||||
Env(#[from] std::env::VarError),
|
||||
#[error("invalid access token: {0}")]
|
||||
AccessToken(#[from] AccessTokenError),
|
||||
#[error("twirp error: {0}")]
|
||||
Twirp(#[from] twirp_client::TwirpError),
|
||||
}
|
||||
|
||||
pub type ServiceResult<T> = Result<T, ServiceError>;
|
||||
|
||||
struct ServiceBase {
|
||||
api_key: String,
|
||||
api_secret: String,
|
||||
}
|
||||
|
||||
impl Debug for ServiceBase {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("ServiceBase")
|
||||
.field("api_key", &self.api_key)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl ServiceBase {
|
||||
pub fn with_api_key(api_key: &str, api_secret: &str) -> Self {
|
||||
Self {
|
||||
api_key: api_key.to_owned(),
|
||||
api_secret: api_secret.to_owned(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn auth_header(&self, grants: VideoGrants) -> Result<HeaderMap, AccessTokenError> {
|
||||
let token = AccessToken::with_api_key(&self.api_key, &self.api_secret)
|
||||
.with_grants(grants)
|
||||
.to_jwt()?;
|
||||
|
||||
let mut headers = HeaderMap::new();
|
||||
headers.insert(
|
||||
AUTHORIZATION,
|
||||
HeaderValue::from_str(&format!("Bearer {}", token)).unwrap(),
|
||||
);
|
||||
Ok(headers)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,308 @@
|
||||
use super::{ServiceBase, ServiceResult, LIVEKIT_PACKAGE};
|
||||
use crate::services::twirp_client::TwirpClient;
|
||||
use crate::{access_token::VideoGrants, get_env_keys};
|
||||
use livekit_protocol as proto;
|
||||
|
||||
const SVC: &'static str = "RoomService";
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct CreateRoomOptions {
|
||||
pub empty_timeout: u32,
|
||||
pub max_participants: u32,
|
||||
pub node_id: String,
|
||||
pub metadata: String,
|
||||
pub egress: Option<proto::RoomEgress>, // TODO(theomonnom): Better API?
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct UpdateParticipantOptions {
|
||||
pub metadata: String,
|
||||
pub permission: Option<proto::ParticipantPermission>,
|
||||
pub name: String, // No effect if left empty
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct SendDataOptions {
|
||||
pub kind: proto::data_packet::Kind,
|
||||
pub destination_sids: Vec<String>,
|
||||
pub topic: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RoomClient {
|
||||
base: ServiceBase,
|
||||
client: TwirpClient,
|
||||
}
|
||||
|
||||
impl RoomClient {
|
||||
pub fn with_api_key(host: &str, api_key: &str, api_secret: &str) -> Self {
|
||||
Self {
|
||||
base: ServiceBase::with_api_key(api_key, api_secret),
|
||||
client: TwirpClient::new(host, LIVEKIT_PACKAGE, None),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(host: &str) -> ServiceResult<Self> {
|
||||
let (api_key, api_secret) = get_env_keys()?;
|
||||
Ok(Self::with_api_key(host, &api_key, &api_secret))
|
||||
}
|
||||
|
||||
pub async fn create_room(
|
||||
&self,
|
||||
name: &str,
|
||||
options: CreateRoomOptions,
|
||||
) -> ServiceResult<proto::Room> {
|
||||
self.client
|
||||
.request(
|
||||
SVC,
|
||||
"CreateRoom",
|
||||
proto::CreateRoomRequest {
|
||||
name: name.to_owned(),
|
||||
empty_timeout: options.empty_timeout,
|
||||
max_participants: options.max_participants,
|
||||
node_id: options.node_id,
|
||||
metadata: options.metadata,
|
||||
egress: options.egress,
|
||||
},
|
||||
self.base.auth_header(VideoGrants {
|
||||
room_create: true,
|
||||
..Default::default()
|
||||
})?,
|
||||
)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
pub async fn list_rooms(&self, names: Vec<String>) -> ServiceResult<Vec<proto::Room>> {
|
||||
let resp: proto::ListRoomsResponse = self
|
||||
.client
|
||||
.request(
|
||||
SVC,
|
||||
"ListRooms",
|
||||
proto::ListRoomsRequest { names },
|
||||
self.base.auth_header(VideoGrants {
|
||||
room_list: true,
|
||||
..Default::default()
|
||||
})?,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(resp.rooms)
|
||||
}
|
||||
|
||||
pub async fn delete_room(&self, room: &str) -> ServiceResult<()> {
|
||||
self.client
|
||||
.request(
|
||||
SVC,
|
||||
"DeleteRoom",
|
||||
proto::DeleteRoomRequest {
|
||||
room: room.to_owned(),
|
||||
},
|
||||
self.base.auth_header(VideoGrants {
|
||||
room_create: true,
|
||||
..Default::default()
|
||||
})?,
|
||||
)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
pub async fn update_room_metadata(
|
||||
&self,
|
||||
room: &str,
|
||||
metadata: &str,
|
||||
) -> ServiceResult<proto::Room> {
|
||||
self.client
|
||||
.request(
|
||||
SVC,
|
||||
"UpdateRoomMetadata",
|
||||
proto::UpdateRoomMetadataRequest {
|
||||
room: room.to_owned(),
|
||||
metadata: metadata.to_owned(),
|
||||
},
|
||||
self.base.auth_header(VideoGrants {
|
||||
room_admin: true,
|
||||
room: room.to_owned(),
|
||||
..Default::default()
|
||||
})?,
|
||||
)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
pub async fn list_participants(
|
||||
&self,
|
||||
room: &str,
|
||||
) -> ServiceResult<Vec<proto::ParticipantInfo>> {
|
||||
let resp: proto::ListParticipantsResponse = self
|
||||
.client
|
||||
.request(
|
||||
SVC,
|
||||
"ListParticipants",
|
||||
proto::ListParticipantsRequest {
|
||||
room: room.to_owned(),
|
||||
},
|
||||
self.base.auth_header(VideoGrants {
|
||||
room_admin: true,
|
||||
room: room.to_owned(),
|
||||
..Default::default()
|
||||
})?,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(resp.participants)
|
||||
}
|
||||
|
||||
pub async fn get_participant(
|
||||
&self,
|
||||
room: &str,
|
||||
identity: &str,
|
||||
) -> ServiceResult<proto::ParticipantInfo> {
|
||||
self.client
|
||||
.request(
|
||||
SVC,
|
||||
"GetParticipant",
|
||||
proto::RoomParticipantIdentity {
|
||||
room: room.to_owned(),
|
||||
identity: identity.to_owned(),
|
||||
},
|
||||
self.base.auth_header(VideoGrants {
|
||||
room_admin: true,
|
||||
room: room.to_owned(),
|
||||
..Default::default()
|
||||
})?,
|
||||
)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
pub async fn remove_participant(&self, room: &str, identity: &str) -> ServiceResult<()> {
|
||||
self.client
|
||||
.request(
|
||||
SVC,
|
||||
"RemoveParticipant",
|
||||
proto::RoomParticipantIdentity {
|
||||
room: room.to_owned(),
|
||||
identity: identity.to_owned(),
|
||||
},
|
||||
self.base.auth_header(VideoGrants {
|
||||
room_admin: true,
|
||||
room: room.to_owned(),
|
||||
..Default::default()
|
||||
})?,
|
||||
)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
pub async fn mute_published_track(
|
||||
&self,
|
||||
room: &str,
|
||||
identity: &str,
|
||||
track_sid: &str,
|
||||
muted: bool,
|
||||
) -> ServiceResult<proto::TrackInfo> {
|
||||
let resp: proto::MuteRoomTrackResponse = self
|
||||
.client
|
||||
.request(
|
||||
SVC,
|
||||
"MutePublishedTrack",
|
||||
proto::MuteRoomTrackRequest {
|
||||
room: room.to_owned(),
|
||||
identity: identity.to_owned(),
|
||||
track_sid: track_sid.to_owned(),
|
||||
muted,
|
||||
},
|
||||
self.base.auth_header(VideoGrants {
|
||||
room_admin: true,
|
||||
room: room.to_owned(),
|
||||
..Default::default()
|
||||
})?,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(resp.track.unwrap())
|
||||
}
|
||||
|
||||
pub async fn update_participant(
|
||||
&self,
|
||||
room: &str,
|
||||
identity: &str,
|
||||
options: UpdateParticipantOptions,
|
||||
) -> ServiceResult<proto::ParticipantInfo> {
|
||||
self.client
|
||||
.request(
|
||||
SVC,
|
||||
"UpdateParticipant",
|
||||
proto::UpdateParticipantRequest {
|
||||
room: room.to_owned(),
|
||||
identity: identity.to_owned(),
|
||||
permission: options.permission,
|
||||
metadata: options.metadata,
|
||||
name: options.name,
|
||||
},
|
||||
self.base.auth_header(VideoGrants {
|
||||
room_admin: true,
|
||||
room: room.to_owned(),
|
||||
..Default::default()
|
||||
})?,
|
||||
)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
pub async fn update_subscriptions(
|
||||
&self,
|
||||
room: &str,
|
||||
identity: &str,
|
||||
track_sids: Vec<String>,
|
||||
subscribe: bool,
|
||||
) -> ServiceResult<()> {
|
||||
self.client
|
||||
.request(
|
||||
SVC,
|
||||
"UpdateSubscriptions",
|
||||
proto::UpdateSubscriptionsRequest {
|
||||
room: room.to_owned(),
|
||||
identity: identity.to_owned(),
|
||||
track_sids,
|
||||
subscribe,
|
||||
..Default::default()
|
||||
},
|
||||
self.base.auth_header(VideoGrants {
|
||||
room_admin: true,
|
||||
room: room.to_owned(),
|
||||
..Default::default()
|
||||
})?,
|
||||
)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
pub async fn send_data(
|
||||
&self,
|
||||
room: &str,
|
||||
data: Vec<u8>,
|
||||
options: SendDataOptions,
|
||||
) -> ServiceResult<()> {
|
||||
self.client
|
||||
.request(
|
||||
SVC,
|
||||
"SendData",
|
||||
proto::SendDataRequest {
|
||||
room: room.to_owned(),
|
||||
data,
|
||||
destination_sids: options.destination_sids,
|
||||
topic: options.topic,
|
||||
kind: options.kind as i32,
|
||||
},
|
||||
self.base.auth_header(VideoGrants {
|
||||
room_admin: true,
|
||||
room: room.to_owned(),
|
||||
..Default::default()
|
||||
})?,
|
||||
)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
use reqwest::{
|
||||
header::{HeaderMap, HeaderValue, CONTENT_TYPE},
|
||||
StatusCode,
|
||||
};
|
||||
use serde::Deserialize;
|
||||
use std::fmt::Display;
|
||||
use thiserror::Error;
|
||||
|
||||
pub const DEFAULT_PREFIX: &str = "/twirp";
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum TwirpError {
|
||||
#[error("failed to execute the request: {0}")]
|
||||
Request(#[from] reqwest::Error),
|
||||
#[error("twirp error: {0}")]
|
||||
Twirp(TwirpErrorCode),
|
||||
#[error("url error: {0}")]
|
||||
Url(#[from] url::ParseError),
|
||||
#[error("prost error: {0}")]
|
||||
Prost(#[from] prost::DecodeError),
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct TwirpErrorCode {
|
||||
pub code: String,
|
||||
pub msg: String,
|
||||
}
|
||||
|
||||
impl TwirpErrorCode {
|
||||
pub const CANCELED: &'static str = "canceled";
|
||||
pub const UNKNOWN: &'static str = "unknown";
|
||||
pub const INVALID_ARGUMENT: &'static str = "invalid_argument";
|
||||
pub const MALFORMED: &'static str = "malformed";
|
||||
pub const DEADLINE_EXCEEDED: &'static str = "deadline_exceeded";
|
||||
pub const NOT_FOUND: &'static str = "not_found";
|
||||
pub const BAD_ROUTE: &'static str = "bad_route";
|
||||
pub const ALREADY_EXISTS: &'static str = "already_exists";
|
||||
pub const PERMISSION_DENIED: &'static str = "permission_denied";
|
||||
pub const UNAUTHENTICATED: &'static str = "unauthenticated";
|
||||
pub const RESOURCE_EXHAUSTED: &'static str = "resource_exhausted";
|
||||
pub const FAILED_PRECONDITION: &'static str = "failed_precondition";
|
||||
pub const ABORTED: &'static str = "aborted";
|
||||
pub const OUT_OF_RANGE: &'static str = "out_of_range";
|
||||
pub const UNIMPLEMENTED: &'static str = "unimplemented";
|
||||
pub const INTERNAL: &'static str = "internal";
|
||||
pub const UNAVAILABLE: &'static str = "unavailable";
|
||||
pub const DATA_LOSS: &'static str = "dataloss";
|
||||
}
|
||||
|
||||
impl Display for TwirpErrorCode {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}: {}", self.code, self.msg)
|
||||
}
|
||||
}
|
||||
|
||||
pub type TwirpResult<T> = Result<T, TwirpError>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TwirpClient {
|
||||
host: String,
|
||||
pkg: String,
|
||||
prefix: String,
|
||||
client: reqwest::Client,
|
||||
}
|
||||
|
||||
impl TwirpClient {
|
||||
pub fn new(host: &str, pkg: &str, prefix: Option<&str>) -> Self {
|
||||
Self {
|
||||
host: host.to_owned(),
|
||||
pkg: pkg.to_owned(),
|
||||
prefix: prefix.unwrap_or(DEFAULT_PREFIX).to_owned(),
|
||||
client: reqwest::Client::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn request<D: prost::Message, R: prost::Message + Default>(
|
||||
&self,
|
||||
service: &str,
|
||||
method: &str,
|
||||
data: D,
|
||||
mut headers: HeaderMap,
|
||||
) -> TwirpResult<R> {
|
||||
let mut url = url::Url::parse(&self.host)?;
|
||||
url.set_path(&format!(
|
||||
"{}/{}.{}/{}",
|
||||
self.prefix, self.pkg, service, method
|
||||
));
|
||||
|
||||
headers.insert(
|
||||
CONTENT_TYPE,
|
||||
HeaderValue::from_static("application/protobuf"),
|
||||
);
|
||||
|
||||
let resp = self
|
||||
.client
|
||||
.post(url)
|
||||
.headers(headers)
|
||||
.body(data.encode_to_vec())
|
||||
.send()
|
||||
.await?;
|
||||
|
||||
if resp.status() == StatusCode::OK {
|
||||
Ok(R::decode(resp.bytes().await?)?)
|
||||
} else {
|
||||
let err: TwirpErrorCode = resp.json().await?;
|
||||
Err(TwirpError::Twirp(err))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
// Webhooks are not yet integrated into the Rust SDK.
|
||||
// Our webhooks protocol use protojson which isn't supported by Prost
|
||||
|
||||
/*
|
||||
use crate::access_token::{AccessTokenError, TokenVerifier};
|
||||
use livekit_protocol as proto;
|
||||
use serde_json;
|
||||
use sha2::{Digest, Sha256};
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum WebhookError {
|
||||
#[error("invalid signature")]
|
||||
InvalidSignature,
|
||||
#[error("failed to verify the authorization: {0}")]
|
||||
InvalidAuth(#[from] AccessTokenError),
|
||||
#[error("invalid body, failed to decode: {0}")]
|
||||
InvalidData(#[from] serde_json::Error),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct WebhookReceiver {
|
||||
token_verifier: TokenVerifier,
|
||||
}
|
||||
|
||||
impl WebhookReceiver {
|
||||
pub fn new(token_verifier: TokenVerifier) -> Self {
|
||||
Self { token_verifier }
|
||||
}
|
||||
|
||||
pub fn receive(
|
||||
&self,
|
||||
body: &str,
|
||||
auth_token: &str,
|
||||
) -> Result<proto::WebhookEvent, WebhookError> {
|
||||
let claims = self.token_verifier.verify(auth_token)?;
|
||||
|
||||
let mut hasher = Sha256::new();
|
||||
hasher.update(body);
|
||||
let hash = hasher.finalize();
|
||||
|
||||
let hex: Result<Vec<u8>, std::num::ParseIntError> = (0..claims.sha256.len())
|
||||
.step_by(2)
|
||||
.map(|i| u8::from_str_radix(&claims.sha256[i..i + 2], 16))
|
||||
.collect();
|
||||
|
||||
let hex = hex.map_err(|_| WebhookError::InvalidSignature)?; // Failed to parse
|
||||
|
||||
if &hex[..] != &hash[..] {
|
||||
return Err(WebhookError::InvalidSignature);
|
||||
}
|
||||
|
||||
Ok(serde_json::from_str(body)?)
|
||||
}
|
||||
}*/
|
||||
@@ -8,6 +8,7 @@ repository = "https://github.com/livekit/client-sdk-rust"
|
||||
|
||||
[dependencies]
|
||||
livekit = { path = "../livekit", version = "0.1.1" }
|
||||
livekit-protocol = { path = "../livekit-protocol", version = "0.1.0" }
|
||||
tokio = { version = "1.0", features = ["full"] }
|
||||
parking_lot = { version = "0.12.1", features = ["send_guard"] }
|
||||
prost = "0.11.0"
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use crate::{proto, server::FFIHandleId};
|
||||
use crate::server::FFIHandleId;
|
||||
use livekit::prelude::*;
|
||||
use livekit::webrtc::prelude::*;
|
||||
use std::any::Any;
|
||||
use crate::proto;
|
||||
|
||||
pub mod participant;
|
||||
pub mod publication;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::{proto, server::FFIHandleId};
|
||||
use crate::proto;
|
||||
use crate::server::FFIHandleId;
|
||||
use livekit::webrtc::prelude::*;
|
||||
use livekit::webrtc::video_frame;
|
||||
use std::any::Any;
|
||||
|
||||
macro_rules! impl_yuv_into {
|
||||
(@fields, $buffer:ident, $data_y:ident, $data_u:ident, $data_v: ident) => {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::proto;
|
||||
use lazy_static::lazy_static;
|
||||
use livekit::prelude::*;
|
||||
use livekit::webrtc::video_frame::{native::VideoFrameBufferExt, BoxVideoFrame, VideoFrameBuffer};
|
||||
use crate::proto;
|
||||
use parking_lot::{Mutex, RwLock};
|
||||
use prost::Message;
|
||||
use std::any::Any;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use crate::proto;
|
||||
use crate::server::FFIServer;
|
||||
use futures_util::stream::StreamExt;
|
||||
use livekit::prelude::*;
|
||||
use livekit::webrtc::video_stream::native::NativeVideoStream;
|
||||
use tokio::sync::{mpsc, oneshot};
|
||||
use crate::proto;
|
||||
|
||||
pub async fn create_room(
|
||||
server: &'static FFIServer,
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
[package]
|
||||
name = "livekit-protocol"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
tokio = { version = "1.26.0", features = ["full"] }
|
||||
futures-util = "0.3"
|
||||
parking_lot = "0.12"
|
||||
prost = "0.11"
|
||||
prost-types = "0.11"
|
||||
|
||||
[build-dependencies]
|
||||
prost-build = { version = "0.11.1" }
|
||||
@@ -0,0 +1,16 @@
|
||||
use std::io::Result;
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let mut prost_build = prost_build::Config::new();
|
||||
prost_build.compile_protos(
|
||||
&[
|
||||
"protocol/livekit_egress.proto",
|
||||
"protocol/livekit_rtc.proto",
|
||||
"protocol/livekit_room.proto",
|
||||
"protocol/livekit_webhook.proto",
|
||||
"protocol/livekit_models.proto",
|
||||
],
|
||||
&["protocol/"],
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
Submodule
+1
Submodule livekit-protocol/protocol added at 1e793a8870
@@ -0,0 +1,8 @@
|
||||
pub mod observer;
|
||||
pub mod enum_dispatch;
|
||||
|
||||
pub mod livekit {
|
||||
include!(concat!(env!("OUT_DIR"), "/livekit.rs"));
|
||||
}
|
||||
|
||||
pub use livekit::*;
|
||||
@@ -1,12 +0,0 @@
|
||||
[package]
|
||||
name = "livekit-utils"
|
||||
version = "0.1.1"
|
||||
edition = "2021"
|
||||
license = "Apache-2.0"
|
||||
description = "Shared utilities for livekit"
|
||||
repository = "https://github.com/livekit/client-sdk-rust"
|
||||
|
||||
[dependencies]
|
||||
tokio = { version = "1.26.0", features = ["full"] }
|
||||
futures-util = "0.3"
|
||||
parking_lot = "0.12"
|
||||
@@ -1,2 +0,0 @@
|
||||
pub mod enum_dispatch;
|
||||
pub mod observer;
|
||||
@@ -8,21 +8,21 @@ description = "Livekit safe bindings to libwebrtc"
|
||||
repository = "https://github.com/livekit/client-sdk-rust"
|
||||
|
||||
[dependencies]
|
||||
livekit-utils = { path = "../livekit-utils", version = "0.1.1" }
|
||||
livekit-protocol = { path = "../livekit-protocol", version = "0.1.0" }
|
||||
log = "0.4"
|
||||
thiserror = "1.0"
|
||||
|
||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||
webrtc-sys = { path = "../webrtc-sys", version = "0.1.1" }
|
||||
futures = { version = "0.3" }
|
||||
tokio = { version = "1.26.0", features = ["full"] }
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
cxx = "1.0"
|
||||
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||
wasm-bindgen = "0.2.84"
|
||||
wasm-bindgen = "0.2"
|
||||
js-sys = "0.3"
|
||||
wasm-bindgen-futures = "0.4.34"
|
||||
web-sys = { version = "0.3.22", features=[
|
||||
web-sys = { version = "0.3", features=[
|
||||
"MessageEvent",
|
||||
"RtcPeerConnection",
|
||||
"RtcSignalingState",
|
||||
@@ -39,4 +39,4 @@ web-sys = { version = "0.3.22", features=[
|
||||
] }
|
||||
|
||||
[dev-dependencies]
|
||||
env_logger = "0.9"
|
||||
env_logger = "0.10"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::imp::media_stream as imp_ms;
|
||||
use livekit_utils::enum_dispatch;
|
||||
use livekit_protocol::enum_dispatch;
|
||||
use std::fmt::Debug;
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
|
||||
+5
-9
@@ -8,20 +8,16 @@ repository = "https://github.com/livekit/client-sdk-rust"
|
||||
|
||||
[dependencies]
|
||||
livekit-webrtc = { path = "../livekit-webrtc", version = "0.1.1" }
|
||||
livekit-utils = { path = "../livekit-utils", version = "0.1.1" }
|
||||
livekit-protocol = { path = "../livekit-protocol", version = "0.1.0" }
|
||||
prost = "0.11"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
tokio-tungstenite = { version = "0.18", features = ["native-tls"] }
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
tokio-stream = "0.1"
|
||||
parking_lot = { version = "0.12.1", features = ["send_guard"] }
|
||||
url = "2.2.2"
|
||||
futures-util = "0.3.23"
|
||||
url = "2.3"
|
||||
futures-util = "0.3"
|
||||
thiserror = "1.0"
|
||||
prost = "0.11.0"
|
||||
prost-types = "0.11.1"
|
||||
lazy_static = "1.4.0"
|
||||
lazy_static = "1.4"
|
||||
tracing = "0.1"
|
||||
|
||||
[build-dependencies]
|
||||
prost-build = { version = "0.11.1" }
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
use std::io::Result;
|
||||
|
||||
fn main() -> Result<()> {
|
||||
prost_build::compile_protos(
|
||||
&[
|
||||
"protocol/livekit_rtc.proto",
|
||||
"protocol/livekit_models.proto",
|
||||
],
|
||||
&["protocol/"],
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
Submodule livekit/protocol deleted from fa87d56355
@@ -1,6 +1,5 @@
|
||||
use crate::track;
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/livekit.rs"));
|
||||
use livekit_protocol::*;
|
||||
|
||||
// Conversions
|
||||
impl TryFrom<TrackType> for track::TrackKind {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use self::track::RemoteTrack;
|
||||
use crate::participant::ConnectionQuality;
|
||||
use crate::prelude::*;
|
||||
use crate::proto;
|
||||
use crate::rtc_engine::EngineError;
|
||||
use livekit_protocol as proto;
|
||||
use std::fmt::Debug;
|
||||
use std::sync::Arc;
|
||||
use thiserror::Error;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::prelude::*;
|
||||
use crate::proto;
|
||||
use livekit_protocol as proto;
|
||||
use livekit_webrtc::prelude::*;
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
|
||||
@@ -4,8 +4,8 @@ use crate::options::compute_video_encodings;
|
||||
use crate::options::video_layers_from_encodings;
|
||||
use crate::options::TrackPublishOptions;
|
||||
use crate::prelude::*;
|
||||
use crate::proto;
|
||||
use crate::rtc_engine::RtcEngine;
|
||||
use livekit_protocol as proto;
|
||||
use livekit_webrtc::rtp_parameters::RtpEncodingParameters;
|
||||
use parking_lot::RwLockReadGuard;
|
||||
use std::collections::HashMap;
|
||||
@@ -150,6 +150,7 @@ impl LocalParticipant {
|
||||
participant_sid: self.sid().to_string(),
|
||||
payload: data.to_vec(),
|
||||
destination_sids: vec![],
|
||||
..Default::default()
|
||||
})),
|
||||
};
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use crate::prelude::*;
|
||||
use crate::proto;
|
||||
use crate::track::TrackError;
|
||||
use livekit_utils::enum_dispatch;
|
||||
use livekit_utils::observer::Dispatcher;
|
||||
use livekit_protocol as proto;
|
||||
use livekit_protocol::enum_dispatch;
|
||||
use livekit_protocol::observer::Dispatcher;
|
||||
use parking_lot::{Mutex, RwLock, RwLockReadGuard};
|
||||
use std::collections::HashMap;
|
||||
use std::sync::atomic::{AtomicBool, AtomicU32, AtomicU8, Ordering};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use super::{ConnectionQuality, ParticipantInner};
|
||||
use crate::prelude::*;
|
||||
use crate::proto;
|
||||
use crate::track::TrackError;
|
||||
use livekit_protocol as proto;
|
||||
use livekit_webrtc as rtc;
|
||||
use parking_lot::RwLockReadGuard;
|
||||
use rtc::prelude::MediaStreamTrack;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use super::TrackPublicationInner;
|
||||
use crate::id::TrackSid;
|
||||
use crate::options::TrackPublishOptions;
|
||||
use crate::proto;
|
||||
use crate::track::{LocalTrack, Track, TrackDimension, TrackKind, TrackSource};
|
||||
use livekit_protocol as proto;
|
||||
use parking_lot::Mutex;
|
||||
use std::sync::Arc;
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use super::track::{TrackDimension, TrackEvent};
|
||||
use crate::prelude::*;
|
||||
use crate::proto;
|
||||
use crate::track::Track;
|
||||
use futures_util::stream::StreamExt;
|
||||
use livekit_utils::enum_dispatch;
|
||||
use livekit_utils::observer::Dispatcher;
|
||||
use livekit_protocol as proto;
|
||||
use livekit_protocol::enum_dispatch;
|
||||
use livekit_protocol::observer::Dispatcher;
|
||||
use parking_lot::Mutex;
|
||||
use std::sync::atomic::{AtomicBool, AtomicU8, Ordering};
|
||||
use std::sync::Arc;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use super::TrackPublicationInner;
|
||||
use crate::id::TrackSid;
|
||||
use crate::proto;
|
||||
use crate::track::{RemoteTrack, Track, TrackDimension, TrackKind, TrackSource};
|
||||
use livekit_protocol as proto;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use crate::participant::ConnectionQuality;
|
||||
use crate::prelude::*;
|
||||
use crate::proto;
|
||||
use crate::rtc_engine::{EngineEvent, EngineEvents, EngineResult, RtcEngine};
|
||||
use crate::signal_client::SignalOptions;
|
||||
use crate::{RoomError, RoomEvent, RoomResult, SimulateScenario};
|
||||
use livekit_utils::observer::Dispatcher;
|
||||
use livekit_protocol as proto;
|
||||
use livekit_protocol::observer::Dispatcher;
|
||||
use parking_lot::{Mutex, RwLock, RwLockReadGuard};
|
||||
use std::collections::HashMap;
|
||||
use std::sync::atomic::{AtomicU8, Ordering};
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use super::TrackInner;
|
||||
use crate::options::AudioCaptureOptions;
|
||||
use crate::prelude::*;
|
||||
use crate::proto;
|
||||
use crate::rtc_engine::lk_runtime::LkRuntime;
|
||||
use crate::webrtc::peer_connection_factory::native::PeerConnectionFactoryExt;
|
||||
use livekit_protocol as proto;
|
||||
use livekit_webrtc as rtc;
|
||||
use parking_lot::Mutex;
|
||||
use rtc::audio_source::native::NativeAudioSource;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use super::TrackInner;
|
||||
use crate::proto;
|
||||
use crate::rtc_engine::lk_runtime::LkRuntime;
|
||||
use crate::{options::VideoCaptureOptions, prelude::*};
|
||||
use livekit_protocol as proto;
|
||||
use livekit_webrtc as rtc;
|
||||
use livekit_webrtc::peer_connection_factory::native::PeerConnectionFactoryExt;
|
||||
use parking_lot::Mutex;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::prelude::*;
|
||||
use crate::proto;
|
||||
use livekit_utils::enum_dispatch;
|
||||
use livekit_utils::observer::Dispatcher;
|
||||
use livekit_protocol as proto;
|
||||
use livekit_protocol::enum_dispatch;
|
||||
use livekit_protocol::observer::Dispatcher;
|
||||
use livekit_webrtc as rtc;
|
||||
use parking_lot::Mutex;
|
||||
use rtc::MediaType;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use super::TrackInner;
|
||||
use crate::prelude::*;
|
||||
use crate::proto;
|
||||
use livekit_protocol as proto;
|
||||
use livekit_webrtc as rtc;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::mpsc;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use super::TrackInner;
|
||||
use crate::prelude::*;
|
||||
use crate::proto;
|
||||
use livekit_protocol as proto;
|
||||
use livekit_webrtc as rtc;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::mpsc;
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
use crate::options::TrackPublishOptions;
|
||||
use crate::prelude::LocalTrack;
|
||||
use crate::proto;
|
||||
use crate::rtc_engine::lk_runtime::LkRuntime;
|
||||
use crate::rtc_engine::rtc_session::{RtcSession, SessionEvent, SessionEvents, SessionInfo};
|
||||
use crate::signal_client::{SignalError, SignalOptions};
|
||||
use livekit_protocol as proto;
|
||||
use livekit_webrtc::prelude::*;
|
||||
use livekit_webrtc::session_description::SdpParseError;
|
||||
use parking_lot::Mutex;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::{Arc, Weak};
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use thiserror::Error;
|
||||
use tokio::sync::RwLock as AsyncRwLock;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use crate::proto;
|
||||
use livekit_protocol as proto;
|
||||
use livekit_webrtc::prelude::*;
|
||||
use std::fmt::{Debug, Formatter};
|
||||
use std::time::Duration;
|
||||
use tracing::{debug, event, Level};
|
||||
use tracing::{event, Level};
|
||||
|
||||
const NEGOTIATION_FREQUENCY: Duration = Duration::from_millis(150);
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use super::peer_transport::PeerTransport;
|
||||
use crate::proto;
|
||||
use crate::rtc_engine::peer_transport::OnOfferCreated;
|
||||
use livekit_protocol as proto;
|
||||
use livekit_webrtc::{self as rtc, prelude::*};
|
||||
use tokio::sync::mpsc;
|
||||
use tracing::{debug, error};
|
||||
|
||||
@@ -4,9 +4,10 @@ use crate::prelude::TrackKind;
|
||||
use crate::rtc_engine::lk_runtime::LkRuntime;
|
||||
use crate::rtc_engine::peer_transport::PeerTransport;
|
||||
use crate::rtc_engine::rtc_events::{RtcEvent, RtcEvents};
|
||||
use crate::signal_client;
|
||||
use crate::signal_client::{SignalClient, SignalEvent, SignalEvents, SignalOptions};
|
||||
use crate::track::LocalTrack;
|
||||
use crate::{proto, signal_client};
|
||||
use livekit_protocol as proto;
|
||||
use livekit_webrtc::prelude::*;
|
||||
use parking_lot::Mutex;
|
||||
use prost::Message;
|
||||
@@ -157,7 +158,21 @@ impl RtcSession {
|
||||
debug!("received JoinResponse: {:?}", join_response);
|
||||
|
||||
let (rtc_emitter, rtc_events) = mpsc::unbounded_channel();
|
||||
let rtc_config = RtcConfiguration::from(join_response.clone());
|
||||
let rtc_config = RtcConfiguration {
|
||||
ice_servers: {
|
||||
let mut servers = vec![];
|
||||
for ice_server in join_response.ice_servers.clone() {
|
||||
servers.push(IceServer {
|
||||
urls: ice_server.urls,
|
||||
username: ice_server.username,
|
||||
password: ice_server.credential,
|
||||
})
|
||||
}
|
||||
servers
|
||||
},
|
||||
continual_gathering_policy: ContinualGatheringPolicy::GatherContinually,
|
||||
ice_transport_type: IceTransportsType::All,
|
||||
};
|
||||
|
||||
let mut publisher_pc = PeerTransport::new(
|
||||
lk_runtime
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::proto;
|
||||
use crate::signal_client::signal_stream::SignalStream;
|
||||
use livekit_protocol as proto;
|
||||
use livekit_webrtc::prelude::*;
|
||||
use parking_lot::RwLock;
|
||||
use std::fmt::Debug;
|
||||
@@ -114,29 +114,9 @@ impl SignalClient {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<proto::JoinResponse> for RtcConfiguration {
|
||||
fn from(join_response: proto::JoinResponse) -> Self {
|
||||
Self {
|
||||
ice_servers: {
|
||||
let mut servers = vec![];
|
||||
for ice_server in join_response.ice_servers.clone() {
|
||||
servers.push(IceServer {
|
||||
urls: ice_server.urls,
|
||||
username: ice_server.username,
|
||||
password: ice_server.credential,
|
||||
})
|
||||
}
|
||||
servers
|
||||
},
|
||||
continual_gathering_policy: ContinualGatheringPolicy::GatherContinually,
|
||||
ice_transport_type: IceTransportsType::All,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub mod utils {
|
||||
use crate::proto::{signal_response, JoinResponse};
|
||||
use crate::signal_client::{SignalError, SignalEvent, SignalResult, JOIN_RESPONSE_TIMEOUT};
|
||||
use livekit_protocol as proto;
|
||||
use tokio::time::timeout;
|
||||
use tokio_tungstenite::tungstenite::Error as WsError;
|
||||
use tracing::{event, instrument, Level};
|
||||
@@ -146,11 +126,13 @@ pub mod utils {
|
||||
#[instrument(level = Level::DEBUG, skip(receiver))]
|
||||
pub(crate) async fn next_join_response(
|
||||
receiver: &mut SignalEvents,
|
||||
) -> SignalResult<JoinResponse> {
|
||||
) -> SignalResult<proto::JoinResponse> {
|
||||
let join = async {
|
||||
while let Some(event) = receiver.recv().await {
|
||||
match event {
|
||||
SignalEvent::Signal(signal_response::Message::Join(join)) => return Ok(join),
|
||||
SignalEvent::Signal(proto::signal_response::Message::Join(join)) => {
|
||||
return Ok(join)
|
||||
}
|
||||
SignalEvent::Close => break,
|
||||
SignalEvent::Open => continue,
|
||||
_ => {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::proto;
|
||||
use crate::signal_client::{SignalEmitter, SignalEvent, SignalOptions, SignalResult};
|
||||
use futures_util::stream::{SplitSink, SplitStream};
|
||||
use futures_util::{SinkExt, StreamExt};
|
||||
use livekit_protocol as proto;
|
||||
use prost::Message as ProstMessage;
|
||||
use tokio::net::TcpStream;
|
||||
use tokio::sync::{mpsc, oneshot};
|
||||
|
||||
@@ -1,209 +0,0 @@
|
||||
The build system and the bindings are inspired by arcas-io (https://github.com/arcas-io)
|
||||
The Android build system is inspired by shiguredo (https://github.com/shiguredo/sora-cpp-sdk)
|
||||
|
||||
** littlebearlabs/arcas-io MIT License ""
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 arcas-io
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
Footer
|
||||
|
||||
** Shiguredo Apache 2.0 License **
|
||||
Sora C++ SDK
|
||||
|
||||
Copyright 2021-2022, Wandbox LLC (Original Author)
|
||||
|
||||
Copyright 2021-2022, Shiguredo Inc.
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation, and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
@@ -0,0 +1,426 @@
|
||||
## webrtc patches APACHE 2.0 License
|
||||
License of some patches we use to build webrtc
|
||||
```
|
||||
Copyright 2019-2022, Wandbox LLC (Original Author)
|
||||
Copyright 2019-2022, tnoho (Original Author)
|
||||
Copyright 2019-2022, Shiguredo Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
```
|
||||
## littlebearlabs/arcas-io MIT License
|
||||
The build system and the bindings are inspired by arcas-io (https://github.com/arcas-io)
|
||||
```
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 arcas-io
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
Footer
|
||||
```
|
||||
## Shiguredo Apache 2.0 License
|
||||
The Android build system is inspired by Shiguredo sora-cpp-sdk.
|
||||
```
|
||||
Sora C++ SDK
|
||||
|
||||
Copyright 2021-2022, Wandbox LLC (Original Author)
|
||||
|
||||
Copyright 2021-2022, Shiguredo Inc.
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation, and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
```
|
||||
|
||||
## webrtc build scripts APACHE 2.0 License
|
||||
The webrtc builds scripts are inspired by Unity-Technologies com.unity.webrtc
|
||||
```
|
||||
com.unity.webrtc copyright © 2022 Unity Technologies ApS
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
---
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
```
|
||||
@@ -189,6 +189,7 @@ fn main() {
|
||||
//.define("WEBRTC_ENABLE_SYMBOL_EXPORT", None) Not necessary when using WebRTC as a static library
|
||||
.define("NOMINMAX", None);
|
||||
}
|
||||
"linux" => {}
|
||||
"macos" => {
|
||||
println!("cargo:rustc-link-lib=framework=Foundation");
|
||||
println!("cargo:rustc-link-lib=framework=AVFoundation");
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
.cipd
|
||||
src
|
||||
.gclient_*
|
||||
depot_tools
|
||||
|
||||
# builds
|
||||
macos
|
||||
linux
|
||||
|
||||
Executable
+77
@@ -0,0 +1,77 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [ ! -e "$(pwd)/depot_tools" ]
|
||||
then
|
||||
git clone --depth 1 https://chromium.googlesource.com/chromium/tools/depot_tools.git
|
||||
fi
|
||||
|
||||
export COMMAND_DIR=$(cd $(dirname $0); pwd)
|
||||
export PATH="$(pwd)/depot_tools:$PATH"
|
||||
export OUTPUT_DIR="$(pwd)/src/out"
|
||||
export ARTIFACTS_DIR="$(pwd)/linux"
|
||||
|
||||
if [ ! -e "$(pwd)/src" ]
|
||||
then
|
||||
gclient sync
|
||||
fi
|
||||
|
||||
cd src
|
||||
git apply "$COMMAND_DIR/patches/add_license_dav1d.patch" -v
|
||||
git apply "$COMMAND_DIR/patches/ssl_verify_callback_with_native_handle.patch" -v
|
||||
git apply "$COMMAND_DIR/patches/fix_mocks.patch" -v
|
||||
cd ..
|
||||
|
||||
mkdir -p "$ARTIFACTS_DIR/lib"
|
||||
|
||||
for is_debug in "true" "false"
|
||||
do
|
||||
for target_cpu in "x64" "arm64"
|
||||
do
|
||||
args="is_debug=${is_debug} \
|
||||
target_os=\"linux\" \
|
||||
target_cpu=\"${target_cpu}\" \
|
||||
rtc_enable_protobuf=false \
|
||||
treat_warnings_as_errors=false \
|
||||
use_custom_libcxx=false \
|
||||
rtc_include_tests=false \
|
||||
rtc_build_tools=false \
|
||||
rtc_build_examples=false \
|
||||
rtc_libvpx_build_vp9=true \
|
||||
is_component_build=false \
|
||||
enable_stripping=true \
|
||||
use_goma=false \
|
||||
rtc_use_h264=false \
|
||||
rtc_use_pipewire=false \
|
||||
symbol_level=0 \
|
||||
enable_iterator_debugging=false \
|
||||
use_rtti=true \
|
||||
rtc_use_x11=false"
|
||||
|
||||
if [ $is_debug = "true" ]; then
|
||||
args="${args} is_asan=true is_lsan=true";
|
||||
fi
|
||||
|
||||
# generate ninja files
|
||||
gn gen "$OUTPUT_DIR" --root="src" --args="${args}"
|
||||
|
||||
# build static library
|
||||
ninja -C "$OUTPUT_DIR" webrtc
|
||||
|
||||
filename="libwebrtc.a"
|
||||
if [ $is_debug = "true" ]; then
|
||||
filename="libwebrtcd.a"
|
||||
fi
|
||||
|
||||
# cppy static library
|
||||
mkdir -p "$ARTIFACTS_DIR/lib/${target_cpu}"
|
||||
cp "$OUTPUT_DIR/obj/libwebrtc.a" "$ARTIFACTS_DIR/lib/${target_cpu}/${filename}"
|
||||
done
|
||||
done
|
||||
|
||||
python3 "./src/tools_webrtc/libs/generate_licenses.py" \
|
||||
--target :webrtc "$OUTPUT_DIR" "$OUTPUT_DIR"
|
||||
|
||||
cd src
|
||||
find . -name "*.h" -print | cpio -pd "$ARTIFACTS_DIR/include"
|
||||
|
||||
cp "$OUTPUT_DIR/LICENSE.md" "$ARTIFACTS_DIR"
|
||||
Executable
+75
@@ -0,0 +1,75 @@
|
||||
#!/bin/bash -eu
|
||||
|
||||
if [ ! -e "$(pwd)/depot_tools" ]
|
||||
then
|
||||
git clone --depth 1 https://chromium.googlesource.com/chromium/tools/depot_tools.git
|
||||
fi
|
||||
|
||||
export COMMAND_DIR=$(cd $(dirname $0); pwd)
|
||||
export PATH="$(pwd)/depot_tools:$PATH"
|
||||
export OUTPUT_DIR="$(pwd)/src/out"
|
||||
export ARTIFACTS_DIR="$(pwd)/macos"
|
||||
|
||||
if [ ! -e "$(pwd)/src" ]
|
||||
then
|
||||
gclient sync
|
||||
fi
|
||||
|
||||
cd src
|
||||
git apply "$COMMAND_DIR/patches/add_license_dav1d.patch" -v
|
||||
git apply "$COMMAND_DIR/patches/ssl_verify_callback_with_native_handle.patch" -v
|
||||
git apply "$COMMAND_DIR/patches/fix_mocks.patch" -v
|
||||
cd ..
|
||||
|
||||
mkdir -p "$ARTIFACTS_DIR/lib"
|
||||
|
||||
for is_debug in "true" "false"
|
||||
do
|
||||
for target_cpu in "x64" "arm64"
|
||||
do
|
||||
|
||||
# generate ninja files
|
||||
gn gen "$OUTPUT_DIR" --root="src" \
|
||||
--args="is_debug=${is_debug} \
|
||||
enable_dsyms=${is_debug} \
|
||||
target_os=\"mac\" \
|
||||
target_cpu=\"${target_cpu}\" \
|
||||
mac_deployment_target=\"10.11\" \
|
||||
treat_warnings_as_errors=false \
|
||||
rtc_enable_protobuf=false \
|
||||
rtc_include_tests=false \
|
||||
rtc_build_examples=false \
|
||||
rtc_build_tools=false \
|
||||
rtc_libvpx_build_vp9=true \
|
||||
is_component_build=false \
|
||||
enable_stripping=true \
|
||||
use_goma=false \
|
||||
rtc_use_h264=false \
|
||||
rtc_enable_symbol_export=true \
|
||||
rtc_enable_objc_symbol_export=false \
|
||||
clang_use_chrome_plugins=false \
|
||||
symbol_level=0 \
|
||||
enable_iterator_debugging=false \
|
||||
use_rtti=true"
|
||||
|
||||
# build static library
|
||||
ninja -C "$OUTPUT_DIR" webrtc
|
||||
|
||||
filename="libwebrtc.a"
|
||||
if [ $is_debug = "true" ]; then
|
||||
filename="libwebrtcd.a"
|
||||
fi
|
||||
|
||||
# cppy static library
|
||||
mkdir -p "$ARTIFACTS_DIR/lib/${target_cpu}"
|
||||
cp "$OUTPUT_DIR/obj/libwebrtc.a" "$ARTIFACTS_DIR/lib/${target_cpu}/${filename}"
|
||||
done
|
||||
done
|
||||
|
||||
python3 "./src/tools_webrtc/libs/generate_licenses.py" \
|
||||
--target :webrtc "$OUTPUT_DIR" "$OUTPUT_DIR"
|
||||
|
||||
cd src
|
||||
find . -name "*.h" -print | cpio -pd "$ARTIFACTS_DIR/include"
|
||||
|
||||
cp "$OUTPUT_DIR/LICENSE.md" "$ARTIFACTS_DIR"
|
||||
@@ -0,0 +1,63 @@
|
||||
@echo off
|
||||
|
||||
if not exist depot_tools (
|
||||
git clone --depth 1 https://chromium.googlesource.com/chromium/tools/depot_tools.git
|
||||
)
|
||||
|
||||
set COMMAND_DIR=%~dp0
|
||||
set PATH=%cd%\depot_tools;%PATH%
|
||||
set DEPOT_TOOLS_WIN_TOOLCHAIN=0
|
||||
set GYP_GENERATORS=ninja,msvs-ninja
|
||||
set GYP_MSVS_VERSION=2019
|
||||
set OUTPUT_DIR=src/out
|
||||
set ARTIFACTS_DIR=%cd%\windows
|
||||
set vs2019_install=C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional
|
||||
|
||||
if not exist src (
|
||||
call gclient.bat sync
|
||||
)
|
||||
|
||||
cd src
|
||||
call git apply "%COMMAND_DIR%/patches/add_license_dav1d.patch" -v
|
||||
call git apply "%COMMAND_DIR%/patches/ssl_verify_callback_with_native_handle.patch" -v
|
||||
call git apply "%COMMAND_DIR%/patches/fix_mocks.patch" -v
|
||||
cd ..
|
||||
|
||||
mkdir "%ARTIFACTS_DIR%\lib"
|
||||
|
||||
setlocal enabledelayedexpansion
|
||||
|
||||
for %%i in (x64 arm64) do (
|
||||
mkdir "%ARTIFACTS_DIR%/lib/%%i"
|
||||
for %%j in (true false) do (
|
||||
|
||||
rem generate ninja for release
|
||||
call gn.bat gen %OUTPUT_DIR% --root="src" ^
|
||||
--args="is_debug=%%j is_clang=true target_cpu=\"%%i\" use_custom_libcxx=false rtc_include_tests=false rtc_build_examples=false rtc_use_h264=false symbol_level=0 enable_iterator_debugging=false"
|
||||
|
||||
rem build
|
||||
ninja.exe -C %OUTPUT_DIR% webrtc
|
||||
|
||||
set filename=
|
||||
if true==%%j (
|
||||
set filename=webrtcd.lib
|
||||
) else (
|
||||
set filename=webrtc.lib
|
||||
)
|
||||
|
||||
rem copy static library for release build
|
||||
copy "%OUTPUT_DIR%\obj\webrtc.lib" "%ARTIFACTS_DIR%\lib\%%i\!filename!"
|
||||
)
|
||||
)
|
||||
|
||||
endlocal
|
||||
|
||||
rem generate license
|
||||
call python3 "%cd%\src\tools_webrtc\libs\generate_licenses.py" ^
|
||||
--target :webrtc %OUTPUT_DIR% %OUTPUT_DIR%
|
||||
|
||||
rem copy header
|
||||
xcopy src\*.h "%ARTIFACTS_DIR%\include" /C /S /I /F /H
|
||||
|
||||
rem copy license
|
||||
copy "%OUTPUT_DIR%\LICENSE.md" "%ARTIFACTS_DIR%\LICENSE.md"
|
||||
@@ -0,0 +1,17 @@
|
||||
diff --git a/tools_webrtc/libs/generate_licenses.py b/tools_webrtc/libs/generate_licenses.py
|
||||
index 86b4cd01f0..cf927670ee 100755
|
||||
--- a/tools_webrtc/libs/generate_licenses.py
|
||||
+++ b/tools_webrtc/libs/generate_licenses.py
|
||||
@@ -91,6 +91,12 @@ LIB_TO_LICENSES_DICT = {
|
||||
'yasm': [],
|
||||
'ow2_asm': [],
|
||||
'jdk': [],
|
||||
+
|
||||
+ 'dav1d': ['third_party/dav1d/LICENSE'],
|
||||
+ 'catapult': [],
|
||||
+ 'google_benchmark': [],
|
||||
+ 'googletest': [],
|
||||
+ 'vinn': [],
|
||||
}
|
||||
|
||||
# Third_party library _regex_ to licences mapping. Keys are regular expression
|
||||
@@ -0,0 +1,25 @@
|
||||
diff --git a/modules/audio_device/include/mock_audio_device.h b/modules/audio_device/include/mock_audio_device.h
|
||||
index 8483aa3da8..f66cdca0ba 100644
|
||||
--- a/modules/audio_device/include/mock_audio_device.h
|
||||
+++ b/modules/audio_device/include/mock_audio_device.h
|
||||
@@ -149,6 +149,7 @@ class MockAudioDeviceModule : public AudioDeviceModule {
|
||||
(AudioParameters * params),
|
||||
(const, override));
|
||||
#endif // WEBRTC_IOS
|
||||
+ MOCK_METHOD(int32_t, SetAudioDeviceSink, (AudioDeviceSink* sink), (const, override));
|
||||
};
|
||||
} // namespace test
|
||||
} // namespace webrtc
|
||||
diff --git a/pc/test/fake_audio_capture_module.h b/pc/test/fake_audio_capture_module.h
|
||||
index fd13a85f89..81bdbf9f8c 100644
|
||||
--- a/pc/test/fake_audio_capture_module.h
|
||||
+++ b/pc/test/fake_audio_capture_module.h
|
||||
@@ -140,6 +140,8 @@ class FakeAudioCaptureModule : public webrtc::AudioDeviceModule,
|
||||
int32_t EnableBuiltInNS(bool enable) override { return -1; }
|
||||
|
||||
int32_t GetPlayoutUnderrunCount() const override { return -1; }
|
||||
+
|
||||
+ int32_t SetAudioDeviceSink(webrtc::AudioDeviceSink* sink) const override { return 0; }
|
||||
#if defined(WEBRTC_IOS)
|
||||
int GetPlayoutAudioParameters(
|
||||
webrtc::AudioParameters* params) const override {
|
||||
@@ -0,0 +1,76 @@
|
||||
diff --git a/rtc_base/boringssl_certificate.cc b/rtc_base/boringssl_certificate.cc
|
||||
index 99b2ab3e24..c37d6d963f 100644
|
||||
--- a/rtc_base/boringssl_certificate.cc
|
||||
+++ b/rtc_base/boringssl_certificate.cc
|
||||
@@ -253,6 +253,12 @@ BoringSSLCertificate::BoringSSLCertificate(
|
||||
RTC_DCHECK(cert_buffer_ != nullptr);
|
||||
}
|
||||
|
||||
+BoringSSLCertificate::BoringSSLCertificate(
|
||||
+ bssl::UniquePtr<CRYPTO_BUFFER> cert_buffer, SSL* ssl)
|
||||
+ : cert_buffer_(std::move(cert_buffer)), ssl_(ssl) {
|
||||
+ RTC_DCHECK(cert_buffer_ != nullptr);
|
||||
+}
|
||||
+
|
||||
std::unique_ptr<BoringSSLCertificate> BoringSSLCertificate::Generate(
|
||||
OpenSSLKeyPair* key_pair,
|
||||
const SSLIdentityParams& params) {
|
||||
diff --git a/rtc_base/boringssl_certificate.h b/rtc_base/boringssl_certificate.h
|
||||
index 8b4577a17c..e1fe26cba5 100644
|
||||
--- a/rtc_base/boringssl_certificate.h
|
||||
+++ b/rtc_base/boringssl_certificate.h
|
||||
@@ -33,6 +33,7 @@ class OpenSSLKeyPair;
|
||||
class BoringSSLCertificate final : public SSLCertificate {
|
||||
public:
|
||||
explicit BoringSSLCertificate(bssl::UniquePtr<CRYPTO_BUFFER> cert_buffer);
|
||||
+ BoringSSLCertificate(bssl::UniquePtr<CRYPTO_BUFFER> cert_buffer, SSL* ssl);
|
||||
|
||||
static std::unique_ptr<BoringSSLCertificate> Generate(
|
||||
OpenSSLKeyPair* key_pair,
|
||||
@@ -74,6 +75,11 @@ class BoringSSLCertificate final : public SSLCertificate {
|
||||
private:
|
||||
// A handle to the DER encoded certificate data.
|
||||
bssl::UniquePtr<CRYPTO_BUFFER> cert_buffer_;
|
||||
+
|
||||
+ private:
|
||||
+ SSL* ssl_ = nullptr;
|
||||
+ public:
|
||||
+ SSL* ssl() const { return ssl_; }
|
||||
};
|
||||
|
||||
} // namespace rtc
|
||||
diff --git a/rtc_base/openssl_adapter.cc b/rtc_base/openssl_adapter.cc
|
||||
index bc10e619eb..836ef9ea18 100644
|
||||
--- a/rtc_base/openssl_adapter.cc
|
||||
+++ b/rtc_base/openssl_adapter.cc
|
||||
@@ -822,7 +822,7 @@ enum ssl_verify_result_t OpenSSLAdapter::SSLVerifyInternal(SSL* ssl,
|
||||
return ssl_verify_invalid;
|
||||
}
|
||||
|
||||
- BoringSSLCertificate cert(bssl::UpRef(sk_CRYPTO_BUFFER_value(chain, 0)));
|
||||
+ BoringSSLCertificate cert(bssl::UpRef(sk_CRYPTO_BUFFER_value(chain, 0)), ssl);
|
||||
if (!ssl_cert_verifier_->Verify(cert)) {
|
||||
RTC_LOG(LS_WARNING) << "Failed to verify certificate using custom callback";
|
||||
return ssl_verify_invalid;
|
||||
@@ -894,7 +894,7 @@ int OpenSSLAdapter::SSLVerifyInternal(int previous_status,
|
||||
RTC_LOG(LS_ERROR) << "Failed to allocate CRYPTO_BUFFER.";
|
||||
return previous_status;
|
||||
}
|
||||
- const BoringSSLCertificate cert(std::move(crypto_buffer));
|
||||
+ const BoringSSLCertificate cert(std::move(crypto_buffer), ssl);
|
||||
#else
|
||||
const OpenSSLCertificate cert(X509_STORE_CTX_get_current_cert(store));
|
||||
#endif
|
||||
diff --git a/rtc_base/openssl_stream_adapter.cc b/rtc_base/openssl_stream_adapter.cc
|
||||
index dd82e4f061..6d7e39c534 100644
|
||||
--- a/rtc_base/openssl_stream_adapter.cc
|
||||
+++ b/rtc_base/openssl_stream_adapter.cc
|
||||
@@ -1154,7 +1154,7 @@ enum ssl_verify_result_t OpenSSLStreamAdapter::SSLVerifyCallback(
|
||||
// Creates certificate chain.
|
||||
std::vector<std::unique_ptr<SSLCertificate>> cert_chain;
|
||||
for (CRYPTO_BUFFER* cert : chain) {
|
||||
- cert_chain.emplace_back(new BoringSSLCertificate(bssl::UpRef(cert)));
|
||||
+ cert_chain.emplace_back(new BoringSSLCertificate(bssl::UpRef(cert), ssl));
|
||||
}
|
||||
stream->peer_cert_chain_.reset(new SSLCertChain(std::move(cert_chain)));
|
||||
|
||||
Reference in New Issue
Block a user