Windows + Initial WebRTC sys & Safe WebRTC + Initial livekit-core

This commit is contained in:
Théo Monnom
2022-09-12 12:51:54 +02:00
parent 7b09d6dd51
commit d9fd69b5c0
128 changed files with 4282 additions and 2282 deletions
+2
View File
@@ -0,0 +1,2 @@
[target.x86_64-pc-windows-msvc]
rustflags = ["-C", "target-feature=+crt-static"]
+14
View File
@@ -0,0 +1,14 @@
[package]
name = "livekit-webrtc"
version = "0.1.0"
edition = "2021"
homepage = "https://livekit.io"
[dependencies]
libwebrtc-sys = { path = "./libwebrtc-sys" }
tokio = { version = "1.20.1", features = ["full"] }
cxx = "1.0"
log = "0.4"
[dev-dependencies]
env_logger = "0.9"
@@ -0,0 +1,2 @@
[target.x86_64-pc-windows-msvc]
rustflags = ["-C", "target-feature=+crt-static"]
@@ -0,0 +1,2 @@
/libwebrtc
/cmake-build-debug
@@ -0,0 +1,23 @@
# IMPORTANT NOTE
# This file is just used because some IDEs need to understand how to do autocompletion.
# This file is completely ignored by the library ( See build.rs for the build system )
cmake_minimum_required(VERSION 3.22)
project(livekit-webrtc)
set(CMAKE_CXX_STANDARD 17)
add_definitions(-DWEBRTC_WIN)
include_directories(libwebrtc/include)
include_directories(libwebrtc/include/third_party/abseil-cpp/)
include_directories(libwebrtc/include/third_party/libc++/)
include_directories(include/)
include_directories(../../../target/cxxbridge) # Can be different
file(GLOB_RECURSE SRC src/*.cpp)
add_library(livekit-webrtc ${SRC})
#include_directories(/Users/theomonnom/Library/Android/sdk/ndk/25.0.8775105/toolchains/llvm/prebuilt/darwin-x86_64/sysroot/usr/include)
#find_library(ANDROID_LIB_ANDROID android)
#target_link_libraries(client_sdk_native PRIVATE android)
+213
View File
@@ -0,0 +1,213 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "aho-corasick"
version = "0.7.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
dependencies = [
"memchr",
]
[[package]]
name = "cc"
version = "1.0.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
[[package]]
name = "codespan-reporting"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e"
dependencies = [
"termcolor",
"unicode-width",
]
[[package]]
name = "cxx"
version = "1.0.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "873c2e83af70859af2aaecd1f5d862f3790b747b1f4f50fb45a931d000ac0422"
dependencies = [
"cc",
"cxxbridge-flags",
"cxxbridge-macro",
"link-cplusplus",
]
[[package]]
name = "cxx-build"
version = "1.0.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b49edea7163bbc7a39e3d829b4b0b66a9d30486973152842b7413f2c7b5632bf"
dependencies = [
"cc",
"codespan-reporting",
"once_cell",
"proc-macro2",
"quote",
"scratch",
"syn",
]
[[package]]
name = "cxxbridge-flags"
version = "1.0.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f46b787c15af80277db5c88c6ac6c502ae545e622f010e06f95e540d34931acf"
[[package]]
name = "cxxbridge-macro"
version = "1.0.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ba3f3a7efa46626878fb5d324fabca4d19d2956b6ae97ce43044ef4515f5abc"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "glob"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
[[package]]
name = "link-cplusplus"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8cae2cd7ba2f3f63938b9c724475dfb7b9861b545a90324476324ed21dbc8c8"
dependencies = [
"cc",
]
[[package]]
name = "livekit-native"
version = "0.1.0"
dependencies = [
"cxx",
"cxx-build",
"glob",
"regex",
]
[[package]]
name = "memchr"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]]
name = "once_cell"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1"
[[package]]
name = "proc-macro2"
version = "1.0.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c278e965f1d8cf32d6e0e96de3d3e79712178ae67986d9cf9151f51e95aac89b"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804"
dependencies = [
"proc-macro2",
]
[[package]]
name = "regex"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.6.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244"
[[package]]
name = "scratch"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96311ef4a16462c757bb6a39152c40f58f31cd2602a40fceb937e2bc34e6cbab"
[[package]]
name = "syn"
version = "1.0.98"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "termcolor"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
dependencies = [
"winapi-util",
]
[[package]]
name = "unicode-ident"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15c61ba63f9235225a22310255a29b806b907c9b8c964bcbd0a2c70f3f2deea7"
[[package]]
name = "unicode-width"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
dependencies = [
"winapi",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
@@ -0,0 +1,21 @@
[package]
name = "libwebrtc-sys"
version = "0.1.0"
edition = "2021"
homepage = "https://livekit.io"
[dependencies]
cxx = "1.0"
log = "0.4"
[build-dependencies]
cxx-build = "1.0"
glob = "0.3.0"
regex = "1.0"
cc = { version = "1.0", features = ["parallel"] }
[dev-dependencies]
env_logger = "0.9"
#[lib]
#crate-type = ["staticlib", "cdylib"]
@@ -0,0 +1,255 @@
use std::env;
use std::fs;
use std::io::Write;
use std::path;
use std::process::Command;
use regex::Regex;
const MAC_SDKS: &str =
"/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs";
fn get_mac_sysroot() -> String {
let mut sdks: Vec<String> = vec![];
let files = fs::read_dir(MAC_SDKS).unwrap();
for entry in files {
let entry = entry.unwrap();
let filename = entry.file_name().to_str().unwrap().to_owned();
sdks.push(filename);
}
sdks = sdks
.iter()
.filter(|value| value.contains("MacOSX1"))
.map(|original| original.to_owned())
.collect();
let last = sdks.last().unwrap();
format!("{}/{}", MAC_SDKS, &last)
}
fn macos_link_search_path() -> Option<String> {
let output = Command::new("clang")
.arg("--print-search-dirs")
.output()
.ok()?;
if !output.status.success() {
// Failed to run 'clang --print-search-dirs'.
return None;
}
let stdout = String::from_utf8_lossy(&output.stdout);
for line in stdout.lines() {
if line.contains("libraries: =") {
let path = line.split('=').nth(1)?;
return Some(format!("{}/lib/darwin", path));
}
}
// Failed to determine link search path.
None
}
fn main() {
// TODO Download precompiled binaries of WebRTC for the target_os
let target_os = "windows";
//let target_arch = "arm64";
let libwebrtc_dir = path::PathBuf::from("libwebrtc");
// Just required for the bridge build to succeed.
let includes = &[
path::PathBuf::from("./include"),
libwebrtc_dir.join("include/"),
libwebrtc_dir.join("include/third_party/abseil-cpp/"),
libwebrtc_dir.join("include/third_party/libc++/"),
// For mac & ios
libwebrtc_dir.join("include/sdk/objc"),
libwebrtc_dir.join("include/sdk/objc/base"),
];
let mut builder = cxx_build::bridges(&[
"src/peer_connection.rs",
"src/peer_connection_factory.rs",
"src/media_stream_interface.rs",
"src/data_channel.rs",
"src/jsep.rs",
"src/candidate.rs",
"src/rtp_receiver.rs",
"src/rtp_transceiver.rs",
"src/rtc_error.rs",
]);
builder.file("src/peer_connection.cpp");
builder.file("src/peer_connection_factory.cpp");
builder.file("src/media_stream_interface.cpp");
builder.file("src/data_channel.cpp");
builder.file("src/jsep.cpp");
builder.file("src/candidate.cpp");
builder.file("src/rtp_receiver.cpp");
builder.file("src/rtp_transceiver.cpp");
builder.file("src/rtc_error.cpp");
for include in includes {
builder.include(include);
}
println!(
"cargo:rustc-link-search=native={}",
libwebrtc_dir.canonicalize().unwrap().to_str().unwrap()
);
match target_os {
"windows" => {
println!("cargo:rustc-link-lib=dylib=msdmo");
println!("cargo:rustc-link-lib=dylib=wmcodecdspuuid");
println!("cargo:rustc-link-lib=dylib=dmoguids");
println!("cargo:rustc-link-lib=dylib=crypt32");
println!("cargo:rustc-link-lib=dylib=iphlpapi");
println!("cargo:rustc-link-lib=dylib=ole32");
println!("cargo:rustc-link-lib=dylib=secur32");
println!("cargo:rustc-link-lib=dylib=winmm");
println!("cargo:rustc-link-lib=dylib=ws2_32");
println!("cargo:rustc-link-lib=dylib=strmiids");
println!("cargo:rustc-link-lib=dylib=d3d11");
println!("cargo:rustc-link-lib=dylib=dxgi");
println!("cargo:rustc-link-lib=dylib=dwmapi");
println!("cargo:rustc-link-lib=dylib=webrtc");
builder
.flag("/std:c++17")
.flag("/EHsc")
.define("WEBRTC_WIN", None)
.define("NOMINMAX", None);
}
"macos" => {
println!("cargo:rustc-link-lib=dylib=c++");
println!("cargo:rustc-link-lib=framework=Foundation");
println!("cargo:rustc-link-lib=framework=AVFoundation");
println!("cargo:rustc-link-lib=framework=CoreAudio");
println!("cargo:rustc-link-lib=framework=AudioToolbox");
println!("cargo:rustc-link-lib=framework=Appkit");
println!("cargo:rustc-link-lib=framework=CoreMedia");
println!("cargo:rustc-link-lib=framework=CoreGraphics");
println!("cargo:rustc-link-lib=framework=VideoToolbox");
println!("cargo:rustc-link-lib=framework=CoreVideo");
println!("cargo:rustc-link-lib=framework=OpenGL");
println!("cargo:rustc-link-lib=framework=Metal");
println!("cargo:rustc-link-lib=framework=QuartzCore");
println!("cargo:rustc-link-lib=framework=IOKit");
println!("cargo:rustc-link-lib=framework=IOSurface");
println!("cargo:rustc-link-lib=static=webrtc");
builder
.flag("-stdlib=libc++")
.flag("-std=c++17")
.flag(format!("-isysroot{}", get_mac_sysroot()).as_str())
.define("WEBRTC_ENABLE_OBJC_SYMBOL_EXPORT", None)
.define("WEBRTC_POSIX", None)
.define("WEBRTC_MAC", None);
if let Some(path) = macos_link_search_path() {
println!("cargo:rustc-link-lib=clang_rt.osx");
println!("cargo:rustc-link-search={}", path);
}
}
"ios" => {
builder
.flag("-std=c++17")
.file("src/objc_test.mm")
.define("WEBRTC_ENABLE_OBJC_SYMBOL_EXPORT", None)
.define("WEBRTC_MAC", None)
.define("WEBRTC_POSIX", None)
.define("WEBRTC_IOS", None);
}
"android" => {
let ndk_env = env::var("ANDROID_NDK_HOME").expect(
"ANDROID_NDK_HOME is not set, please set it to the path of your Android NDK",
);
let android_ndk = path::PathBuf::from(ndk_env);
let host_os = if cfg!(target_os = "linux") {
"linux-x86_64"
} else if cfg!(target_os = "macos") {
"darwin-x86_64"
} else if cfg!(target_os = "windows") {
"windows-x86_64"
} else {
panic!("Unsupported host OS");
};
let toolchain = android_ndk.join(std::format!("toolchains/llvm/prebuilt/{}", host_os));
// libgcc ( redirects to libunwind )
println!(
"cargo:rustc-link-search={}",
toolchain.join("lib").to_str().unwrap()
);
// Needed when loading the library in the JVM ( System.loadLibrary )
println!("cargo:rustc-link-lib=egl");
println!("cargo:rustc-link-lib=OpenSLES");
// Find JNI symbols
let readelf_output = std::process::Command::new(toolchain.join("bin/llvm-readelf"))
.arg("-Ws")
.arg(libwebrtc_dir.join("libwebrtc.a"))
.output()
.expect("failed to run llvm-readelf");
// Get all JNI symbols
let jni_regex = Regex::new(r"(Java_org_webrtc.*)").unwrap();
let content = &String::from_utf8_lossy(&readelf_output.stdout);
let mut jni_symbols = Vec::new();
jni_regex.captures_iter(&content).for_each(|cap| {
jni_symbols.push(cap.get(1).unwrap().as_str());
});
// JNI Version Script & Keep JNI symbols
let vs_path = path::PathBuf::from(env::var("OUT_DIR").unwrap()).join("webrtc_jni.map");
let mut vs_file = fs::File::create(&vs_path).unwrap();
builder.file("src/jni_onload.cc");
println!("cargo:rustc-link-arg=-Wl,--undefined=JNI_OnLoad");
write!(vs_file, "JNI_WEBRTC {{\n\tglobal: ").unwrap();
write!(vs_file, "JNI_OnLoad; ").unwrap();
for x in &jni_symbols {
println!("cargo:rustc-link-arg=-Wl,--undefined={}", x);
write!(vs_file, "{}; ", x).unwrap();
}
write!(vs_file, "\n}};").unwrap();
println!(
"cargo:rustc-link-arg=-Wl,--version-script={}",
vs_path.to_str().unwrap()
);
builder
.flag("-std=c++17")
.define("WEBRTC_LINUX", None)
.define("WEBRTC_POSIX", None)
.define("WEBRTC_ANDROID", None);
}
_ => {
panic!("Unsupported target, {}", target_os);
}
}
builder.warnings(false).compile("lkwebrtc");
for entry in glob::glob("./src/**/*.cpp").unwrap() {
println!(
"cargo:rerun-if-changed={}",
entry.unwrap().display().to_string()
);
}
for entry in glob::glob("./include/**/*.h").unwrap() {
println!(
"cargo:rerun-if-changed={}",
entry.unwrap().display().to_string()
);
}
println!("cargo:rerun-if-changed=src/main.rs");
}
@@ -0,0 +1,28 @@
//
// Created by Théo Monnom on 01/09/2022.
//
#ifndef CLIENT_SDK_NATIVE_CANDIDATE_H
#define CLIENT_SDK_NATIVE_CANDIDATE_H
#include <memory>
#include "api/candidate.h"
// cricket::Candidate
namespace livekit {
class Candidate {
public:
explicit Candidate(const cricket::Candidate &candidate);
private:
cricket::Candidate candidate_;
};
static std::unique_ptr<Candidate> _unique_candidate(){
return nullptr;
}
} // livekit
#endif //CLIENT_SDK_NATIVE_CANDIDATE_H
@@ -0,0 +1,26 @@
//
// Created by Théo Monnom on 01/09/2022.
//
#ifndef CLIENT_SDK_NATIVE_DATA_CHANNEL_H
#define CLIENT_SDK_NATIVE_DATA_CHANNEL_H
#include <memory>
#include "api/data_channel_interface.h"
namespace livekit {
class DataChannel {
public:
explicit DataChannel(rtc::scoped_refptr<webrtc::DataChannelInterface> data_channel);
private:
rtc::scoped_refptr<webrtc::DataChannelInterface> data_channel_;
};
static std::unique_ptr<DataChannel> _unique_data_channel(){
return nullptr; // Ignore
}
} // livekit
#endif //CLIENT_SDK_NATIVE_DATA_CHANNEL_H
@@ -0,0 +1,96 @@
//
// Created by Théo Monnom on 01/09/2022.
//
#ifndef CLIENT_SDK_NATIVE_JSEP_H
#define CLIENT_SDK_NATIVE_JSEP_H
#include <memory>
#include "api/jsep.h"
#include "rust/cxx.h"
#include "rust_types.h"
#include "api/ref_counted_base.h"
namespace livekit {
class IceCandidate {
public:
explicit IceCandidate(std::unique_ptr<webrtc::IceCandidateInterface> ice_candidate);
private:
std::unique_ptr<webrtc::IceCandidateInterface> ice_candidate_;
};
static std::unique_ptr<IceCandidate> _unique_ice_candidate(){
return nullptr; // Ignore
}
class SessionDescription {
public:
explicit SessionDescription(std::unique_ptr<webrtc::SessionDescriptionInterface> session_description);
std::unique_ptr<SessionDescription> clone() const;
std::unique_ptr<webrtc::SessionDescriptionInterface> release();
private:
std::unique_ptr<webrtc::SessionDescriptionInterface> session_description_;
};
static std::unique_ptr<SessionDescription> _unique_session_description(){
return nullptr; // Ignore
}
// SetCreateSdpObserver
class NativeCreateSdpObserver : public webrtc::CreateSessionDescriptionObserver {
public:
explicit NativeCreateSdpObserver(rust::Box<CreateSdpObserverWrapper> observer);
void OnSuccess(webrtc::SessionDescriptionInterface* desc) override;
void OnFailure(webrtc::RTCError error) override;
private:
rust::Box<CreateSdpObserverWrapper> observer_;
};
struct NativeCreateSdpObserverHandle {
rtc::scoped_refptr<NativeCreateSdpObserver> observer;
};
std::unique_ptr<NativeCreateSdpObserverHandle> create_native_create_sdp_observer(rust::Box<CreateSdpObserverWrapper> observer);
// SetLocalSdpObserver
class NativeSetLocalSdpObserver : public webrtc::SetLocalDescriptionObserverInterface{
public:
explicit NativeSetLocalSdpObserver(rust::Box<SetLocalSdpObserverWrapper> observer);
void OnSetLocalDescriptionComplete(webrtc::RTCError error) override;
private:
rust::Box<SetLocalSdpObserverWrapper> observer_;
};
struct NativeSetLocalSdpObserverHandle {
rtc::scoped_refptr<NativeSetLocalSdpObserver> observer;
};
std::unique_ptr<NativeSetLocalSdpObserverHandle> create_native_set_local_sdp_observer(rust::Box<SetLocalSdpObserverWrapper> observer);
// SetRemoteSdpObserver
class NativeSetRemoteSdpObserver : public webrtc::SetRemoteDescriptionObserverInterface{
public:
explicit NativeSetRemoteSdpObserver(rust::Box<SetRemoteSdpObserverWrapper> observer);
void OnSetRemoteDescriptionComplete(webrtc::RTCError error) override;
private:
rust::Box<SetRemoteSdpObserverWrapper> observer_;
};
struct NativeSetRemoteSdpObserverHandle {
rtc::scoped_refptr<NativeSetRemoteSdpObserver> observer;
};
std::unique_ptr<NativeSetRemoteSdpObserverHandle> create_native_set_remote_sdp_observer(rust::Box<SetRemoteSdpObserverWrapper> observer);
} // livekit
#endif //CLIENT_SDK_NATIVE_JSEP_H
@@ -0,0 +1,26 @@
//
// Created by Théo Monnom on 31/08/2022.
//
#ifndef CLIENT_SDK_NATIVE_MEDIA_STREAM_INTERFACE_H
#define CLIENT_SDK_NATIVE_MEDIA_STREAM_INTERFACE_H
#include <memory>
#include "api/media_stream_interface.h"
namespace livekit {
class MediaStreamInterface {
public:
explicit MediaStreamInterface(rtc::scoped_refptr<webrtc::MediaStreamInterface> stream);
private:
rtc::scoped_refptr<webrtc::MediaStreamInterface> media_stream_;
};
static std::unique_ptr<MediaStreamInterface> _unique_media_stream(){
return nullptr; // Ignore
}
} // livekit
#endif //CLIENT_SDK_NATIVE_MEDIA_STREAM_INTERFACE_H
@@ -0,0 +1,71 @@
//
// Created by Théo Monnom on 30/08/2022.
//
#ifndef CLIENT_SDK_NATIVE_PEER_CONNECTION_H
#define CLIENT_SDK_NATIVE_PEER_CONNECTION_H
#include <memory>
#include "api/peer_connection_interface.h"
#include "rust/cxx.h"
#include "data_channel.h"
#include "jsep.h"
#include "rust_types.h"
namespace livekit {
class NativePeerConnectionObserver;
class PeerConnection {
public:
explicit PeerConnection(rtc::scoped_refptr<webrtc::PeerConnectionInterface> peer_connection, std::unique_ptr<NativePeerConnectionObserver> observer);
void close();
void create_offer(std::unique_ptr<NativeCreateSdpObserverHandle> observer, RTCOfferAnswerOptions options);
void create_answer(std::unique_ptr<NativeCreateSdpObserverHandle> observer, RTCOfferAnswerOptions options);
void set_local_description(std::unique_ptr<SessionDescription> desc, std::unique_ptr<NativeSetLocalSdpObserverHandle> observer);
void set_remote_description(std::unique_ptr<SessionDescription> desc, std::unique_ptr<NativeSetRemoteSdpObserverHandle> observer);
private:
rtc::scoped_refptr<webrtc::PeerConnectionInterface> peer_connection_;
std::unique_ptr<NativePeerConnectionObserver> observer_;
};
static std::unique_ptr<PeerConnection> _unique_peer_connection() {
return nullptr; // Ignore
}
class NativePeerConnectionObserver : public webrtc::PeerConnectionObserver {
public:
explicit NativePeerConnectionObserver(rust::Box<PeerConnectionObserverWrapper> observer);
~NativePeerConnectionObserver() override = default;
void OnSignalingChange(webrtc::PeerConnectionInterface::SignalingState new_state) override;
void OnAddStream(rtc::scoped_refptr<webrtc::MediaStreamInterface> stream) override;
void OnRemoveStream(rtc::scoped_refptr<webrtc::MediaStreamInterface> stream) override;
void OnDataChannel(rtc::scoped_refptr<webrtc::DataChannelInterface> data_channel) override;
void OnRenegotiationNeeded() override;
void OnNegotiationNeededEvent(uint32_t event_id) override;
void OnIceConnectionChange(webrtc::PeerConnectionInterface::IceConnectionState new_state) override;
void OnStandardizedIceConnectionChange(webrtc::PeerConnectionInterface::IceConnectionState new_state) override;
void OnConnectionChange(webrtc::PeerConnectionInterface::PeerConnectionState new_state) override;
void OnIceGatheringChange(webrtc::PeerConnectionInterface::IceGatheringState new_state) override;
void OnIceCandidate(const webrtc::IceCandidateInterface *candidate) override;
void OnIceCandidateError(const std::string &address, int port, const std::string &url, int error_code, const std::string &error_text) override;
void OnIceCandidatesRemoved(const std::vector<cricket::Candidate> &candidates) override;
void OnIceConnectionReceivingChange(bool receiving) override;
void OnIceSelectedCandidatePairChanged(const cricket::CandidatePairChangeEvent &event) override;
void OnAddTrack(rtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver, const std::vector<rtc::scoped_refptr<webrtc::MediaStreamInterface>> &streams) override;
void OnTrack(rtc::scoped_refptr<webrtc::RtpTransceiverInterface> transceiver) override;
void OnRemoveTrack(rtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver) override;
void OnInterestingUsage(int usage_pattern) override;
private:
rust::Box<PeerConnectionObserverWrapper> observer_;
};
std::unique_ptr<NativePeerConnectionObserver> create_native_peer_connection_observer(rust::Box<PeerConnectionObserverWrapper> observer);
} // livekit
#endif //CLIENT_SDK_NATIVE_PEER_CONNECTION_H
@@ -0,0 +1,35 @@
//
// Created by Théo Monnom on 03/08/2022.
//
#ifndef PEER_CONNECTION_FACTORY_H
#define PEER_CONNECTION_FACTORY_H
#include "api/peer_connection_interface.h"
#include "peer_connection.h"
#include "rust_types.h"
namespace livekit {
using NativeRTCConfiguration = webrtc::PeerConnectionInterface::RTCConfiguration;
class PeerConnectionFactory {
public:
PeerConnectionFactory();
std::unique_ptr<PeerConnection> create_peer_connection(std::unique_ptr<NativeRTCConfiguration> config, std::unique_ptr<NativePeerConnectionObserver> observer) const;
private:
std::unique_ptr<rtc::Thread> network_thread_;
std::unique_ptr<rtc::Thread> worker_thread_;
std::unique_ptr<rtc::Thread> signaling_thread_;
rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> peer_factory_;
};
std::unique_ptr<PeerConnectionFactory> create_peer_connection_factory();
std::unique_ptr<NativeRTCConfiguration> create_rtc_configuration(RTCConfiguration conf);
} // livekit
#endif //PEER_CONNECTION_FACTORY_H
@@ -0,0 +1,25 @@
//
// Created by theom on 04/09/2022.
//
#ifndef CLIENT_SDK_NATIVE_RTC_ERROR_H
#define CLIENT_SDK_NATIVE_RTC_ERROR_H
#include "api/rtc_error.h"
namespace livekit {
class RTCError {
public:
explicit RTCError(webrtc::RTCError error);
private:
webrtc::RTCError rtc_error_;
};
static std::unique_ptr<RTCError> _unique_rtc_error(){
return nullptr; // Ignore
}
} // livekit
#endif //CLIENT_SDK_NATIVE_RTC_ERROR_H
@@ -0,0 +1,26 @@
//
// Created by Théo Monnom on 01/09/2022.
//
#ifndef CLIENT_SDK_NATIVE_RTP_RECEIVER_H
#define CLIENT_SDK_NATIVE_RTP_RECEIVER_H
#include <memory>
#include "api/rtp_receiver_interface.h"
namespace livekit {
class RtpReceiver {
public:
explicit RtpReceiver(rtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver);
private:
rtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver_;
};
static std::unique_ptr<RtpReceiver> _unique_rtp_receiver(){
return nullptr; // Ignore
}
} // livekit
#endif //CLIENT_SDK_NATIVE_RTP_RECEIVER_H
@@ -0,0 +1,26 @@
//
// Created by Théo Monnom on 02/09/2022.
//
#ifndef CLIENT_SDK_NATIVE_RTP_TRANSCEIVER_H
#define CLIENT_SDK_NATIVE_RTP_TRANSCEIVER_H
#include <memory>
#include "api/rtp_transceiver_interface.h"
namespace livekit {
class RtpTransceiver {
public:
explicit RtpTransceiver(rtc::scoped_refptr<webrtc::RtpTransceiverInterface> transceiver);
private:
rtc::scoped_refptr<webrtc::RtpTransceiverInterface> transceiver_;
};
static std::unique_ptr<RtpTransceiver> _unique_rtp_transceiver(){
return nullptr; // Ignore
}
} // livekit
#endif //CLIENT_SDK_NATIVE_RTP_TRANSCEIVER_H
@@ -0,0 +1,22 @@
//
// Created by Théo Monnom on 30/08/2022.
//
#ifndef RUST_TYPES_H
#define RUST_TYPES_H
#include "api/peer_connection_interface.h"
namespace livekit {
struct RTCConfiguration;
struct PeerConnectionObserverWrapper;
struct CreateSdpObserverWrapper;
struct SetLocalSdpObserverWrapper;
struct SetRemoteSdpObserverWrapper;
// Shared types
struct RTCOfferAnswerOptions;
}
#endif //RUST_TYPES_H
@@ -0,0 +1,11 @@
//
// Created by Théo Monnom on 01/09/2022.
//
#include "livekit/candidate.h"
namespace livekit {
Candidate::Candidate(const cricket::Candidate &candidate) : candidate_(candidate) {
}
} // livekit
@@ -0,0 +1,12 @@
use cxx::UniquePtr;
#[cxx::bridge(namespace = "livekit")]
pub mod ffi {
unsafe extern "C++" {
include!("livekit/candidate.h");
type Candidate; // cricket::Candidate
fn _unique_candidate() -> UniquePtr<Candidate>; // Ignore
}
}
@@ -0,0 +1,12 @@
//
// Created by Théo Monnom on 01/09/2022.
//
#include "livekit/data_channel.h"
namespace livekit {
DataChannel::DataChannel(rtc::scoped_refptr<webrtc::DataChannelInterface> data_channel) : data_channel_(data_channel) {
}
} // livekit
@@ -0,0 +1,12 @@
use cxx::UniquePtr;
#[cxx::bridge(namespace = "livekit")]
pub mod ffi {
unsafe extern "C++" {
include!("livekit/data_channel.h");
type DataChannel;
fn _unique_data_channel() -> UniquePtr<DataChannel>; // Ignore
}
}
@@ -0,0 +1,83 @@
//
// Created by Théo Monnom on 01/09/2022.
//
#include <memory>
#include "livekit/jsep.h"
#include "libwebrtc-sys/src/jsep.rs.h"
#include "api/make_ref_counted.h"
namespace livekit {
IceCandidate::IceCandidate(std::unique_ptr<webrtc::IceCandidateInterface> ice_candidate) : ice_candidate_(std::move(ice_candidate)){
}
SessionDescription::SessionDescription(std::unique_ptr<webrtc::SessionDescriptionInterface> session_description) : session_description_(std::move(session_description)){
}
std::unique_ptr<SessionDescription> SessionDescription::clone() const {
return std::make_unique<SessionDescription>(session_description_->Clone());
}
std::unique_ptr<webrtc::SessionDescriptionInterface> SessionDescription::release() {
return std::move(session_description_);
}
// CreateSdpObserver
NativeCreateSdpObserver::NativeCreateSdpObserver(
rust::Box<CreateSdpObserverWrapper> observer) : observer_(std::move(observer)) {
}
void NativeCreateSdpObserver::OnSuccess(webrtc::SessionDescriptionInterface *desc) {
// We have ownership of desc
observer_->on_success(std::make_unique<SessionDescription>(std::unique_ptr<webrtc::SessionDescriptionInterface>(desc)));
}
void NativeCreateSdpObserver::OnFailure(webrtc::RTCError error) {
observer_->on_failure(std::make_unique<RTCError>(error));
}
std::unique_ptr<NativeCreateSdpObserverHandle> create_native_create_sdp_observer(rust::Box<CreateSdpObserverWrapper> observer){
return std::make_unique<NativeCreateSdpObserverHandle>(NativeCreateSdpObserverHandle {
rtc::make_ref_counted<NativeCreateSdpObserver>(std::move(observer))
});
}
// SetLocalSdpObserver
NativeSetLocalSdpObserver::NativeSetLocalSdpObserver(rust::Box<SetLocalSdpObserverWrapper> observer) : observer_(std::move(observer)) {
}
void NativeSetLocalSdpObserver::OnSetLocalDescriptionComplete(webrtc::RTCError error) {
observer_->on_set_local_description_complete(std::make_unique<RTCError>(error));
}
std::unique_ptr<NativeSetLocalSdpObserverHandle> create_native_set_local_sdp_observer(rust::Box<SetLocalSdpObserverWrapper> observer){
return std::make_unique<NativeSetLocalSdpObserverHandle>(NativeSetLocalSdpObserverHandle {
rtc::make_ref_counted<NativeSetLocalSdpObserver>(std::move(observer))
});
}
// SetRemoteSdpObserver
NativeSetRemoteSdpObserver::NativeSetRemoteSdpObserver(rust::Box<SetRemoteSdpObserverWrapper> observer) : observer_(std::move(observer)) {
}
void NativeSetRemoteSdpObserver::OnSetRemoteDescriptionComplete(webrtc::RTCError error) {
observer_->on_set_remote_description_complete(std::make_unique<RTCError>(error));
}
std::unique_ptr<NativeSetRemoteSdpObserverHandle> create_native_set_remote_sdp_observer(rust::Box<SetRemoteSdpObserverWrapper> observer){
return std::make_unique<NativeSetRemoteSdpObserverHandle>(NativeSetRemoteSdpObserverHandle {
rtc::make_ref_counted<NativeSetRemoteSdpObserver>(std::move(observer))
});
}
} // livekit
@@ -0,0 +1,109 @@
use cxx::UniquePtr;
use cxx::{type_id, ExternType};
use crate::rtc_error::ffi::RTCError;
#[cxx::bridge(namespace = "livekit")]
pub mod ffi {
extern "Rust" {
type CreateSdpObserverWrapper;
fn on_success(self: &CreateSdpObserverWrapper, session_description: UniquePtr<SessionDescription>);
fn on_failure(self: &CreateSdpObserverWrapper, error: UniquePtr<RTCError>);
type SetLocalSdpObserverWrapper;
fn on_set_local_description_complete(self: &SetLocalSdpObserverWrapper, error: UniquePtr<RTCError>);
type SetRemoteSdpObserverWrapper;
fn on_set_remote_description_complete(self: &SetRemoteSdpObserverWrapper, error: UniquePtr<RTCError>);
}
unsafe extern "C++" {
include!("livekit/jsep.h");
include!("livekit/rtc_error.h");
type RTCError = crate::rtc_error::ffi::RTCError;
type IceCandidate;
type SessionDescription;
type NativeCreateSdpObserverHandle;
type NativeSetLocalSdpObserverHandle;
type NativeSetRemoteSdpObserverHandle;
fn create_native_create_sdp_observer(observer: Box<CreateSdpObserverWrapper>) -> UniquePtr<NativeCreateSdpObserverHandle>;
fn create_native_set_local_sdp_observer(observer: Box<SetLocalSdpObserverWrapper>) -> UniquePtr<NativeSetLocalSdpObserverHandle>;
fn create_native_set_remote_sdp_observer(observer: Box<SetRemoteSdpObserverWrapper>) -> UniquePtr<NativeSetRemoteSdpObserverHandle>;
fn _unique_ice_candidate() -> UniquePtr<IceCandidate>; // Ignore
fn _unique_session_description() -> UniquePtr<SessionDescription>; // Ignore
}
}
// CreateSdpObserver
pub trait CreateSdpObserver: Send + Sync {
fn on_success(&self, session_description: UniquePtr<ffi::SessionDescription>);
fn on_failure(&self, error: UniquePtr<RTCError>);
}
pub struct CreateSdpObserverWrapper {
observer: Box<dyn CreateSdpObserver>,
}
impl CreateSdpObserverWrapper {
pub fn new(observer: Box<dyn CreateSdpObserver>) -> Self {
Self {
observer
}
}
fn on_success(&self, session_description: UniquePtr<ffi::SessionDescription>) {
self.observer.on_success(session_description);
}
fn on_failure(&self, error: UniquePtr<RTCError>) {
self.observer.on_failure(error);
}
}
// SetLocalSdpObserver
pub trait SetLocalSdpObserver: Send + Sync {
fn on_set_local_description_complete(&self, error: UniquePtr<RTCError>);
}
pub struct SetLocalSdpObserverWrapper {
observer: Box<dyn SetLocalSdpObserver>,
}
impl SetLocalSdpObserverWrapper {
pub fn new(observer: Box<dyn SetLocalSdpObserver>) -> Self {
Self {
observer
}
}
fn on_set_local_description_complete(&self, error: UniquePtr<RTCError>) {
self.observer.on_set_local_description_complete(error);
}
}
// SetRemoteSdpObserver
pub trait SetRemoteSdpObserver: Send + Sync {
fn on_set_remote_description_complete(&self, error: UniquePtr<RTCError>);
}
pub struct SetRemoteSdpObserverWrapper {
observer: Box<dyn SetRemoteSdpObserver>,
}
impl SetRemoteSdpObserverWrapper {
pub fn new(observer: Box<dyn SetRemoteSdpObserver>) -> Self {
Self {
observer
}
}
fn on_set_remote_description_complete(&self, error: UniquePtr<RTCError>) {
self.observer.on_set_remote_description_complete(error);
}
}
@@ -0,0 +1,10 @@
pub mod media_stream_interface;
pub mod peer_connection;
pub mod peer_connection_factory;
pub mod data_channel;
pub mod jsep;
pub mod candidate;
pub mod rtp_receiver;
pub mod rtp_transceiver;
pub mod rtc_error;
@@ -0,0 +1,12 @@
//
// Created by Théo Monnom on 31/08/2022.
//
#include "livekit/media_stream_interface.h"
namespace livekit {
MediaStreamInterface::MediaStreamInterface(rtc::scoped_refptr<webrtc::MediaStreamInterface> stream) : media_stream_(stream) {
}
} // livekit
@@ -0,0 +1,13 @@
use cxx::UniquePtr;
#[cxx::bridge(namespace = "livekit")]
pub mod ffi {
unsafe extern "C++" {
include!("livekit/media_stream_interface.h");
type MediaStreamInterface;
fn _unique_media_stream() -> UniquePtr<MediaStreamInterface>; // Ignore
}
}
@@ -0,0 +1,166 @@
//
// Created by Théo Monnom on 30/08/2022.
//
#include "livekit/peer_connection.h"
#include "libwebrtc-sys/src/peer_connection.rs.h"
namespace livekit {
inline webrtc::PeerConnectionInterface::RTCOfferAnswerOptions toNativeOfferAnswerOptions(const RTCOfferAnswerOptions& options) {
webrtc::PeerConnectionInterface::RTCOfferAnswerOptions rtc_options;
rtc_options.offer_to_receive_video = options.offer_to_receive_video;
rtc_options.offer_to_receive_audio = options.offer_to_receive_audio;
rtc_options.voice_activity_detection = options.voice_activity_detection;
rtc_options.ice_restart = options.ice_restart;
rtc_options.use_rtp_mux = options.use_rtp_mux;
rtc_options.raw_packetization_for_video = options.raw_packetization_for_video;
rtc_options.num_simulcast_layers = options.num_simulcast_layers;
rtc_options.use_obsolete_sctp_sdp = options.use_obsolete_sctp_sdp;
return rtc_options;
}
PeerConnection::PeerConnection(rtc::scoped_refptr<webrtc::PeerConnectionInterface> peer_connection,
std::unique_ptr<NativePeerConnectionObserver> observer) : peer_connection_(
std::move(peer_connection)), observer_(std::move(observer)) {
}
void PeerConnection::close() {
peer_connection_->Close();
}
void PeerConnection::create_offer(std::unique_ptr<NativeCreateSdpObserverHandle> observer_handle, RTCOfferAnswerOptions options) {
peer_connection_->CreateOffer(observer_handle->observer.get(), toNativeOfferAnswerOptions(options));
}
void PeerConnection::create_answer(std::unique_ptr<NativeCreateSdpObserverHandle> observer_handle, RTCOfferAnswerOptions options) {
peer_connection_->CreateAnswer(observer_handle->observer.get(), toNativeOfferAnswerOptions(options));
}
void PeerConnection::set_local_description(std::unique_ptr<SessionDescription> desc, std::unique_ptr<NativeSetLocalSdpObserverHandle> observer) {
peer_connection_->SetLocalDescription(desc->clone()->release(), observer->observer);
}
void PeerConnection::set_remote_description(std::unique_ptr<SessionDescription> desc, std::unique_ptr<NativeSetRemoteSdpObserverHandle> observer) {
peer_connection_->SetRemoteDescription(desc->clone()->release(), observer->observer);
}
/* Observer */
NativePeerConnectionObserver::NativePeerConnectionObserver(rust::Box<PeerConnectionObserverWrapper> observer) : observer_(std::move(observer)) {
}
void NativePeerConnectionObserver::OnSignalingChange(webrtc::PeerConnectionInterface::SignalingState new_state) {
observer_->on_signaling_change(static_cast<SignalingState>(new_state));
}
void NativePeerConnectionObserver::OnAddStream(rtc::scoped_refptr<webrtc::MediaStreamInterface> stream) {
observer_->on_add_stream(std::make_unique<MediaStreamInterface>(stream));
}
void NativePeerConnectionObserver::OnRemoveStream(rtc::scoped_refptr<webrtc::MediaStreamInterface> stream) {
observer_->on_remove_stream(std::make_unique<MediaStreamInterface>(stream));
}
void NativePeerConnectionObserver::OnDataChannel(rtc::scoped_refptr<webrtc::DataChannelInterface> data_channel) {
observer_->on_data_channel(std::make_unique<DataChannel>(data_channel));
}
void NativePeerConnectionObserver::OnRenegotiationNeeded() {
observer_->on_renegotiation_needed();
}
void NativePeerConnectionObserver::OnNegotiationNeededEvent(uint32_t event_id) {
observer_->on_negotiation_needed_event(event_id);
}
void
NativePeerConnectionObserver::OnIceConnectionChange(webrtc::PeerConnectionInterface::IceConnectionState new_state) {
observer_->on_ice_connection_change(static_cast<IceConnectionState>(new_state));
}
void NativePeerConnectionObserver::OnStandardizedIceConnectionChange(
webrtc::PeerConnectionInterface::IceConnectionState new_state) {
observer_->on_standardized_ice_connection_change(static_cast<IceConnectionState>(new_state));
}
void
NativePeerConnectionObserver::OnConnectionChange(webrtc::PeerConnectionInterface::PeerConnectionState new_state) {
observer_->on_connection_change(static_cast<PeerConnectionState>(new_state));
}
void
NativePeerConnectionObserver::OnIceGatheringChange(webrtc::PeerConnectionInterface::IceGatheringState new_state) {
observer_->on_ice_gathering_change(static_cast<IceGatheringState>(new_state));
}
void NativePeerConnectionObserver::OnIceCandidate(const webrtc::IceCandidateInterface *candidate) {
auto new_candidate = webrtc::CreateIceCandidate(candidate->sdp_mid(), candidate->sdp_mline_index(),
candidate->candidate());
observer_->on_ice_candidate(std::make_unique<IceCandidate>(std::move(new_candidate)));
}
void NativePeerConnectionObserver::OnIceCandidateError(const std::string &address, int port, const std::string &url,
int error_code, const std::string &error_text) {
observer_->on_ice_candidate_error(address, port, url, error_code, error_text);
}
void NativePeerConnectionObserver::OnIceCandidatesRemoved(const std::vector<cricket::Candidate> &candidates) {
rust::Vec<CandidatePtr> vec;
for (const auto &item: candidates) {
vec.push_back(CandidatePtr{
std::make_unique<Candidate>(item)
});
}
observer_->on_ice_candidates_removed(std::move(vec));
}
void NativePeerConnectionObserver::OnIceConnectionReceivingChange(bool receiving) {
observer_->on_ice_connection_receiving_change(receiving);
}
void
NativePeerConnectionObserver::OnIceSelectedCandidatePairChanged(const cricket::CandidatePairChangeEvent &event) {
CandidatePairChangeEvent e;
e.selected_candidate_pair.local = std::make_unique<Candidate>(event.selected_candidate_pair.local);
e.selected_candidate_pair.remote = std::make_unique<Candidate>(event.selected_candidate_pair.remote);
e.last_data_received_ms = event.last_data_received_ms;
e.reason = event.reason;
e.estimated_disconnected_time_ms = event.estimated_disconnected_time_ms;
observer_->on_ice_selected_candidate_pair_changed(std::move(e));
}
void NativePeerConnectionObserver::OnAddTrack(rtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver,
const std::vector<rtc::scoped_refptr<webrtc::MediaStreamInterface>> &streams) {
rust::Vec<MediaStreamPtr> vec;
for (const auto &item: streams) {
vec.push_back(MediaStreamPtr{
std::make_unique<MediaStreamInterface>(item)
});
}
observer_->on_add_track(std::make_unique<RtpReceiver>(receiver), std::move(vec));
}
void NativePeerConnectionObserver::OnTrack(rtc::scoped_refptr<webrtc::RtpTransceiverInterface> transceiver) {
observer_->on_track(std::make_unique<RtpTransceiver>(transceiver));
}
void NativePeerConnectionObserver::OnRemoveTrack(rtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver) {
observer_->on_remove_track(std::make_unique<RtpReceiver>(receiver));
}
void NativePeerConnectionObserver::OnInterestingUsage(int usage_pattern) {
observer_->on_interesting_usage(usage_pattern);
}
std::unique_ptr<NativePeerConnectionObserver> create_native_peer_connection_observer(rust::Box<PeerConnectionObserverWrapper> observer) {
return std::make_unique<NativePeerConnectionObserver>(std::move(observer));
}
} // livekit
@@ -0,0 +1,293 @@
use cxx::UniquePtr;
use crate::candidate::ffi::Candidate;
use crate::data_channel::ffi::DataChannel;
use crate::jsep::ffi::IceCandidate;
use crate::media_stream_interface::ffi::MediaStreamInterface;
use crate::rtp_receiver::ffi::RtpReceiver;
use crate::rtp_transceiver::ffi::RtpTransceiver;
#[cxx::bridge(namespace = "livekit")]
pub mod ffi {
struct CandidatePair {
local: UniquePtr<Candidate>,
remote: UniquePtr<Candidate>,
}
struct CandidatePairChangeEvent {
selected_candidate_pair: CandidatePair,
last_data_received_ms: i64,
reason: String,
estimated_disconnected_time_ms: i64,
}
#[derive(Debug)]
#[repr(u32)]
pub enum PeerConnectionState {
kNew,
kConnecting,
kConnected,
kDisconnected,
kFailed,
kClosed,
}
#[derive(Debug)]
#[repr(u32)]
pub enum SignalingState {
kStable,
kHaveLocalOffer,
kHaveLocalPrAnswer,
kHaveRemoteOffer,
kHaveRemotePrAnswer,
kClosed,
}
#[derive(Debug)]
#[repr(u32)]
pub enum IceConnectionState {
kIceConnectionNew,
kIceConnectionChecking,
kIceConnectionConnected,
kIceConnectionCompleted,
kIceConnectionFailed,
kIceConnectionDisconnected,
kIceConnectionClosed,
kIceConnectionMax,
}
#[derive(Debug)]
#[repr(u32)]
pub enum IceGatheringState {
kIceGatheringNew,
kIceGatheringGathering,
kIceGatheringComplete
}
#[derive(Debug)]
pub struct RTCOfferAnswerOptions {
offer_to_receive_video: i32,
offer_to_receive_audio: i32,
voice_activity_detection: bool,
ice_restart: bool,
use_rtp_mux: bool,
raw_packetization_for_video: bool,
num_simulcast_layers: i32,
use_obsolete_sctp_sdp: bool,
}
// Wrapper to opaque C++ objects
// https://github.com/dtolnay/cxx/issues/741
struct MediaStreamPtr {
pub ptr: UniquePtr<MediaStreamInterface>
}
struct CandidatePtr {
pub ptr: UniquePtr<Candidate>
}
unsafe extern "C++" {
include!("livekit/peer_connection.h");
include!("livekit/jsep.h");
include!("livekit/data_channel.h");
include!("livekit/rtp_receiver.h");
include!("livekit/rtp_transceiver.h");
include!("livekit/media_stream_interface.h");
include!("livekit/candidate.h");
type Candidate = crate::candidate::ffi::Candidate;
type IceCandidate = crate::jsep::ffi::IceCandidate;
type DataChannel = crate::data_channel::ffi::DataChannel;
type RtpReceiver = crate::rtp_receiver::ffi::RtpReceiver;
type RtpTransceiver = crate::rtp_transceiver::ffi::RtpTransceiver;
type MediaStreamInterface = crate::media_stream_interface::ffi::MediaStreamInterface;
type NativeCreateSdpObserverHandle = crate::jsep::ffi::NativeCreateSdpObserverHandle;
type NativeSetLocalSdpObserverHandle = crate::jsep::ffi::NativeSetLocalSdpObserverHandle;
type NativeSetRemoteSdpObserverHandle = crate::jsep::ffi::NativeSetRemoteSdpObserverHandle;
type SessionDescription = crate::jsep::ffi::SessionDescription;
type NativePeerConnectionObserver;
type PeerConnection;
fn create_offer(self: Pin<&mut PeerConnection>, observer: UniquePtr<NativeCreateSdpObserverHandle>, options: RTCOfferAnswerOptions);
fn create_answer(self: Pin<&mut PeerConnection>, observer: UniquePtr<NativeCreateSdpObserverHandle>, options: RTCOfferAnswerOptions);
fn set_local_description(self: Pin<&mut PeerConnection>, desc: UniquePtr<SessionDescription>, observer: UniquePtr<NativeSetLocalSdpObserverHandle>);
fn set_remote_description(self: Pin<&mut PeerConnection>, desc: UniquePtr<SessionDescription>, observer: UniquePtr<NativeSetRemoteSdpObserverHandle>);
fn close(self: Pin<&mut PeerConnection>);
fn create_native_peer_connection_observer(observer: Box<PeerConnectionObserverWrapper>) -> UniquePtr<NativePeerConnectionObserver>;
fn _unique_peer_connection() -> UniquePtr<PeerConnection>; // Ignore
}
extern "Rust" {
type PeerConnectionObserverWrapper;
fn on_signaling_change(self: &mut PeerConnectionObserverWrapper, new_state: SignalingState);
fn on_add_stream(self: &mut PeerConnectionObserverWrapper, stream: UniquePtr<MediaStreamInterface>);
fn on_remove_stream(self: &mut PeerConnectionObserverWrapper, stream: UniquePtr<MediaStreamInterface>);
fn on_data_channel(self: &mut PeerConnectionObserverWrapper, data_channel: UniquePtr<DataChannel>);
fn on_renegotiation_needed(self: &mut PeerConnectionObserverWrapper);
fn on_negotiation_needed_event(self: &mut PeerConnectionObserverWrapper, event: u32);
fn on_ice_connection_change(self: &mut PeerConnectionObserverWrapper, new_state: IceConnectionState);
fn on_standardized_ice_connection_change(self: &mut PeerConnectionObserverWrapper, new_state: IceConnectionState);
fn on_connection_change(self: &mut PeerConnectionObserverWrapper, new_state: PeerConnectionState);
fn on_ice_gathering_change(self: &mut PeerConnectionObserverWrapper, new_state: IceGatheringState);
fn on_ice_candidate(self: &mut PeerConnectionObserverWrapper, candidate: UniquePtr<IceCandidate>);
fn on_ice_candidate_error(self: &mut PeerConnectionObserverWrapper, address: String, port: i32, url: String, error_code: i32, error_text: String);
fn on_ice_candidates_removed(self: &mut PeerConnectionObserverWrapper, removed: Vec<CandidatePtr>);
fn on_ice_connection_receiving_change(self: &mut PeerConnectionObserverWrapper, receiving: bool);
fn on_ice_selected_candidate_pair_changed(self: &mut PeerConnectionObserverWrapper, event: CandidatePairChangeEvent);
fn on_add_track(self: &mut PeerConnectionObserverWrapper, receiver: UniquePtr<RtpReceiver>, streams: Vec<MediaStreamPtr>);
fn on_track(self: &mut PeerConnectionObserverWrapper, transceiver: UniquePtr<RtpTransceiver>);
fn on_remove_track(self: &mut PeerConnectionObserverWrapper, receiver: UniquePtr<RtpReceiver>);
fn on_interesting_usage(self: &mut PeerConnectionObserverWrapper, usage_pattern: i32);
}
}
// https://webrtc.github.io/webrtc-org/native-code/native-apis/
unsafe impl Sync for ffi::PeerConnection {}
unsafe impl Send for ffi::PeerConnection {}
impl Default for ffi::RTCOfferAnswerOptions {
/*
static const int kUndefined = -1;
static const int kMaxOfferToReceiveMedia = 1;
static const int kOfferToReceiveMediaTrue = 1;
*/
fn default() -> Self {
Self {
offer_to_receive_video: -1,
offer_to_receive_audio: -1,
voice_activity_detection: true,
ice_restart: false,
use_rtp_mux: true,
raw_packetization_for_video: false,
num_simulcast_layers: 1,
use_obsolete_sctp_sdp: false
}
}
}
pub trait PeerConnectionObserver: Send + Sync {
fn on_signaling_change(&mut self, new_state: ffi::SignalingState);
fn on_add_stream(&mut self, stream: UniquePtr<MediaStreamInterface>);
fn on_remove_stream(&mut self, stream: UniquePtr<MediaStreamInterface>);
fn on_data_channel(&mut self, data_channel: UniquePtr<DataChannel>);
fn on_renegotiation_needed(&mut self);
fn on_negotiation_needed_event(&mut self, event: u32);
fn on_ice_connection_change(&mut self, new_state: ffi::IceConnectionState);
fn on_standardized_ice_connection_change(&mut self, new_state: ffi::IceConnectionState);
fn on_connection_change(&mut self, new_state: ffi::PeerConnectionState);
fn on_ice_gathering_change(&mut self, new_state: ffi::IceGatheringState);
fn on_ice_candidate(&mut self, candidate: UniquePtr<IceCandidate>);
fn on_ice_candidate_error(&mut self, address: String, port: i32, url: String, error_code: i32, error_text: String);
fn on_ice_candidates_removed(&mut self, removed: Vec<UniquePtr<Candidate>>);
fn on_ice_connection_receiving_change(&mut self, receiving: bool);
fn on_ice_selected_candidate_pair_changed(&mut self, event: ffi::CandidatePairChangeEvent);
fn on_add_track(&mut self, receiver: UniquePtr<RtpReceiver>, streams: Vec<UniquePtr<MediaStreamInterface>>);
fn on_track(&mut self, transceiver: UniquePtr<RtpTransceiver>);
fn on_remove_track(&mut self, receiver: UniquePtr<RtpReceiver>);
fn on_interesting_usage(&mut self, usage_pattern: i32);
}
pub struct PeerConnectionObserverWrapper {
observer: Box<dyn PeerConnectionObserver>,
}
impl PeerConnectionObserverWrapper {
pub fn new(observer: Box<dyn PeerConnectionObserver>) -> Self {
Self {
observer
}
}
fn on_signaling_change(&mut self, new_state: ffi::SignalingState) {
self.observer.on_signaling_change(new_state);
}
fn on_add_stream(&mut self, stream: UniquePtr<MediaStreamInterface>) {
self.observer.on_add_stream(stream);
}
fn on_remove_stream(&mut self, stream: UniquePtr<MediaStreamInterface>) {
self.observer.on_remove_stream(stream);
}
fn on_data_channel(&mut self, data_channel: UniquePtr<DataChannel>) {
self.observer.on_data_channel(data_channel);
}
fn on_renegotiation_needed(&mut self) {
self.observer.on_renegotiation_needed();
}
fn on_negotiation_needed_event(&mut self, event: u32) {
self.observer.on_negotiation_needed_event(event);
}
fn on_ice_connection_change(&mut self, new_state: ffi::IceConnectionState) {
self.observer.on_ice_connection_change(new_state);
}
fn on_standardized_ice_connection_change(&mut self, new_state: ffi::IceConnectionState) {
self.observer.on_standardized_ice_connection_change(new_state);
}
fn on_connection_change(&mut self, new_state: ffi::PeerConnectionState) {
self.observer.on_connection_change(new_state);
}
fn on_ice_gathering_change(&mut self, new_state: ffi::IceGatheringState) {
self.observer.on_ice_gathering_change(new_state);
}
fn on_ice_candidate(&mut self, candidate: UniquePtr<IceCandidate>) {
self.observer.on_ice_candidate(candidate);
}
fn on_ice_candidate_error(&mut self, address: String, port: i32, url: String, error_code: i32, error_text: String) {
self.observer.on_ice_candidate_error(address, port, url, error_code, error_text);
}
fn on_ice_candidates_removed(&mut self, removed: Vec<ffi::CandidatePtr>) {
let mut vec = Vec::new();
for v in removed {
vec.push(v.ptr);
}
self.observer.on_ice_candidates_removed(vec);
}
fn on_ice_connection_receiving_change(&mut self, receiving: bool) {
self.observer.on_ice_connection_receiving_change(receiving);
}
fn on_ice_selected_candidate_pair_changed(&mut self, event: ffi::CandidatePairChangeEvent) {
self.observer.on_ice_selected_candidate_pair_changed(event);
}
fn on_add_track(&mut self, receiver: UniquePtr<RtpReceiver>, streams: Vec<ffi::MediaStreamPtr>) {
let mut vec = Vec::new();
for v in streams {
vec.push(v.ptr);
}
self.observer.on_add_track(receiver, vec);
}
fn on_track(&mut self, transceiver: UniquePtr<RtpTransceiver>) {
self.observer.on_track(transceiver);
}
fn on_remove_track(&mut self, receiver: UniquePtr<RtpReceiver>) {
self.observer.on_remove_track(receiver);
}
fn on_interesting_usage(&mut self, usage_pattern: i32) {
self.observer.on_interesting_usage(usage_pattern);
}
}
@@ -0,0 +1,87 @@
//
// Created by Théo Monnom on 03/08/2022.
//
#include "livekit/peer_connection_factory.h"
#include "api/video_codecs/builtin_video_decoder_factory.h"
#include "api/audio_codecs/builtin_audio_decoder_factory.h"
#include "api/audio_codecs/builtin_audio_encoder_factory.h"
#include "api/video_codecs/builtin_video_encoder_factory.h"
#include "media/engine/webrtc_media_engine.h"
#include "api/task_queue/default_task_queue_factory.h"
#include "api/rtc_event_log/rtc_event_log_factory.h"
#include "libwebrtc-sys/src/peer_connection_factory.rs.h"
namespace livekit{
PeerConnectionFactory::PeerConnectionFactory(){
rtc::LogMessage::LogToDebug(rtc::LS_INFO);
RTC_LOG(LS_INFO) << "PeerConnectionFactory::PeerConnectionFactory()";
network_thread_ = rtc::Thread::CreateWithSocketServer();
network_thread_->SetName("network_thread", &network_thread_);
network_thread_->Start();
worker_thread_ = rtc::Thread::Create();
worker_thread_->SetName("worker_thread", &worker_thread_);
worker_thread_->Start();
signaling_thread_ = rtc::Thread::Create();
signaling_thread_->SetName("signaling_thread", &signaling_thread_);
signaling_thread_->Start();
webrtc::PeerConnectionFactoryDependencies dependencies;
dependencies.network_thread = network_thread_.get();
dependencies.worker_thread = worker_thread_.get();
dependencies.signaling_thread = signaling_thread_.get();
dependencies.task_queue_factory = webrtc::CreateDefaultTaskQueueFactory();
dependencies.event_log_factory = std::make_unique<webrtc::RtcEventLogFactory>(dependencies.task_queue_factory.get());
cricket::MediaEngineDependencies media_deps;
media_deps.task_queue_factory = dependencies.task_queue_factory.get();
media_deps.video_encoder_factory = webrtc::CreateBuiltinVideoEncoderFactory();
media_deps.video_decoder_factory = webrtc::CreateBuiltinVideoDecoderFactory();
media_deps.audio_encoder_factory = webrtc::CreateBuiltinAudioEncoderFactory();
media_deps.audio_decoder_factory = webrtc::CreateBuiltinAudioDecoderFactory();
dependencies.media_engine = cricket::CreateMediaEngine(std::move(media_deps));
peer_factory_ = webrtc::CreateModularPeerConnectionFactory(std::move(dependencies));
if (peer_factory_.get() == nullptr) {
RTC_LOG_ERR(LS_ERROR) << "Failed to create PeerConnectionFactory";
return;
}
}
std::unique_ptr<PeerConnection> PeerConnectionFactory::create_peer_connection(std::unique_ptr<webrtc::PeerConnectionInterface::RTCConfiguration> config, std::unique_ptr<NativePeerConnectionObserver> observer) const {
webrtc::PeerConnectionDependencies deps{observer.get()};
auto result = peer_factory_->CreatePeerConnectionOrError(*config, std::move(deps));
if(!result.ok()){
throw std::runtime_error(result.error().message()); // TODO(theomonnom) Bridge RTCError - Mb use ProtoBuf
}
return std::make_unique<PeerConnection>(std::move(result.value()), std::move(observer));
}
std::unique_ptr<PeerConnectionFactory> create_peer_connection_factory() {
return std::make_unique<PeerConnectionFactory>();
}
std::unique_ptr<NativeRTCConfiguration> create_rtc_configuration(RTCConfiguration conf){
auto rtc = std::make_unique<webrtc::PeerConnectionInterface::RTCConfiguration>();
for (auto &item: conf.ice_servers){
webrtc::PeerConnectionInterface::IceServer ice_server;
ice_server.username = item.username.c_str();
ice_server.password = item.password.c_str();
for (auto &url: item.urls){
ice_server.urls.push_back(url.c_str());
}
rtc->servers.push_back(ice_server);
}
return rtc;
}
} // namespace lk
@@ -0,0 +1,186 @@
use std::any::Any;
use std::thread::sleep;
use std::time::Duration;
use cxx::UniquePtr;
use log::info;
use crate::candidate::ffi::Candidate;
use crate::data_channel::ffi::DataChannel;
use crate::jsep::ffi::IceCandidate;
use crate::media_stream_interface::ffi::MediaStreamInterface;
use crate::{jsep, peer_connection};
use crate::jsep::CreateSdpObserver;
use crate::peer_connection::ffi::{CandidatePairChangeEvent, IceConnectionState, IceGatheringState, PeerConnectionState, SignalingState};
use crate::peer_connection::PeerConnectionObserver;
use crate::rtp_receiver::ffi::RtpReceiver;
use crate::rtp_transceiver::ffi::RtpTransceiver;
#[cxx::bridge(namespace = "livekit")]
pub mod ffi {
#[derive(Debug, Clone)]
pub struct ICEServer {
urls: Vec<String>,
username: String,
password: String,
}
#[derive(Debug)]
pub struct RTCConfiguration {
pub ice_servers: Vec<ICEServer>,
}
unsafe extern "C++" {
include!("livekit/peer_connection_factory.h");
type PeerConnection = crate::peer_connection::ffi::PeerConnection;
type NativePeerConnectionObserver = crate::peer_connection::ffi::NativePeerConnectionObserver;
type PeerConnectionFactory;
type NativeRTCConfiguration;
fn create_peer_connection_factory() -> UniquePtr<PeerConnectionFactory>;
fn create_rtc_configuration(conf: RTCConfiguration) -> UniquePtr<NativeRTCConfiguration>;
unsafe fn create_peer_connection(self: &PeerConnectionFactory, config: UniquePtr<NativeRTCConfiguration>, observer: UniquePtr<NativePeerConnectionObserver>) -> Result<UniquePtr<PeerConnection>>;
}
}
#[cfg(test)]
mod test {
struct TestObserver {
}
impl PeerConnectionObserver for TestObserver {
fn on_signaling_change(&self, new_state: SignalingState) {
log::debug!("Signaling state changed: {:?}", new_state);
}
fn on_add_stream(&self, stream: UniquePtr<MediaStreamInterface>) {
todo!()
}
fn on_remove_stream(&self, stream: UniquePtr<MediaStreamInterface>) {
todo!()
}
fn on_data_channel(&self, data_channel: UniquePtr<DataChannel>) {
todo!()
}
fn on_renegotiation_needed(&self) {
todo!()
}
fn on_negotiation_needed_event(&self, event: u32) {
todo!()
}
fn on_ice_connection_change(&self, new_state: IceConnectionState) {
log::debug!("ICE connection state changed: {:?}", new_state);
}
fn on_standardized_ice_connection_change(&self, new_state: IceConnectionState) {
todo!()
}
fn on_connection_change(&self, new_state: PeerConnectionState) {
log::debug!("PeerConnection state changed: {:?}", new_state);
}
fn on_ice_gathering_change(&self, new_state: IceGatheringState) {
todo!()
}
fn on_ice_candidate(&self, candidate: UniquePtr<IceCandidate>) {
todo!()
}
fn on_ice_candidate_error(&self, address: String, port: i32, url: String, error_code: i32, error_text: String) {
todo!()
}
fn on_ice_candidates_removed(&self, removed: Vec<UniquePtr<Candidate>>) {
todo!()
}
fn on_ice_connection_receiving_change(&self, receiving: bool) {
todo!()
}
fn on_ice_selected_candidate_pair_changed(&self, event: CandidatePairChangeEvent) {
todo!()
}
fn on_add_track(&self, receiver: UniquePtr<RtpReceiver>, streams: Vec<UniquePtr<MediaStreamInterface>>) {
todo!()
}
fn on_track(&self, transceiver: UniquePtr<RtpTransceiver>) {
todo!()
}
fn on_remove_track(&self, receiver: UniquePtr<RtpReceiver>) {
todo!()
}
fn on_interesting_usage(&self, usage_pattern: i32) {
todo!()
}
}
struct SessionObserver {
}
impl CreateSdpObserver for SessionObserver {
fn on_success(&self, session_description: UniquePtr<crate::jsep::ffi::SessionDescription>) {
info!("on_success");
}
fn on_failure(&self, error: UniquePtr<crate::rtc_error::ffi::RTCError>) {
info!("on_failure");
}
}
#[test]
fn create_pc_test() {
env_logger::init();
let factory = ffi::create_peer_connection_factory(); // Default factory config is defined on the c++ side atm
unsafe {
let mut pc = factory.create_peer_connection(ffi::create_rtc_configuration(ffi::RTCConfiguration {
ice_servers: vec![ffi::ICEServer {
urls: vec!["stun:stun.l.google.com:19302".to_string()],
username: "".to_string(),
password: "".to_string(),
}],
}), peer_connection::ffi::create_native_peer_connection_observer(Box::new(peer_connection::PeerConnectionObserverWrapper::new(Box::new(TestObserver{}))))).unwrap();
let options = peer_connection::ffi::RTCOfferAnswerOptions::default();
let sdp_observer = jsep::ffi::create_native_create_sdp_observer(Box::new(jsep::CreateSdpObserverWrapper::new(Box::new(SessionObserver{}))));
pc.pin_mut().create_offer(sdp_observer, options);
sleep(Duration::from_secs(2));
pc.pin_mut().close();
}
}
}
@@ -0,0 +1,11 @@
//
// Created by theom on 04/09/2022.
//
#include "livekit/rtc_error.h"
namespace livekit {
RTCError::RTCError(webrtc::RTCError error) : rtc_error_(std::move(error)) {
}
} // livekit
@@ -0,0 +1,13 @@
// TODO(theomonnom) Don't use RTCError as Opaque. I should use a Struct and serialize/deserialize when needed for Result<>
#[cxx::bridge(namespace = "livekit")]
pub mod ffi {
unsafe extern "C++" {
include!("livekit/rtc_error.h");
type RTCError;
fn _unique_rtc_error() -> UniquePtr<RTCError>;
}
}
@@ -0,0 +1,11 @@
//
// Created by Théo Monnom on 01/09/2022.
//
#include "livekit/rtp_receiver.h"
namespace livekit {
RtpReceiver::RtpReceiver(rtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver) : receiver_(std::move(receiver)) {
}
} // livekit
@@ -0,0 +1,12 @@
use cxx::UniquePtr;
#[cxx::bridge(namespace = "livekit")]
pub mod ffi {
unsafe extern "C++" {
include!("livekit/rtp_receiver.h");
type RtpReceiver;
fn _unique_rtp_receiver() -> UniquePtr<RtpReceiver>; // Ignore
}
}
@@ -0,0 +1,11 @@
//
// Created by Théo Monnom on 02/09/2022.
//
#include "livekit/rtp_transceiver.h"
namespace livekit {
RtpTransceiver::RtpTransceiver(rtc::scoped_refptr<webrtc::RtpTransceiverInterface> transceiver) : transceiver_(std::move(transceiver)) {
}
} // livekit
@@ -0,0 +1,12 @@
use cxx::UniquePtr;
#[cxx::bridge(namespace = "livekit")]
pub mod ffi {
unsafe extern "C++" {
include!("livekit/rtp_transceiver.h");
type RtpTransceiver;
fn _unique_rtp_transceiver() -> UniquePtr<RtpTransceiver>; // Ignore
}
}
@@ -0,0 +1,6 @@
pub struct DataChannel {
}
@@ -0,0 +1,4 @@
pub struct IceCandidate {
}
+9
View File
@@ -0,0 +1,9 @@
pub mod peer_connection_factory;
pub mod peer_connection;
pub mod rtc_error;
pub mod data_channel;
pub mod media_stream;
pub mod rtp_receiver;
pub mod rtp_transceiver;
pub mod ice_candidate;
pub mod session_description;
@@ -0,0 +1,4 @@
pub struct MediaStream {
}
@@ -0,0 +1,336 @@
use std::sync::{Arc, Mutex};
use cxx::UniquePtr;
use tokio::sync::mpsc;
use libwebrtc_sys::peer_connection as sys_pc;
use libwebrtc_sys::jsep as sys_jsep;
use crate::data_channel::DataChannel;
use crate::media_stream::MediaStream;
use crate::ice_candidate::IceCandidate;
use crate::rtp_receiver::RtpReceiver;
use crate::rtp_transceiver::RtpTransceiver;
use crate::session_description::SessionDescription;
use crate::rtc_error::RTCError;
pub use libwebrtc_sys::peer_connection::ffi::PeerConnectionState;
pub use libwebrtc_sys::peer_connection::ffi::SignalingState;
pub use libwebrtc_sys::peer_connection::ffi::IceConnectionState;
pub use libwebrtc_sys::peer_connection::ffi::IceGatheringState;
pub use libwebrtc_sys::peer_connection::ffi::RTCOfferAnswerOptions;
pub struct PeerConnection {
cxx_handle: UniquePtr<sys_pc::ffi::PeerConnection>,
observer: InternalObserver
}
impl PeerConnection {
pub fn new(cxx_handle: UniquePtr<sys_pc::ffi::PeerConnection>) -> Self {
Self {
cxx_handle,
observer: InternalObserver {
on_signaling_change_handler: Arc::new(Default::default()),
on_add_stream_handler: Arc::new(Default::default()),
on_remove_stream_handler: Arc::new(Default::default()),
on_data_channel_handler: Arc::new(Default::default()),
on_renegotiation_needed_handler: Arc::new(Default::default()),
on_negotiation_needed_event_handler: Arc::new(Default::default()),
on_ice_connection_change_handler: Arc::new(Default::default()),
on_standardized_ice_connection_change_handler: Arc::new(Default::default()),
on_connection_change_handler: Arc::new(Default::default()),
on_ice_gathering_change_handler: Arc::new(Default::default()),
on_ice_candidate_handler: Arc::new(Default::default()),
on_ice_candidate_error_handler: Arc::new(Default::default()),
on_ice_candidates_removed_handler: Arc::new(Default::default()),
on_ice_connection_receiving_change_handler: Arc::new(Default::default()),
on_ice_selected_candidate_pair_changed_handler: Arc::new(Default::default()),
on_add_track_handler: Arc::new(Default::default()),
on_track_handler: Arc::new(Default::default()),
on_remove_track_handler: Arc::new(Default::default()),
on_interesting_usage_handler: Arc::new(Default::default())
}
}
}
pub async fn create_offer(&mut self) -> Result<SessionDescription, RTCError> {
let (tx, mut rx) = mpsc::channel(1);
let wrapper = sys_jsep::CreateSdpObserverWrapper::new(Box::new(InternalCreateSdpObserver { tx }));
let native_wrapper = sys_jsep::ffi::create_native_create_sdp_observer(Box::new(wrapper));
self.cxx_handle.pin_mut().create_offer(native_wrapper, RTCOfferAnswerOptions::default());
rx.recv().await.unwrap()
}
pub async fn create_answer(&mut self) -> Result<SessionDescription, RTCError> {
}
pub fn on_signaling_change(&mut self, handler: OnSignalingChangeHandler) {
*self.observer.on_signaling_change_handler.lock().unwrap() = Some(handler);
}
pub fn on_add_stream(&mut self, handler: OnAddStreamHandler) {
*self.observer.on_add_stream_handler.lock().unwrap() = Some(handler);
}
pub fn on_remove_stream(&mut self, handler: OnRemoveStreamHandler) {
*self.observer.on_remove_stream_handler.lock().unwrap() = Some(handler);
}
pub fn on_data_channel(&mut self, handler: OnDataChannelHandler) {
*self.observer.on_data_channel_handler.lock().unwrap() = Some(handler);
}
pub fn on_renegotiation_needed(&mut self, handler: OnRenegotiationNeededHandler) {
*self.observer.on_renegotiation_needed_handler.lock().unwrap() = Some(handler);
}
pub fn on_ice_connection_change(&mut self, handler: OnIceConnectionChangeHandler) {
*self.observer.on_ice_connection_change_handler.lock().unwrap() = Some(handler);
}
pub fn on_standardized_ice_connection_change(&mut self, handler: OnStandardizedIceConnectionChangeHandler) {
*self.observer.on_standardized_ice_connection_change_handler.lock().unwrap() = Some(handler);
}
pub fn on_connection_change(&mut self, handler: OnConnectionChangeHandler) {
*self.observer.on_connection_change_handler.lock().unwrap() = Some(handler);
}
pub fn on_ice_gathering_change(&mut self, handler: OnIceGatheringChangeHandler) {
*self.observer.on_ice_gathering_change_handler.lock().unwrap() = Some(handler);
}
pub fn on_ice_candidate(&mut self, handler: OnIceCandidateHandler) {
*self.observer.on_ice_candidate_handler.lock().unwrap() = Some(handler);
}
pub fn on_ice_candidate_error(&mut self, handler: OnIceCandidateErrorHandler) {
*self.observer.on_ice_candidate_error_handler.lock().unwrap() = Some(handler);
}
pub fn on_ice_candidates_removed(&mut self, handler: OnIceCandidatesRemovedHandler) {
*self.observer.on_ice_candidates_removed_handler.lock().unwrap() = Some(handler);
}
pub fn on_ice_connection_receiving_change(&mut self, handler: OnIceConnectionReceivingChangeHandler) {
*self.observer.on_ice_connection_receiving_change_handler.lock().unwrap() = Some(handler);
}
pub fn on_ice_selected_candidate_pair_changed(&mut self, handler: OnIceSelectedCandidatePairChangedHandler) {
*self.observer.on_ice_selected_candidate_pair_changed_handler.lock().unwrap() = Some(handler);
}
pub fn on_add_track(&mut self, handler: OnAddTrackHandler) {
*self.observer.on_add_track_handler.lock().unwrap() = Some(handler);
}
pub fn on_track(&mut self, handler: OnTrackHandler) {
*self.observer.on_track_handler.lock().unwrap() = Some(handler);
}
pub fn on_remove_track(&mut self, handler: OnRemoveTrackHandler) {
*self.observer.on_remove_track_handler.lock().unwrap() = Some(handler);
}
pub fn on_interesting_usage(&mut self, handler: OnInterestingUsageHandler) {
*self.observer.on_interesting_usage_handler.lock().unwrap() = Some(handler);
}
}
// CreateSdpObserver
struct InternalCreateSdpObserver {
tx: mpsc::Sender<Result<SessionDescription, RTCError>>
}
impl sys_jsep::CreateSdpObserver for InternalCreateSdpObserver {
fn on_success(&self, session_description: UniquePtr<libwebrtc_sys::jsep::ffi::SessionDescription>) {
self.tx.blocking_send(Ok(SessionDescription{})).unwrap(); // TODO
}
fn on_failure(&self, error: UniquePtr<libwebrtc_sys::rtc_error::ffi::RTCError>) {
self.tx.blocking_send(Err(RTCError{})).unwrap(); // TODO
}
}
// PeerConnectionObserver
// TODO(theomonnom) Should we return futures?
pub type OnSignalingChangeHandler = Box<dyn FnMut(SignalingState) + Send + Sync>;
pub type OnAddStreamHandler = Box<dyn FnMut(MediaStream) + Send + Sync>;
pub type OnRemoveStreamHandler = Box<dyn FnMut(MediaStream) + Send + Sync>;
pub type OnDataChannelHandler = Box<dyn FnMut(DataChannel) + Send + Sync>;
pub type OnRenegotiationNeededHandler = Box<dyn FnMut() + Send + Sync>;
pub type OnNegotiationNeededEventHandler = Box<dyn FnMut(u32) + Send + Sync>;
pub type OnIceConnectionChangeHandler = Box<dyn FnMut(IceConnectionState) + Send + Sync>;
pub type OnStandardizedIceConnectionChangeHandler = Box<dyn FnMut(IceConnectionState) + Send + Sync>;
pub type OnConnectionChangeHandler = Box<dyn FnMut(PeerConnectionState) + Send + Sync>;
pub type OnIceGatheringChangeHandler = Box<dyn FnMut(IceGatheringState) + Send + Sync>;
pub type OnIceCandidateHandler = Box<dyn FnMut(IceCandidate) + Send + Sync>;
pub type OnIceCandidateErrorHandler = Box<dyn FnMut(String, i32, String, i32, String) + Send + Sync>;
pub type OnIceCandidatesRemovedHandler = Box<dyn FnMut(Vec<IceCandidate>) + Send + Sync>;
pub type OnIceConnectionReceivingChangeHandler = Box<dyn FnMut(bool) + Send + Sync>;
pub type OnIceSelectedCandidatePairChangedHandler = Box<dyn FnMut(libwebrtc_sys::peer_connection::ffi::CandidatePairChangeEvent) + Send + Sync>;
pub type OnAddTrackHandler = Box<dyn FnMut(RtpReceiver, Vec<MediaStream>) + Send + Sync>;
pub type OnTrackHandler = Box<dyn FnMut(RtpTransceiver) + Send + Sync>;
pub type OnRemoveTrackHandler = Box<dyn FnMut(RtpReceiver) + Send + Sync>;
pub type OnInterestingUsageHandler = Box<dyn FnMut(i32) + Send + Sync>;
struct InternalObserver {
on_signaling_change_handler: Arc<Mutex<Option<OnSignalingChangeHandler>>>,
on_add_stream_handler: Arc<Mutex<Option<OnAddStreamHandler>>>,
on_remove_stream_handler: Arc<Mutex<Option<OnRemoveStreamHandler>>>,
on_data_channel_handler: Arc<Mutex<Option<OnDataChannelHandler>>>,
on_renegotiation_needed_handler: Arc<Mutex<Option<OnRenegotiationNeededHandler>>>,
on_negotiation_needed_event_handler: Arc<Mutex<Option<OnNegotiationNeededEventHandler>>>,
on_ice_connection_change_handler: Arc<Mutex<Option<OnIceConnectionChangeHandler>>>,
on_standardized_ice_connection_change_handler: Arc<Mutex<Option<OnStandardizedIceConnectionChangeHandler>>>,
on_connection_change_handler: Arc<Mutex<Option<OnConnectionChangeHandler>>>,
on_ice_gathering_change_handler: Arc<Mutex<Option<OnIceGatheringChangeHandler>>>,
on_ice_candidate_handler: Arc<Mutex<Option<OnIceCandidateHandler>>>,
on_ice_candidate_error_handler: Arc<Mutex<Option<OnIceCandidateErrorHandler>>>,
on_ice_candidates_removed_handler: Arc<Mutex<Option<OnIceCandidatesRemovedHandler>>>,
on_ice_connection_receiving_change_handler: Arc<Mutex<Option<OnIceConnectionReceivingChangeHandler>>>,
on_ice_selected_candidate_pair_changed_handler: Arc<Mutex<Option<OnIceSelectedCandidatePairChangedHandler>>>,
on_add_track_handler: Arc<Mutex<Option<OnAddTrackHandler>>>,
on_track_handler: Arc<Mutex<Option<OnTrackHandler>>>,
on_remove_track_handler: Arc<Mutex<Option<OnRemoveTrackHandler>>>,
on_interesting_usage_handler: Arc<Mutex<Option<OnInterestingUsageHandler>>>
}
// Observers are being called on the Signaling Thread
impl sys_pc::PeerConnectionObserver for InternalObserver {
fn on_signaling_change(&mut self, new_state: SignalingState) {
let mut handler = self.on_signaling_change_handler.lock().unwrap();
if let Some(f) = handler.as_mut() {
f(new_state);
}
}
fn on_add_stream(&mut self, stream: UniquePtr<libwebrtc_sys::media_stream_interface::ffi::MediaStreamInterface>) {
let mut handler = self.on_add_stream_handler.lock().unwrap();
if let Some(f) = handler.as_mut() {
// TODO(theomonnom)
}
}
fn on_remove_stream(&mut self, stream: UniquePtr<libwebrtc_sys::media_stream_interface::ffi::MediaStreamInterface>) {
let mut handler = self.on_remove_stream_handler.lock().unwrap();
if let Some(f) = handler.as_mut() {
// TODO(theomonnom)
}
}
fn on_data_channel(&mut self, data_channel: UniquePtr<libwebrtc_sys::data_channel::ffi::DataChannel>) {
let mut handler = self.on_data_channel_handler.lock().unwrap();
if let Some(f) = handler.as_mut() {
// TODO(theomonnom)
}
}
fn on_renegotiation_needed(&mut self) {
let mut handler = self.on_renegotiation_needed_handler.lock().unwrap();
if let Some(f) = handler.as_mut() {
f();
}
}
fn on_negotiation_needed_event(&mut self, event: u32) {
let mut handler = self.on_negotiation_needed_event_handler.lock().unwrap();
if let Some(f) = handler.as_mut() {
f(event);
}
}
fn on_ice_connection_change(&mut self, new_state: IceConnectionState) {
let mut handler = self.on_ice_connection_change_handler.lock().unwrap();
if let Some(f) = handler.as_mut() {
f(new_state);
}
}
fn on_standardized_ice_connection_change(&mut self, new_state: IceConnectionState) {
let mut handler = self.on_standardized_ice_connection_change_handler.lock().unwrap();
if let Some(f) = handler.as_mut() {
f(new_state);
}
}
fn on_connection_change(&mut self, new_state: PeerConnectionState) {
let mut handler = self.on_connection_change_handler.lock().unwrap();
if let Some(f) = handler.as_mut() {
f(new_state);
}
}
fn on_ice_gathering_change(&mut self, new_state: IceGatheringState) {
let mut handler = self.on_ice_gathering_change_handler.lock().unwrap();
if let Some(f) = handler.as_mut() {
f(new_state);
}
}
fn on_ice_candidate(&mut self, candidate: UniquePtr<libwebrtc_sys::jsep::ffi::IceCandidate>) {
let mut handler = self.on_ice_candidate_handler.lock().unwrap();
if let Some(f) = handler.as_mut() {
// TODO(theomonnom)
}
}
fn on_ice_candidate_error(&mut self, address: String, port: i32, url: String, error_code: i32, error_text: String) {
let mut handler = self.on_ice_candidate_error_handler.lock().unwrap();
if let Some(f) = handler.as_mut() {
f(address, port, url, error_code, error_text);
}
}
fn on_ice_candidates_removed(&mut self, removed: Vec<UniquePtr<libwebrtc_sys::candidate::ffi::Candidate>>) {
let mut handler = self.on_ice_candidates_removed_handler.lock().unwrap();
if let Some(f) = handler.as_mut() {
// TODO(theomonnom)
}
}
fn on_ice_connection_receiving_change(&mut self, receiving: bool) {
let mut handler = self.on_ice_connection_receiving_change_handler.lock().unwrap();
if let Some(f) = handler.as_mut() {
f(receiving);
}
}
fn on_ice_selected_candidate_pair_changed(&mut self, event: libwebrtc_sys::peer_connection::ffi::CandidatePairChangeEvent) {
let mut handler = self.on_ice_selected_candidate_pair_changed_handler.lock().unwrap();
if let Some(f) = handler.as_mut() {
f(event);
}
}
fn on_add_track(&mut self, receiver: UniquePtr<libwebrtc_sys::rtp_receiver::ffi::RtpReceiver>, streams: Vec<UniquePtr<libwebrtc_sys::media_stream_interface::ffi::MediaStreamInterface>>) {
let mut handler = self.on_add_track_handler.lock().unwrap();
if let Some(f) = handler.as_mut() {
// TODO(theomonnom)
}
}
fn on_track(&mut self, transceiver: UniquePtr<libwebrtc_sys::rtp_transceiver::ffi::RtpTransceiver>) {
let mut handler = self.on_track_handler.lock().unwrap();
if let Some(f) = handler.as_mut() {
// TODO(theomonnom)
}
}
fn on_remove_track(&mut self, receiver: UniquePtr<libwebrtc_sys::rtp_receiver::ffi::RtpReceiver>) {
let mut handler = self.on_remove_track_handler.lock().unwrap();
if let Some(f) = handler.as_mut() {
// TODO(theomonnom)
}
}
fn on_interesting_usage(&mut self, usage_pattern: i32) {
let mut handler = self.on_interesting_usage_handler.lock().unwrap();
if let Some(f) = handler.as_mut() {
f(usage_pattern);
}
}
}
@@ -0,0 +1,54 @@
use cxx::UniquePtr;
use libwebrtc_sys::peer_connection_factory as sys_factory;
use libwebrtc_sys::peer_connection as sys_pc;
use crate::peer_connection::PeerConnection;
use crate::rtc_error::RTCError;
pub use sys_factory::ffi::{RTCConfiguration, ICEServer};
pub struct PeerConnectionFactory {
cxx_handle: UniquePtr<sys_factory::ffi::PeerConnectionFactory>
}
impl PeerConnectionFactory {
pub fn new() -> Self {
Self {
cxx_handle: sys_factory::ffi::create_peer_connection_factory()
}
}
pub fn create_peer_connection(&self, config: RTCConfiguration, observer: Box<dyn sys_pc::PeerConnectionObserver>) -> Result<PeerConnection, RTCError> {
let native_config = sys_factory::ffi::create_rtc_configuration(config);
let native_observer = sys_pc::ffi::create_native_peer_connection_observer(Box::new(sys_pc::PeerConnectionObserverWrapper::new(observer)));
let pc_result : Result<UniquePtr<sys_pc::ffi::PeerConnection>, cxx::Exception> = unsafe {
self.cxx_handle.create_peer_connection(native_config, native_observer)
};
match pc_result {
Ok(cxx_handle) => {
let pc = PeerConnection::new(cxx_handle);
Ok(pc)
}
Err(e) => {
Err(RTCError{}) // TODO
}
}
}
}
#[cfg(test)]
mod tests {
use crate::peer_connection_factory::PeerConnectionFactory;
use crate::peer_connection_factory::{RTCConfiguration, ICEServer};
#[test]
fn create_pc(){
let factory = PeerConnectionFactory::new();
let pc = factory.create_peer_connection(RTCConfiguration{
ice_servers: vec!()
}, Box::new(()));
}
}
+5
View File
@@ -0,0 +1,5 @@
#[derive(Debug)]
pub struct RTCError {
}
@@ -0,0 +1,5 @@
pub struct RtpReceiver {
}
@@ -0,0 +1,5 @@
pub struct RtpTransceiver {
}
@@ -0,0 +1,5 @@
#[derive(Debug)]
pub struct SessionDescription {
}