basic MacOS version

This commit is contained in:
Théo Monnom
2022-08-03 16:19:02 +02:00
parent 5c8841de1f
commit 5a84aaa3c9
31 changed files with 356 additions and 39516 deletions
-8
View File
@@ -1,8 +0,0 @@
//
// Created by Théo Monnom on 30/05/2022.
//
#include "createsession_observer.h"
namespace livekit {
} // livekit
-26
View File
@@ -1,26 +0,0 @@
//
// Created by Théo Monnom on 30/05/2022.
//
#ifndef LIVEKIT_NATIVE_CREATESESSION_OBSERVER_H
#define LIVEKIT_NATIVE_CREATESESSION_OBSERVER_H
#include <api/peer_connection_interface.h>
namespace livekit {
class CreateSessionObserver : public webrtc::CreateSessionDescriptionObserver {
public:
void OnSuccess(webrtc::SessionDescriptionInterface *desc) override {
};
void OnFailure(webrtc::RTCError error) override {
};
};
} // livekit
#endif //LIVEKIT_NATIVE_CREATESESSION_OBSERVER_H
+20
View File
@@ -0,0 +1,20 @@
use std::thread::sleep;
use std::time;
#[cxx::bridge(namespace = "lk")]
mod ffi {
unsafe extern "C++" {
include!("peer_connection_factory.h");
type PeerConnectionFactory;
fn CreatePeerConnectionFactory() -> UniquePtr<PeerConnectionFactory>;
}
}
fn main() {
println!("Hello, world!");
let factory = ffi::CreatePeerConnectionFactory();
}
+39
View File
@@ -0,0 +1,39 @@
//
// Created by Théo Monnom on 03/08/2022.
//
#include "peer_connection_factory.h"
#include <iostream>
namespace lk{
PeerConnectionFactory::PeerConnectionFactory(){
rtc::LogMessage::LogToDebug(rtc::LS_INFO);
RTC_LOG(LS_INFO) << "PeerConnectionFactory::PeerConnectionFactory()";
network_thread_ = rtc::Thread::CreateWithSocketServer();
network_thread_->Start();
worker_thread_ = rtc::Thread::Create();
worker_thread_->Start();
signaling_thread_ = rtc::Thread::Create();
signaling_thread_->Start();
webrtc::PeerConnectionFactoryDependencies dependencies;
dependencies.network_thread = network_thread_.get();
dependencies.worker_thread = worker_thread_.get();
dependencies.signaling_thread = signaling_thread_.get();
peer_factory_ = webrtc::CreateModularPeerConnectionFactory(std::move(dependencies));
if (peer_factory_.get() == nullptr) {
RTC_LOG_ERR(LS_ERROR) << "Failed to create PeerConnectionFactory";
return;
}
// TODO(theomonnom) Close resources
}
std::unique_ptr<PeerConnectionFactory> CreatePeerConnectionFactory() {
return std::make_unique<PeerConnectionFactory>();
}
} // namespace lk
-10
View File
@@ -1,10 +0,0 @@
//
// Created by Théo Monnom on 21/05/2022.
//
#include "peer_observer.h"
namespace livekit {
} // livekit
-51
View File
@@ -1,51 +0,0 @@
//
// Created by Théo Monnom on 21/05/2022.
//
#ifndef LIVEKIT_NATIVE_PEER_OBSERVER_H
#define LIVEKIT_NATIVE_PEER_OBSERVER_H
#include <api/create_peerconnection_factory.h>
#include <spdlog/spdlog.h>
namespace livekit {
class PeerObserver : public webrtc::PeerConnectionObserver {
public:
void OnSignalingChange(webrtc::PeerConnectionInterface::SignalingState new_state) override {
spdlog::info("Received OnSignalingChange");
};
void OnAddStream(rtc::scoped_refptr<webrtc::MediaStreamInterface> stream) override {
spdlog::info("Received OnAddStream");
};
void OnRemoveStream(rtc::scoped_refptr<webrtc::MediaStreamInterface> stream) override {
spdlog::info("Received OnRemoveStream");
};
void OnDataChannel(rtc::scoped_refptr<webrtc::DataChannelInterface> data_channel) override {
spdlog::info("Received OnDataChannel");
};
void OnRenegotiationNeeded() override {
spdlog::info("Received OnRenegotiationNeeded");
};
void OnIceConnectionChange(webrtc::PeerConnectionInterface::IceConnectionState new_state) override {
spdlog::info("Received OnIceConnectionChange");
};
void OnIceGatheringChange(webrtc::PeerConnectionInterface::IceGatheringState new_state) override {
spdlog::info("Received OnIceGatheringChange");
};
void OnIceCandidate(const webrtc::IceCandidateInterface *candidate) override {
spdlog::info("Received OnIceCandidate");
};
};
} // livekit
#endif //LIVEKIT_NATIVE_PEER_OBSERVER_H
-26
View File
@@ -1,26 +0,0 @@
//
// Created by Théo Monnom on 30/05/2022.
//
#include "peer_transport.h"
#include "rtc_engine.h"
namespace livekit {
PeerTransport::PeerTransport(const RTCEngine &rtc_engine) {
observer = std::make_unique<PeerObserver>();
webrtc::PeerConnectionDependencies peer_configuration{observer.get()};
webrtc::RTCErrorOr<rtc::scoped_refptr<webrtc::PeerConnectionInterface>> opt_peer = rtc_engine.peer_factory_->CreatePeerConnectionOrError(
rtc_engine.configuration_, std::move(peer_configuration));
if (!opt_peer.ok()) {
throw std::runtime_error{"Failed to create a peer connection"};
}
peer_connection = opt_peer.value();
}
void PeerTransport::Negotiate() {
}
} // livekit
-27
View File
@@ -1,27 +0,0 @@
//
// Created by Théo Monnom on 30/05/2022.
//
#ifndef LIVEKIT_NATIVE_PEER_TRANSPORT_H
#define LIVEKIT_NATIVE_PEER_TRANSPORT_H
#include <api/peer_connection_interface.h>
#include "peer_observer.h"
namespace livekit {
class RTCEngine;
class PeerTransport {
public:
explicit PeerTransport(const RTCEngine &rtc_engine);
void Negotiate();
private:
rtc::scoped_refptr<webrtc::PeerConnectionInterface> peer_connection;
std::unique_ptr<PeerObserver> observer;
};
} // livekit
#endif //LIVEKIT_NATIVE_PEER_TRANSPORT_H
-1
View File
@@ -1 +0,0 @@
* linguist-generated
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
-5
View File
@@ -1,5 +0,0 @@
//
// Created by Théo Monnom on 07/05/2022.
//
#include "room.h"
-17
View File
@@ -1,17 +0,0 @@
//
// Created by Théo Monnom on 07/05/2022.
//
#ifndef LIVEKIT_NATIVE_ROOM_H
#define LIVEKIT_NATIVE_ROOM_H
#include <string>
#include "signal_client.h"
namespace livekit{
} // livekit
#endif //LIVEKIT_NATIVE_ROOM_H
-71
View File
@@ -1,71 +0,0 @@
//
// Created by Théo Monnom on 04/05/2022.
//
#include "rtc_engine.h"
#include <rtc_base/ssl_adapter.h>
#include <spdlog/spdlog.h>
#include "peer_transport.h"
namespace livekit{
RTCEngine::RTCEngine() {
}
void RTCEngine::Join(const std::string &url, const std::string &token){
client_.Connect(url, token);
}
void RTCEngine::Update(){
client_.update();
auto res = client_.poll();
if(res.has_join())
OnJoin(res.join());
}
void RTCEngine::OnJoin(const JoinResponse &res){
spdlog::info("OnJoin");
rtc::InitializeSSL();
for(auto& is : res.ice_servers()){
webrtc::PeerConnectionInterface::IceServer ice_server;
for(auto& url : is.urls())
ice_server.urls.push_back(url);
ice_server.username = is.username();
ice_server.password = is.credential();
configuration_.servers.push_back(ice_server);
}
network_thread_ = rtc::Thread::CreateWithSocketServer();
network_thread_->Start();
worker_thread_ = rtc::Thread::Create();
worker_thread_->Start();
signaling_thread_ = rtc::Thread::Create();
signaling_thread_->Start();
webrtc::PeerConnectionFactoryDependencies dependencies;
dependencies.network_thread = network_thread_.get();
dependencies.worker_thread = worker_thread_.get();
dependencies.signaling_thread = signaling_thread_.get();
peer_factory_ = webrtc::CreateModularPeerConnectionFactory(std::move(dependencies));
if (peer_factory_.get() == nullptr) {
// TODO Make error callback
spdlog::error("Error on CreateModularPeerConnectionFactory");
return;
}
subscriber_ = std::make_unique<PeerTransport>(*this);
publisher_ = std::make_unique<PeerTransport>(*this);
}
void RTCEngine::Configure() {
}
} // livekit
-43
View File
@@ -1,43 +0,0 @@
//
// Created by Théo Monnom on 04/05/2022.
//
#ifndef LIVEKIT_NATIVE_RTC_ENGINE_H
#define LIVEKIT_NATIVE_RTC_ENGINE_H
#include "signal_client.h"
#include "peer_observer.h"
#include "peer_transport.h"
#include <api/peer_connection_interface.h>
namespace livekit{
class RTCEngine {
public:
RTCEngine();
void Join(const std::string &url, const std::string &token);
void Update();
private:
void Configure();
void OnJoin(const JoinResponse &res);
private:
friend class PeerTransport;
SignalClient client_;
rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> peer_factory_;
webrtc::PeerConnectionInterface::RTCConfiguration configuration_;
std::unique_ptr<rtc::Thread> network_thread_;
std::unique_ptr<rtc::Thread> worker_thread_;
std::unique_ptr<rtc::Thread> signaling_thread_;
std::unique_ptr<PeerTransport> publisher_;
std::unique_ptr<PeerTransport> subscriber_;
};
} // livekit
#endif //LIVEKIT_NATIVE_RTC_ENGINE_H
-141
View File
@@ -1,141 +0,0 @@
//
// Created by Théo Monnom on 27/04/2022.
//
#include "signal_client.h"
#include <thread>
#include <spdlog/spdlog.h>
namespace livekit {
SignalClient::SignalClient() : connected_(false), writing_(false), reading_(false) {
}
SignalClient::~SignalClient() {
Disconnect();
}
void SignalClient::Connect(const std::string &url, const std::string &token) {
if (connected_)
throw std::runtime_error{"already connected"};
url_ = ParseURL(url);
token_ = token;
start(); // We don't need a thread, everything is async ( + easier to maintain )
}
void SignalClient::update() {
beast::error_code ec;
io_context_.poll(ec);
if (ec)
throw std::runtime_error{"SignalClient::Update - " + ec.message()};
if (connected_) {
if (!websocket_.is_open())
throw std::runtime_error{"Websocket isn't open"}; // TODO Start reconnect
if (!reading_) {
websocket_.async_read(read_buffer_, beast::bind_front_handler(&SignalClient::OnRead, this));
reading_ = true;
}
// Write pending messages
if (!writing_ && !write_queue_.empty()) {
auto req = write_queue_.front();
unsigned long len = req.ByteSizeLong();
uint8_t data[len];
req.SerializeToArray(data, len);
websocket_.async_write(net::buffer(&data, len),
beast::bind_front_handler(&SignalClient::OnWrite, this));
write_queue_.pop();
writing_ = true;
}
}
}
SignalResponse SignalClient::poll(){
if(read_queue_.empty())
return SignalResponse{};
auto r = read_queue_.front();
read_queue_.pop();
return r;
}
void SignalClient::start() {
resolver_.async_resolve(url_.host, url_.port, beast::bind_front_handler(&SignalClient::OnResolve, this));
}
void SignalClient::Disconnect() {
if (!connected_)
return;
connected_ = false;
work_guard_.reset();
//m_IOContext.stop();
websocket_.close(websocket::close_code::normal); // TODO Close should be async
}
void SignalClient::Send(SignalRequest req) {
write_queue_.emplace(req);
}
void SignalClient::OnResolve(beast::error_code ec, tcp::resolver::results_type results) {
if (ec)
throw std::runtime_error{"SignalClient::OnResolve - " + ec.message()};
auto &layer = beast::get_lowest_layer(websocket_);
layer.expires_after(std::chrono::seconds(15));
layer.async_connect(results, beast::bind_front_handler(&SignalClient::OnConnect, this));
}
void SignalClient::OnConnect(beast::error_code ec, tcp::resolver::results_type::endpoint_type ep) {
if (ec)
throw std::runtime_error{"SignalClient::OnConnect - " + ec.message()};
beast::get_lowest_layer(websocket_).expires_never();
websocket_.set_option(websocket::stream_base::timeout::suggested(beast::role_type::client));
websocket_.async_handshake(url_.host, "/rtc?access_token=" + token_ + "&protocol=7",
beast::bind_front_handler(&SignalClient::OnHandshake, this));
}
void SignalClient::OnHandshake(beast::error_code ec) {
if (ec)
throw std::runtime_error{
"SignalClient::OnHandshake - " + ec.message()}; // TODO Callback for handling errors
connected_ = true;
spdlog::info("Connected to Websocket");
}
void SignalClient::OnRead(beast::error_code ec, std::size_t bytesTransferred) {
reading_ = false;
if (ec)
throw std::runtime_error{"SignalClient::OnRead - " + ec.message()};
SignalResponse res{};
if (res.ParseFromArray(read_buffer_.cdata().data(), bytesTransferred)) {
spdlog::info("Received SignalResponse {}", bytesTransferred);
read_queue_.emplace(res);
} else {
spdlog::error("Failed to decode signal message");
}
read_buffer_.clear();
}
void SignalClient::OnWrite(beast::error_code ec, std::size_t bytesTransferred) {
writing_ = false;
if (ec)
throw std::runtime_error{"SignalClient::OnWrite - " + ec.message()};
}
} // livekit
-65
View File
@@ -1,65 +0,0 @@
//
// Created by Théo Monnom on 27/04/2022.
//
#ifndef LIVEKIT_NATIVE_SIGNAL_CLIENT_H
#define LIVEKIT_NATIVE_SIGNAL_CLIENT_H
#include <boost/beast/core.hpp>
#include <boost/beast/websocket.hpp>
#include <queue>
#include "proto/livekit_rtc.pb.h"
#include "utils.h"
namespace beast = boost::beast; // from <boost/beast.hpp>
namespace http = beast::http; // from <boost/beast/http.hpp>
namespace websocket = beast::websocket; // from <boost/beast/websocket.hpp>
namespace net = boost::asio; // from <boost/asio.hpp>
using tcp = boost::asio::ip::tcp; // from <boost/asio/ip/tcp.hpp>
// If we keep the code singled threaded here, it'll be easily used in wasm ( Need ws bindings ), tho not sure
namespace livekit {
class SignalClient {
public:
SignalClient();
~SignalClient();
void Connect(const std::string &url, const std::string &token);
void Disconnect();
void update();
void Send(SignalRequest req);
SignalResponse poll();
private:
void start();
// beast handlers
void OnResolve(beast::error_code ec, tcp::resolver::results_type results);
void OnConnect(beast::error_code ec, tcp::resolver::results_type::endpoint_type ep);
void OnHandshake(beast::error_code ec);
void OnRead(beast::error_code ec, std::size_t bytesTransferred);
void OnWrite(beast::error_code ec, std::size_t bytesTransferred);
private:
URL url_;
std::string token_;
std::queue<SignalResponse> read_queue_;
std::queue<SignalRequest> write_queue_;
bool connected_;
bool reading_, writing_;
beast::flat_buffer write_buffer_;
beast::flat_buffer read_buffer_;
// Keep order
net::io_context io_context_;
net::executor_work_guard <net::io_context::executor_type> work_guard_ = net::make_work_guard(
io_context_); // Prevent the IOContext from running out of work
tcp::resolver resolver_{io_context_};
websocket::stream <beast::tcp_stream> websocket_{io_context_};
};
} // livekit
#endif //LIVEKIT_NATIVE_SIGNAL_CLIENT_H
-36
View File
@@ -1,36 +0,0 @@
//
// Created by Théo Monnom on 01/05/2022.
//
#ifndef LIVEKIT_NATIVE_UTILS_H
#define LIVEKIT_NATIVE_UTILS_H
#include <string>
#include <boost/regex.hpp>
namespace livekit {
// TODO Do I need path + query ?
struct URL {
std::string protocol;
std::string host;
std::string port;
};
static URL ParseURL(const std::string &url) {
boost::regex reg("(ws|wss)://([^:]*):?(\\d*)(.*)");
boost::match_results<std::string::const_iterator> groups;
if (boost::regex_search(url, groups, reg)) {
return URL{
groups[1],
groups[2],
groups[3]
};
}
throw std::runtime_error{"failed to parse url"};
}
} // livekit
#endif //LIVEKIT_NATIVE_UTILS_H