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:
Théo Monnom
2023-04-19 12:33:39 +02:00
committed by GitHub
parent 459a42bf12
commit 180864e953
62 changed files with 2621 additions and 635 deletions
+5
View File
@@ -36,6 +36,11 @@ jobs:
rustup update --no-self-update stable rustup update --no-self-update stable
rustup target add ${{ matrix.target }} 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 - uses: actions/checkout@v3
with: with:
submodules: true submodules: true
+1 -1
View File
@@ -1,3 +1,3 @@
[submodule "livekit/protocol"] [submodule "livekit/protocol"]
path = livekit/protocol path = livekit-protocol/protocol
url = https://github.com/livekit/protocol url = https://github.com/livekit/protocol
Generated
+363 -320
View File
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -1,7 +1,8 @@
[workspace] [workspace]
members = [ members = [
"livekit", "livekit",
"livekit-utils", "livekit-api",
"livekit-protocol",
"livekit-ffi", "livekit-ffi",
"livekit-webrtc", "livekit-webrtc",
"webrtc-sys" "webrtc-sys"
+15
View File
@@ -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"
+260
View File
@@ -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());
}
}
+9
View File
@@ -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))
}
+423
View File
@@ -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()
};
}
+138
View File
@@ -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)
}
}
+59
View File
@@ -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)
}
}
+308
View File
@@ -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)
}
}
+109
View File
@@ -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))
}
}
}
+55
View File
@@ -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)?)
}
}*/
+1
View File
@@ -8,6 +8,7 @@ repository = "https://github.com/livekit/client-sdk-rust"
[dependencies] [dependencies]
livekit = { path = "../livekit", version = "0.1.1" } livekit = { path = "../livekit", version = "0.1.1" }
livekit-protocol = { path = "../livekit-protocol", version = "0.1.0" }
tokio = { version = "1.0", features = ["full"] } tokio = { version = "1.0", features = ["full"] }
parking_lot = { version = "0.12.1", features = ["send_guard"] } parking_lot = { version = "0.12.1", features = ["send_guard"] }
prost = "0.11.0" prost = "0.11.0"
+2 -3
View File
@@ -1,7 +1,6 @@
use crate::{proto, server::FFIHandleId}; use crate::server::FFIHandleId;
use livekit::prelude::*; use livekit::prelude::*;
use livekit::webrtc::prelude::*; use crate::proto;
use std::any::Any;
pub mod participant; pub mod participant;
pub mod publication; 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::prelude::*;
use livekit::webrtc::video_frame; use livekit::webrtc::video_frame;
use std::any::Any;
macro_rules! impl_yuv_into { macro_rules! impl_yuv_into {
(@fields, $buffer:ident, $data_y:ident, $data_u:ident, $data_v: ident) => { (@fields, $buffer:ident, $data_y:ident, $data_u:ident, $data_v: ident) => {
+1 -1
View File
@@ -1,7 +1,7 @@
use crate::proto;
use lazy_static::lazy_static; use lazy_static::lazy_static;
use livekit::prelude::*; use livekit::prelude::*;
use livekit::webrtc::video_frame::{native::VideoFrameBufferExt, BoxVideoFrame, VideoFrameBuffer}; use livekit::webrtc::video_frame::{native::VideoFrameBufferExt, BoxVideoFrame, VideoFrameBuffer};
use crate::proto;
use parking_lot::{Mutex, RwLock}; use parking_lot::{Mutex, RwLock};
use prost::Message; use prost::Message;
use std::any::Any; use std::any::Any;
+1 -1
View File
@@ -1,9 +1,9 @@
use crate::proto;
use crate::server::FFIServer; use crate::server::FFIServer;
use futures_util::stream::StreamExt; use futures_util::stream::StreamExt;
use livekit::prelude::*; use livekit::prelude::*;
use livekit::webrtc::video_stream::native::NativeVideoStream; use livekit::webrtc::video_stream::native::NativeVideoStream;
use tokio::sync::{mpsc, oneshot}; use tokio::sync::{mpsc, oneshot};
use crate::proto;
pub async fn create_room( pub async fn create_room(
server: &'static FFIServer, server: &'static FFIServer,
+14
View File
@@ -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" }
+16
View File
@@ -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(())
}
+8
View File
@@ -0,0 +1,8 @@
pub mod observer;
pub mod enum_dispatch;
pub mod livekit {
include!(concat!(env!("OUT_DIR"), "/livekit.rs"));
}
pub use livekit::*;
-12
View File
@@ -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"
-2
View File
@@ -1,2 +0,0 @@
pub mod enum_dispatch;
pub mod observer;
+5 -5
View File
@@ -8,21 +8,21 @@ description = "Livekit safe bindings to libwebrtc"
repository = "https://github.com/livekit/client-sdk-rust" repository = "https://github.com/livekit/client-sdk-rust"
[dependencies] [dependencies]
livekit-utils = { path = "../livekit-utils", version = "0.1.1" } livekit-protocol = { path = "../livekit-protocol", version = "0.1.0" }
log = "0.4" log = "0.4"
thiserror = "1.0" thiserror = "1.0"
[target.'cfg(not(target_arch = "wasm32"))'.dependencies] [target.'cfg(not(target_arch = "wasm32"))'.dependencies]
webrtc-sys = { path = "../webrtc-sys", version = "0.1.1" } webrtc-sys = { path = "../webrtc-sys", version = "0.1.1" }
futures = { version = "0.3" } futures = { version = "0.3" }
tokio = { version = "1.26.0", features = ["full"] } tokio = { version = "1", features = ["full"] }
cxx = "1.0" cxx = "1.0"
[target.'cfg(target_arch = "wasm32")'.dependencies] [target.'cfg(target_arch = "wasm32")'.dependencies]
wasm-bindgen = "0.2.84" wasm-bindgen = "0.2"
js-sys = "0.3" js-sys = "0.3"
wasm-bindgen-futures = "0.4.34" wasm-bindgen-futures = "0.4.34"
web-sys = { version = "0.3.22", features=[ web-sys = { version = "0.3", features=[
"MessageEvent", "MessageEvent",
"RtcPeerConnection", "RtcPeerConnection",
"RtcSignalingState", "RtcSignalingState",
@@ -39,4 +39,4 @@ web-sys = { version = "0.3.22", features=[
] } ] }
[dev-dependencies] [dev-dependencies]
env_logger = "0.9" env_logger = "0.10"
+1 -1
View File
@@ -1,5 +1,5 @@
use crate::imp::media_stream as imp_ms; use crate::imp::media_stream as imp_ms;
use livekit_utils::enum_dispatch; use livekit_protocol::enum_dispatch;
use std::fmt::Debug; use std::fmt::Debug;
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Copy, Clone, PartialEq, Eq)]
+5 -9
View File
@@ -8,20 +8,16 @@ repository = "https://github.com/livekit/client-sdk-rust"
[dependencies] [dependencies]
livekit-webrtc = { path = "../livekit-webrtc", version = "0.1.1" } 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 = { version = "1", features = ["derive"] }
serde_json = "1.0" serde_json = "1.0"
tokio-tungstenite = { version = "0.18", features = ["native-tls"] } tokio-tungstenite = { version = "0.18", features = ["native-tls"] }
tokio = { version = "1", features = ["full"] } tokio = { version = "1", features = ["full"] }
tokio-stream = "0.1" tokio-stream = "0.1"
parking_lot = { version = "0.12.1", features = ["send_guard"] } parking_lot = { version = "0.12.1", features = ["send_guard"] }
url = "2.2.2" url = "2.3"
futures-util = "0.3.23" futures-util = "0.3"
thiserror = "1.0" thiserror = "1.0"
prost = "0.11.0" lazy_static = "1.4"
prost-types = "0.11.1"
lazy_static = "1.4.0"
tracing = "0.1" tracing = "0.1"
[build-dependencies]
prost-build = { version = "0.11.1" }
-12
View File
@@ -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(())
}
+1 -2
View File
@@ -1,6 +1,5 @@
use crate::track; use crate::track;
use livekit_protocol::*;
include!(concat!(env!("OUT_DIR"), "/livekit.rs"));
// Conversions // Conversions
impl TryFrom<TrackType> for track::TrackKind { impl TryFrom<TrackType> for track::TrackKind {
+1 -1
View File
@@ -1,8 +1,8 @@
use self::track::RemoteTrack; use self::track::RemoteTrack;
use crate::participant::ConnectionQuality; use crate::participant::ConnectionQuality;
use crate::prelude::*; use crate::prelude::*;
use crate::proto;
use crate::rtc_engine::EngineError; use crate::rtc_engine::EngineError;
use livekit_protocol as proto;
use std::fmt::Debug; use std::fmt::Debug;
use std::sync::Arc; use std::sync::Arc;
use thiserror::Error; use thiserror::Error;
+1 -1
View File
@@ -1,5 +1,5 @@
use crate::prelude::*; use crate::prelude::*;
use crate::proto; use livekit_protocol as proto;
use livekit_webrtc::prelude::*; use livekit_webrtc::prelude::*;
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[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::video_layers_from_encodings;
use crate::options::TrackPublishOptions; use crate::options::TrackPublishOptions;
use crate::prelude::*; use crate::prelude::*;
use crate::proto;
use crate::rtc_engine::RtcEngine; use crate::rtc_engine::RtcEngine;
use livekit_protocol as proto;
use livekit_webrtc::rtp_parameters::RtpEncodingParameters; use livekit_webrtc::rtp_parameters::RtpEncodingParameters;
use parking_lot::RwLockReadGuard; use parking_lot::RwLockReadGuard;
use std::collections::HashMap; use std::collections::HashMap;
@@ -150,6 +150,7 @@ impl LocalParticipant {
participant_sid: self.sid().to_string(), participant_sid: self.sid().to_string(),
payload: data.to_vec(), payload: data.to_vec(),
destination_sids: vec![], destination_sids: vec![],
..Default::default()
})), })),
}; };
+3 -3
View File
@@ -1,8 +1,8 @@
use crate::prelude::*; use crate::prelude::*;
use crate::proto;
use crate::track::TrackError; use crate::track::TrackError;
use livekit_utils::enum_dispatch; use livekit_protocol as proto;
use livekit_utils::observer::Dispatcher; use livekit_protocol::enum_dispatch;
use livekit_protocol::observer::Dispatcher;
use parking_lot::{Mutex, RwLock, RwLockReadGuard}; use parking_lot::{Mutex, RwLock, RwLockReadGuard};
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::atomic::{AtomicBool, AtomicU32, AtomicU8, Ordering}; use std::sync::atomic::{AtomicBool, AtomicU32, AtomicU8, Ordering};
@@ -1,7 +1,7 @@
use super::{ConnectionQuality, ParticipantInner}; use super::{ConnectionQuality, ParticipantInner};
use crate::prelude::*; use crate::prelude::*;
use crate::proto;
use crate::track::TrackError; use crate::track::TrackError;
use livekit_protocol as proto;
use livekit_webrtc as rtc; use livekit_webrtc as rtc;
use parking_lot::RwLockReadGuard; use parking_lot::RwLockReadGuard;
use rtc::prelude::MediaStreamTrack; use rtc::prelude::MediaStreamTrack;
+1 -1
View File
@@ -1,8 +1,8 @@
use super::TrackPublicationInner; use super::TrackPublicationInner;
use crate::id::TrackSid; use crate::id::TrackSid;
use crate::options::TrackPublishOptions; use crate::options::TrackPublishOptions;
use crate::proto;
use crate::track::{LocalTrack, Track, TrackDimension, TrackKind, TrackSource}; use crate::track::{LocalTrack, Track, TrackDimension, TrackKind, TrackSource};
use livekit_protocol as proto;
use parking_lot::Mutex; use parking_lot::Mutex;
use std::sync::Arc; use std::sync::Arc;
+3 -3
View File
@@ -1,10 +1,10 @@
use super::track::{TrackDimension, TrackEvent}; use super::track::{TrackDimension, TrackEvent};
use crate::prelude::*; use crate::prelude::*;
use crate::proto;
use crate::track::Track; use crate::track::Track;
use futures_util::stream::StreamExt; use futures_util::stream::StreamExt;
use livekit_utils::enum_dispatch; use livekit_protocol as proto;
use livekit_utils::observer::Dispatcher; use livekit_protocol::enum_dispatch;
use livekit_protocol::observer::Dispatcher;
use parking_lot::Mutex; use parking_lot::Mutex;
use std::sync::atomic::{AtomicBool, AtomicU8, Ordering}; use std::sync::atomic::{AtomicBool, AtomicU8, Ordering};
use std::sync::Arc; use std::sync::Arc;
+1 -1
View File
@@ -1,7 +1,7 @@
use super::TrackPublicationInner; use super::TrackPublicationInner;
use crate::id::TrackSid; use crate::id::TrackSid;
use crate::proto;
use crate::track::{RemoteTrack, Track, TrackDimension, TrackKind, TrackSource}; use crate::track::{RemoteTrack, Track, TrackDimension, TrackKind, TrackSource};
use livekit_protocol as proto;
use std::sync::Arc; use std::sync::Arc;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
+2 -2
View File
@@ -1,10 +1,10 @@
use crate::participant::ConnectionQuality; use crate::participant::ConnectionQuality;
use crate::prelude::*; use crate::prelude::*;
use crate::proto;
use crate::rtc_engine::{EngineEvent, EngineEvents, EngineResult, RtcEngine}; use crate::rtc_engine::{EngineEvent, EngineEvents, EngineResult, RtcEngine};
use crate::signal_client::SignalOptions; use crate::signal_client::SignalOptions;
use crate::{RoomError, RoomEvent, RoomResult, SimulateScenario}; 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 parking_lot::{Mutex, RwLock, RwLockReadGuard};
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::atomic::{AtomicU8, Ordering}; use std::sync::atomic::{AtomicU8, Ordering};
+1 -1
View File
@@ -1,9 +1,9 @@
use super::TrackInner; use super::TrackInner;
use crate::options::AudioCaptureOptions; use crate::options::AudioCaptureOptions;
use crate::prelude::*; use crate::prelude::*;
use crate::proto;
use crate::rtc_engine::lk_runtime::LkRuntime; use crate::rtc_engine::lk_runtime::LkRuntime;
use crate::webrtc::peer_connection_factory::native::PeerConnectionFactoryExt; use crate::webrtc::peer_connection_factory::native::PeerConnectionFactoryExt;
use livekit_protocol as proto;
use livekit_webrtc as rtc; use livekit_webrtc as rtc;
use parking_lot::Mutex; use parking_lot::Mutex;
use rtc::audio_source::native::NativeAudioSource; use rtc::audio_source::native::NativeAudioSource;
+1 -1
View File
@@ -1,7 +1,7 @@
use super::TrackInner; use super::TrackInner;
use crate::proto;
use crate::rtc_engine::lk_runtime::LkRuntime; use crate::rtc_engine::lk_runtime::LkRuntime;
use crate::{options::VideoCaptureOptions, prelude::*}; use crate::{options::VideoCaptureOptions, prelude::*};
use livekit_protocol as proto;
use livekit_webrtc as rtc; use livekit_webrtc as rtc;
use livekit_webrtc::peer_connection_factory::native::PeerConnectionFactoryExt; use livekit_webrtc::peer_connection_factory::native::PeerConnectionFactoryExt;
use parking_lot::Mutex; use parking_lot::Mutex;
+3 -3
View File
@@ -1,7 +1,7 @@
use crate::prelude::*; use crate::prelude::*;
use crate::proto; use livekit_protocol as proto;
use livekit_utils::enum_dispatch; use livekit_protocol::enum_dispatch;
use livekit_utils::observer::Dispatcher; use livekit_protocol::observer::Dispatcher;
use livekit_webrtc as rtc; use livekit_webrtc as rtc;
use parking_lot::Mutex; use parking_lot::Mutex;
use rtc::MediaType; use rtc::MediaType;
+1 -1
View File
@@ -1,6 +1,6 @@
use super::TrackInner; use super::TrackInner;
use crate::prelude::*; use crate::prelude::*;
use crate::proto; use livekit_protocol as proto;
use livekit_webrtc as rtc; use livekit_webrtc as rtc;
use std::sync::Arc; use std::sync::Arc;
use tokio::sync::mpsc; use tokio::sync::mpsc;
+1 -1
View File
@@ -1,6 +1,6 @@
use super::TrackInner; use super::TrackInner;
use crate::prelude::*; use crate::prelude::*;
use crate::proto; use livekit_protocol as proto;
use livekit_webrtc as rtc; use livekit_webrtc as rtc;
use std::sync::Arc; use std::sync::Arc;
use tokio::sync::mpsc; use tokio::sync::mpsc;
+2 -2
View File
@@ -1,14 +1,14 @@
use crate::options::TrackPublishOptions; use crate::options::TrackPublishOptions;
use crate::prelude::LocalTrack; use crate::prelude::LocalTrack;
use crate::proto;
use crate::rtc_engine::lk_runtime::LkRuntime; use crate::rtc_engine::lk_runtime::LkRuntime;
use crate::rtc_engine::rtc_session::{RtcSession, SessionEvent, SessionEvents, SessionInfo}; use crate::rtc_engine::rtc_session::{RtcSession, SessionEvent, SessionEvents, SessionInfo};
use crate::signal_client::{SignalError, SignalOptions}; use crate::signal_client::{SignalError, SignalOptions};
use livekit_protocol as proto;
use livekit_webrtc::prelude::*; use livekit_webrtc::prelude::*;
use livekit_webrtc::session_description::SdpParseError; use livekit_webrtc::session_description::SdpParseError;
use parking_lot::Mutex; use parking_lot::Mutex;
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Weak}; use std::sync::Arc;
use std::time::Duration; use std::time::Duration;
use thiserror::Error; use thiserror::Error;
use tokio::sync::RwLock as AsyncRwLock; use tokio::sync::RwLock as AsyncRwLock;
+2 -2
View File
@@ -1,8 +1,8 @@
use crate::proto; use livekit_protocol as proto;
use livekit_webrtc::prelude::*; use livekit_webrtc::prelude::*;
use std::fmt::{Debug, Formatter}; use std::fmt::{Debug, Formatter};
use std::time::Duration; use std::time::Duration;
use tracing::{debug, event, Level}; use tracing::{event, Level};
const NEGOTIATION_FREQUENCY: Duration = Duration::from_millis(150); const NEGOTIATION_FREQUENCY: Duration = Duration::from_millis(150);
+1 -1
View File
@@ -1,6 +1,6 @@
use super::peer_transport::PeerTransport; use super::peer_transport::PeerTransport;
use crate::proto;
use crate::rtc_engine::peer_transport::OnOfferCreated; use crate::rtc_engine::peer_transport::OnOfferCreated;
use livekit_protocol as proto;
use livekit_webrtc::{self as rtc, prelude::*}; use livekit_webrtc::{self as rtc, prelude::*};
use tokio::sync::mpsc; use tokio::sync::mpsc;
use tracing::{debug, error}; use tracing::{debug, error};
+17 -2
View File
@@ -4,9 +4,10 @@ use crate::prelude::TrackKind;
use crate::rtc_engine::lk_runtime::LkRuntime; use crate::rtc_engine::lk_runtime::LkRuntime;
use crate::rtc_engine::peer_transport::PeerTransport; use crate::rtc_engine::peer_transport::PeerTransport;
use crate::rtc_engine::rtc_events::{RtcEvent, RtcEvents}; use crate::rtc_engine::rtc_events::{RtcEvent, RtcEvents};
use crate::signal_client;
use crate::signal_client::{SignalClient, SignalEvent, SignalEvents, SignalOptions}; use crate::signal_client::{SignalClient, SignalEvent, SignalEvents, SignalOptions};
use crate::track::LocalTrack; use crate::track::LocalTrack;
use crate::{proto, signal_client}; use livekit_protocol as proto;
use livekit_webrtc::prelude::*; use livekit_webrtc::prelude::*;
use parking_lot::Mutex; use parking_lot::Mutex;
use prost::Message; use prost::Message;
@@ -157,7 +158,21 @@ impl RtcSession {
debug!("received JoinResponse: {:?}", join_response); debug!("received JoinResponse: {:?}", join_response);
let (rtc_emitter, rtc_events) = mpsc::unbounded_channel(); 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( let mut publisher_pc = PeerTransport::new(
lk_runtime lk_runtime
+6 -24
View File
@@ -1,5 +1,5 @@
use crate::proto;
use crate::signal_client::signal_stream::SignalStream; use crate::signal_client::signal_stream::SignalStream;
use livekit_protocol as proto;
use livekit_webrtc::prelude::*; use livekit_webrtc::prelude::*;
use parking_lot::RwLock; use parking_lot::RwLock;
use std::fmt::Debug; 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 { pub mod utils {
use crate::proto::{signal_response, JoinResponse};
use crate::signal_client::{SignalError, SignalEvent, SignalResult, JOIN_RESPONSE_TIMEOUT}; use crate::signal_client::{SignalError, SignalEvent, SignalResult, JOIN_RESPONSE_TIMEOUT};
use livekit_protocol as proto;
use tokio::time::timeout; use tokio::time::timeout;
use tokio_tungstenite::tungstenite::Error as WsError; use tokio_tungstenite::tungstenite::Error as WsError;
use tracing::{event, instrument, Level}; use tracing::{event, instrument, Level};
@@ -146,11 +126,13 @@ pub mod utils {
#[instrument(level = Level::DEBUG, skip(receiver))] #[instrument(level = Level::DEBUG, skip(receiver))]
pub(crate) async fn next_join_response( pub(crate) async fn next_join_response(
receiver: &mut SignalEvents, receiver: &mut SignalEvents,
) -> SignalResult<JoinResponse> { ) -> SignalResult<proto::JoinResponse> {
let join = async { let join = async {
while let Some(event) = receiver.recv().await { while let Some(event) = receiver.recv().await {
match event { 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::Close => break,
SignalEvent::Open => continue, SignalEvent::Open => continue,
_ => { _ => {
+1 -1
View File
@@ -1,7 +1,7 @@
use crate::proto;
use crate::signal_client::{SignalEmitter, SignalEvent, SignalOptions, SignalResult}; use crate::signal_client::{SignalEmitter, SignalEvent, SignalOptions, SignalResult};
use futures_util::stream::{SplitSink, SplitStream}; use futures_util::stream::{SplitSink, SplitStream};
use futures_util::{SinkExt, StreamExt}; use futures_util::{SinkExt, StreamExt};
use livekit_protocol as proto;
use prost::Message as ProstMessage; use prost::Message as ProstMessage;
use tokio::net::TcpStream; use tokio::net::TcpStream;
use tokio::sync::{mpsc, oneshot}; use tokio::sync::{mpsc, oneshot};
-209
View File
@@ -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
+426
View File
@@ -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
```
+1
View File
@@ -189,6 +189,7 @@ fn main() {
//.define("WEBRTC_ENABLE_SYMBOL_EXPORT", None) Not necessary when using WebRTC as a static library //.define("WEBRTC_ENABLE_SYMBOL_EXPORT", None) Not necessary when using WebRTC as a static library
.define("NOMINMAX", None); .define("NOMINMAX", None);
} }
"linux" => {}
"macos" => { "macos" => {
println!("cargo:rustc-link-lib=framework=Foundation"); println!("cargo:rustc-link-lib=framework=Foundation");
println!("cargo:rustc-link-lib=framework=AVFoundation"); println!("cargo:rustc-link-lib=framework=AVFoundation");
+5
View File
@@ -1,3 +1,8 @@
.cipd .cipd
src src
.gclient_* .gclient_*
depot_tools
# builds
macos
linux
+77
View File
@@ -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"
+75
View File
@@ -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"
+63
View File
@@ -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)));