Better RTCError handling + tests

This commit is contained in:
Théo Monnom
2022-09-13 14:19:44 +02:00
parent d9fd69b5c0
commit 12a6d232b5
16 changed files with 325 additions and 82 deletions
@@ -4,6 +4,7 @@
#include <memory>
#include "livekit/rtc_error.h"
#include "livekit/jsep.h"
#include "libwebrtc-sys/src/jsep.rs.h"
#include "api/make_ref_counted.h"
@@ -39,7 +40,7 @@ namespace livekit {
}
void NativeCreateSdpObserver::OnFailure(webrtc::RTCError error) {
observer_->on_failure(std::make_unique<RTCError>(error));
observer_->on_failure(to_error(error));
}
std::unique_ptr<NativeCreateSdpObserverHandle> create_native_create_sdp_observer(rust::Box<CreateSdpObserverWrapper> observer){
@@ -55,7 +56,7 @@ namespace livekit {
}
void NativeSetLocalSdpObserver::OnSetLocalDescriptionComplete(webrtc::RTCError error) {
observer_->on_set_local_description_complete(std::make_unique<RTCError>(error));
observer_->on_set_local_description_complete(to_error(error));
}
std::unique_ptr<NativeSetLocalSdpObserverHandle> create_native_set_local_sdp_observer(rust::Box<SetLocalSdpObserverWrapper> observer){
@@ -71,7 +72,7 @@ namespace livekit {
}
void NativeSetRemoteSdpObserver::OnSetRemoteDescriptionComplete(webrtc::RTCError error) {
observer_->on_set_remote_description_complete(std::make_unique<RTCError>(error));
observer_->on_set_remote_description_complete(to_error(error));
}
std::unique_ptr<NativeSetRemoteSdpObserverHandle> create_native_set_remote_sdp_observer(rust::Box<SetRemoteSdpObserverWrapper> observer){
+11 -10
View File
@@ -5,21 +5,22 @@ 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>);
fn on_failure(self: &CreateSdpObserverWrapper, error: RTCError);
type SetLocalSdpObserverWrapper;
fn on_set_local_description_complete(self: &SetLocalSdpObserverWrapper, error: UniquePtr<RTCError>);
fn on_set_local_description_complete(self: &SetLocalSdpObserverWrapper, error: RTCError);
type SetRemoteSdpObserverWrapper;
fn on_set_remote_description_complete(self: &SetRemoteSdpObserverWrapper, error: UniquePtr<RTCError>);
fn on_set_remote_description_complete(self: &SetRemoteSdpObserverWrapper, error: RTCError);
}
unsafe extern "C++" {
include!("libwebrtc-sys/src/rtc_error.rs.h");
include!("livekit/jsep.h");
include!("livekit/rtc_error.h");
type RTCError = crate::rtc_error::ffi::RTCError;
type IceCandidate;
@@ -41,7 +42,7 @@ pub mod ffi {
pub trait CreateSdpObserver: Send + Sync {
fn on_success(&self, session_description: UniquePtr<ffi::SessionDescription>);
fn on_failure(&self, error: UniquePtr<RTCError>);
fn on_failure(&self, error: RTCError);
}
pub struct CreateSdpObserverWrapper {
@@ -59,7 +60,7 @@ impl CreateSdpObserverWrapper {
self.observer.on_success(session_description);
}
fn on_failure(&self, error: UniquePtr<RTCError>) {
fn on_failure(&self, error: RTCError) {
self.observer.on_failure(error);
}
}
@@ -67,7 +68,7 @@ impl CreateSdpObserverWrapper {
// SetLocalSdpObserver
pub trait SetLocalSdpObserver: Send + Sync {
fn on_set_local_description_complete(&self, error: UniquePtr<RTCError>);
fn on_set_local_description_complete(&self, error: RTCError);
}
pub struct SetLocalSdpObserverWrapper {
@@ -81,7 +82,7 @@ impl SetLocalSdpObserverWrapper {
}
}
fn on_set_local_description_complete(&self, error: UniquePtr<RTCError>) {
fn on_set_local_description_complete(&self, error: RTCError) {
self.observer.on_set_local_description_complete(error);
}
}
@@ -89,7 +90,7 @@ impl SetLocalSdpObserverWrapper {
// SetRemoteSdpObserver
pub trait SetRemoteSdpObserver: Send + Sync {
fn on_set_remote_description_complete(&self, error: UniquePtr<RTCError>);
fn on_set_remote_description_complete(&self, error: RTCError);
}
pub struct SetRemoteSdpObserverWrapper {
@@ -103,7 +104,7 @@ impl SetRemoteSdpObserverWrapper {
}
}
fn on_set_remote_description_complete(&self, error: UniquePtr<RTCError>) {
fn on_set_remote_description_complete(&self, error: RTCError) {
self.observer.on_set_remote_description_complete(error);
}
}
@@ -24,44 +24,44 @@ pub mod ffi {
#[derive(Debug)]
#[repr(u32)]
pub enum PeerConnectionState {
kNew,
kConnecting,
kConnected,
kDisconnected,
kFailed,
kClosed,
New,
Connecting,
Connected,
Disconnected,
Failed,
Closed,
}
#[derive(Debug)]
#[repr(u32)]
pub enum SignalingState {
kStable,
kHaveLocalOffer,
kHaveLocalPrAnswer,
kHaveRemoteOffer,
kHaveRemotePrAnswer,
kClosed,
Stable,
HaveLocalOffer,
HaveLocalPrAnswer,
HaveRemoteOffer,
HaveRemotePrAnswer,
Closed,
}
#[derive(Debug)]
#[repr(u32)]
pub enum IceConnectionState {
kIceConnectionNew,
kIceConnectionChecking,
kIceConnectionConnected,
kIceConnectionCompleted,
kIceConnectionFailed,
kIceConnectionDisconnected,
kIceConnectionClosed,
kIceConnectionMax,
IceConnectionNew,
IceConnectionChecking,
IceConnectionConnected,
IceConnectionCompleted,
IceConnectionFailed,
IceConnectionDisconnected,
IceConnectionClosed,
IceConnectionMax,
}
#[derive(Debug)]
#[repr(u32)]
pub enum IceGatheringState {
kIceGatheringNew,
kIceGatheringGathering,
kIceGatheringComplete
IceGatheringNew,
IceGatheringGathering,
IceGatheringComplete
}
#[derive(Debug)]
@@ -11,6 +11,7 @@
#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"
#include "livekit/rtc_error.h"
namespace livekit{
@@ -57,7 +58,7 @@ namespace livekit{
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
throw std::runtime_error(serialize_error(to_error(result.error())));
}
return std::make_unique<PeerConnection>(std::move(result.value()), std::move(observer));
@@ -42,8 +42,7 @@ pub mod ffi {
unsafe fn create_peer_connection(self: &PeerConnectionFactory, config: UniquePtr<NativeRTCConfiguration>, observer: UniquePtr<NativePeerConnectionObserver>) -> Result<UniquePtr<PeerConnection>>;
}
}
}
@@ -51,6 +50,7 @@ pub mod ffi {
/*
@@ -182,5 +182,5 @@ mod test {
}
}
*/
@@ -3,9 +3,54 @@
//
#include "livekit/rtc_error.h"
#include <iomanip>
#include <sstream>
#include <string>
namespace livekit {
RTCError::RTCError(webrtc::RTCError error) : rtc_error_(std::move(error)) {
RTCError to_error(const webrtc::RTCError &error) {
RTCError lk_error;
lk_error.error_detail = static_cast<RTCErrorDetailType>(error.error_detail());
lk_error.error_type = static_cast<RTCErrorType>(error.type());
lk_error.has_sctp_cause_code = error.sctp_cause_code().has_value();
lk_error.sctp_cause_code = error.sctp_cause_code().value();
lk_error.message = error.message();
return lk_error;
}
std::string serialize_error(const RTCError &error) {
std::stringstream ss;
ss << std::hex << std::setfill('0');
ss << std::setw(8) << (uint32_t) error.error_type;
ss << std::setw(8) << (uint32_t) error.error_detail;
ss << std::setw(2) << (uint16_t) error.has_sctp_cause_code;
ss << std::setw(4) << (uint16_t) error.sctp_cause_code;
ss << std::dec << std::setw(1) << std::string(error.message);
return ss.str();
}
#ifdef LIVEKIT_TEST
rust::String serialize_deserialize(){
RTCError lk_error;
lk_error.error_type = RTCErrorType::InternalError;
lk_error.error_detail = RTCErrorDetailType::DataChannelFailure;
lk_error.has_sctp_cause_code = true;
lk_error.sctp_cause_code = 24;
lk_error.message = "this is not a test, I repeat, this is not a test";
return serialize_error(lk_error);
}
void throw_error() {
RTCError lk_error;
lk_error.error_type = RTCErrorType::InvalidModification;
lk_error.error_detail = RTCErrorDetailType::None;
lk_error.has_sctp_cause_code = false;
lk_error.sctp_cause_code = 0;
lk_error.message = "exception is thrown!";
throw std::runtime_error(serialize_error(lk_error));
}
#endif
} // livekit
@@ -1,13 +1,115 @@
// TODO(theomonnom) Don't use RTCError as Opaque. I should use a Struct and serialize/deserialize when needed for Result<>
use std::fmt::{Display, Formatter};
use std::error::Error;
#[cxx::bridge(namespace = "livekit")]
pub mod ffi {
unsafe extern "C++" {
include!("livekit/rtc_error.h");
type RTCError;
#[derive(Debug)]
#[repr(u32)]
pub enum RTCErrorType {
None,
UnsupportedOperation,
UnsupportedParameter,
InvalidParameter,
InvalidRange,
SyntaxError,
InvalidState,
InvalidModification,
NetworkError,
ResourceExhausted,
InternalError,
OperationErrorWithData,
}
fn _unique_rtc_error() -> UniquePtr<RTCError>;
#[derive(Debug)]
#[repr(u32)]
pub enum RTCErrorDetailType {
None,
DataChannelFailure,
DtlsFailure,
FingerprintFailure,
SctpFailure,
SdpSyntaxError,
HardwareEncoderNotAvailable,
HardwareEncoderError,
}
#[derive(Debug)]
pub struct RTCError {
pub error_type: RTCErrorType,
pub message: String,
pub error_detail: RTCErrorDetailType,
pub has_sctp_cause_code: bool, // cxx doesn't support the Option trait
pub sctp_cause_code: u16
}
}
impl ffi::RTCError {
/// # Safety
/// The value must be correctly encoded
pub unsafe fn from(value: &str) -> Self {
// Parse the hex encoded error from c++
let error_type = u32::from_str_radix(&value[0..8], 16).unwrap();
let error_detail = u32::from_str_radix(&value[8..16], 16).unwrap();
let has_scp_cause_code = u8::from_str_radix(&value[16..18], 16).unwrap();
let sctp_cause_code = u16::from_str_radix(&value[18..22], 16).unwrap();
let message = String::from(&value[22..]); // msg isn't encoded
Self {
error_type: unsafe { std::mem::transmute(error_type) },
error_detail: unsafe { std::mem::transmute(error_detail) },
sctp_cause_code,
has_sctp_cause_code: has_scp_cause_code == 1,
message,
}
}
}
impl Error for ffi::RTCError {
}
impl Display for ffi::RTCError {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
write!(f, "RtcError occurred {:?}: {}", self.error_type, self.message)
}
}
#[cfg(test)]
mod tests {
use crate::rtc_error::ffi::{RTCError, RTCErrorDetailType, RTCErrorType};
#[cxx::bridge(namespace = "livekit")]
pub mod ffi {
unsafe extern "C++" {
include!("livekit/rtc_error.h");
fn serialize_deserialize() -> String;
fn throw_error() -> Result<()>;
}
}
#[test]
fn serialize_deserialize(){
let str = ffi::serialize_deserialize();
let error = unsafe { RTCError::from(&str) };
assert_eq!(error.error_type, RTCErrorType::InternalError);
assert_eq!(error.error_detail, RTCErrorDetailType::DataChannelFailure);
assert_eq!(error.has_sctp_cause_code, true);
assert_eq!(error.sctp_cause_code, 24);
assert_eq!(error.message, "this is not a test, I repeat, this is not a test");
}
#[test]
fn throw_error(){
let exc: cxx::Exception = ffi::throw_error().err().unwrap();
let error = unsafe { RTCError::from(exc.what()) };
assert_eq!(error.error_type, RTCErrorType::InvalidModification);
assert_eq!(error.error_detail, RTCErrorDetailType::None);
assert_eq!(error.has_sctp_cause_code, false);
assert_eq!(error.sctp_cause_code, 0);
assert_eq!(error.message, "exception is thrown!");
}
}