basic MacOS version
This commit is contained in:
@@ -1,8 +0,0 @@
|
||||
//
|
||||
// Created by Théo Monnom on 30/05/2022.
|
||||
//
|
||||
|
||||
#include "createsession_observer.h"
|
||||
|
||||
namespace livekit {
|
||||
} // livekit
|
||||
@@ -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
@@ -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();
|
||||
}
|
||||
@@ -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
|
||||
@@ -1,10 +0,0 @@
|
||||
//
|
||||
// Created by Théo Monnom on 21/05/2022.
|
||||
//
|
||||
|
||||
#include "peer_observer.h"
|
||||
|
||||
namespace livekit {
|
||||
|
||||
|
||||
} // livekit
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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 +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
@@ -1,5 +0,0 @@
|
||||
//
|
||||
// Created by Théo Monnom on 07/05/2022.
|
||||
//
|
||||
|
||||
#include "room.h"
|
||||
-17
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
Reference in New Issue
Block a user