Properly catch exceptions in C API

This commit is contained in:
Paul-Louis Ageneau
2020-06-10 16:54:32 +02:00
parent 22a1c56863
commit d0695aa9cb
5 changed files with 377 additions and 376 deletions

View File

@ -60,6 +60,10 @@ typedef enum { // Don't change, it must match plog severity
RTC_LOG_VERBOSE = 6 RTC_LOG_VERBOSE = 6
} rtcLogLevel; } rtcLogLevel;
const int RTC_ERR_SUCCESS = 0;
const int RTC_ERR_INVALID = -1; // invalid argument
const int RTC_ERR_FAILURE = -2; // runtime error
typedef struct { typedef struct {
const char **iceServers; const char **iceServers;
int iceServersCount; int iceServersCount;
@ -129,7 +133,8 @@ int rtcGetAvailableAmount(int id); // total size available to receive
int rtcSetAvailableCallback(int id, availableCallbackFunc cb); int rtcSetAvailableCallback(int id, availableCallbackFunc cb);
int rtcReceiveMessage(int id, char *buffer, int *size); int rtcReceiveMessage(int id, char *buffer, int *size);
// Cleanup // Optional preload and cleanup
void rtcPreload();
void rtcCleanup(); void rtcCleanup();
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -235,7 +235,7 @@ namespace {
template <class F, class... Args> template <class F, class... Args>
std::future<std::result_of_t<std::decay_t<F>(std::decay_t<Args>...)>> thread_call(F &&f, std::future<std::result_of_t<std::decay_t<F>(std::decay_t<Args>...)>> thread_call(F &&f,
Args &&... args) { Args &&... args) {
using R = std::result_of_t<std::decay_t<F>(std::decay_t<Args>...)>; using R = std::invoke_result_t<std::decay_t<F>, std::decay_t<Args>...>;
std::packaged_task<R()> task(std::bind(f, std::forward<Args>(args)...)); std::packaged_task<R()> task(std::bind(f, std::forward<Args>(args)...));
std::future<R> future = task.get_future(); std::future<R> future = task.get_future();
std::thread t(std::move(task)); std::thread t(std::move(task));

View File

@ -42,6 +42,9 @@ PeerConnection::PeerConnection(const Configuration &config)
: mConfig(config), mCertificate(make_certificate()), mState(State::New), : mConfig(config), mCertificate(make_certificate()), mState(State::New),
mGatheringState(GatheringState::New) { mGatheringState(GatheringState::New) {
PLOG_VERBOSE << "Creating PeerConnection"; PLOG_VERBOSE << "Creating PeerConnection";
if (config.portRangeEnd && config.portRangeBegin > config.portRangeEnd)
throw std::invalid_argument("Invalid port range");
} }
PeerConnection::~PeerConnection() { PeerConnection::~PeerConnection() {

View File

@ -29,6 +29,7 @@
#include <exception> #include <exception>
#include <mutex> #include <mutex>
#include <type_traits>
#include <unordered_map> #include <unordered_map>
#include <utility> #include <utility>
@ -36,14 +37,6 @@ using namespace rtc;
using std::shared_ptr; using std::shared_ptr;
using std::string; using std::string;
#define CATCH(statement) \
try { \
statement; \
} catch (const std::exception &e) { \
PLOG_ERROR << e.what(); \
return -1; \
}
namespace { namespace {
std::unordered_map<int, shared_ptr<PeerConnection>> peerConnectionMap; std::unordered_map<int, shared_ptr<PeerConnection>> peerConnectionMap;
@ -71,14 +64,18 @@ void setUserPointer(int i, void *ptr) {
shared_ptr<PeerConnection> getPeerConnection(int id) { shared_ptr<PeerConnection> getPeerConnection(int id) {
std::lock_guard lock(mutex); std::lock_guard lock(mutex);
auto it = peerConnectionMap.find(id); if (auto it = peerConnectionMap.find(id); it != peerConnectionMap.end())
return it != peerConnectionMap.end() ? it->second : nullptr; return it->second;
else
throw std::invalid_argument("PeerConnection ID does not exist");
} }
shared_ptr<DataChannel> getDataChannel(int id) { shared_ptr<DataChannel> getDataChannel(int id) {
std::lock_guard lock(mutex); std::lock_guard lock(mutex);
auto it = dataChannelMap.find(id); if (auto it = dataChannelMap.find(id); it != dataChannelMap.end())
return it != dataChannelMap.end() ? it->second : nullptr; return it->second;
else
throw std::invalid_argument("DataChannel ID does not exist");
} }
int emplacePeerConnection(shared_ptr<PeerConnection> ptr) { int emplacePeerConnection(shared_ptr<PeerConnection> ptr) {
@ -95,27 +92,27 @@ int emplaceDataChannel(shared_ptr<DataChannel> ptr) {
return dc; return dc;
} }
bool erasePeerConnection(int pc) { void erasePeerConnection(int pc) {
std::lock_guard lock(mutex); std::lock_guard lock(mutex);
if (peerConnectionMap.erase(pc) == 0) if (peerConnectionMap.erase(pc) == 0)
return false; throw std::invalid_argument("PeerConnection ID does not exist");
userPointerMap.erase(pc); userPointerMap.erase(pc);
return true;
} }
bool eraseDataChannel(int dc) { void eraseDataChannel(int dc) {
std::lock_guard lock(mutex); std::lock_guard lock(mutex);
if (dataChannelMap.erase(dc) == 0) if (dataChannelMap.erase(dc) == 0)
return false; throw std::invalid_argument("DataChannel ID does not exist");
userPointerMap.erase(dc); userPointerMap.erase(dc);
return true;
} }
#if RTC_ENABLE_WEBSOCKET #if RTC_ENABLE_WEBSOCKET
shared_ptr<WebSocket> getWebSocket(int id) { shared_ptr<WebSocket> getWebSocket(int id) {
std::lock_guard lock(mutex); std::lock_guard lock(mutex);
auto it = webSocketMap.find(id); if (auto it = webSocketMap.find(id); it != webSocketMap.end())
return it != webSocketMap.end() ? it->second : nullptr; return it->second;
else
throw std::invalid_argument("WebSocket ID does not exist");
} }
int emplaceWebSocket(shared_ptr<WebSocket> ptr) { int emplaceWebSocket(shared_ptr<WebSocket> ptr) {
@ -125,12 +122,11 @@ int emplaceWebSocket(shared_ptr<WebSocket> ptr) {
return ws; return ws;
} }
bool eraseWebSocket(int ws) { void eraseWebSocket(int ws) {
std::lock_guard lock(mutex); std::lock_guard lock(mutex);
if (webSocketMap.erase(ws) == 0) if (webSocketMap.erase(ws) == 0)
return false; throw std::invalid_argument("WebSocket ID does not exist");
userPointerMap.erase(ws); userPointerMap.erase(ws);
return true;
} }
#endif #endif
@ -142,9 +138,28 @@ shared_ptr<Channel> getChannel(int id) {
if (auto it = webSocketMap.find(id); it != webSocketMap.end()) if (auto it = webSocketMap.find(id); it != webSocketMap.end())
return it->second; return it->second;
#endif #endif
return nullptr; throw std::invalid_argument("DataChannel or WebSocket ID does not exist");
} }
template <typename F> int wrap(F func) {
try {
return func();
} catch (const std::invalid_argument &e) {
PLOG_ERROR << e.what();
return RTC_ERR_INVALID;
} catch (const std::exception &e) {
PLOG_ERROR << e.what();
return RTC_ERR_FAILURE;
}
}
#define WRAP(statement) \
wrap([&]() { \
statement; \
return RTC_ERR_SUCCESS; \
})
} // namespace } // namespace
void rtcInitLogger(rtcLogLevel level) { InitLogger(static_cast<LogLevel>(level)); } void rtcInitLogger(rtcLogLevel level) { InitLogger(static_cast<LogLevel>(level)); }
@ -152,370 +167,349 @@ void rtcInitLogger(rtcLogLevel level) { InitLogger(static_cast<LogLevel>(level))
void rtcSetUserPointer(int i, void *ptr) { setUserPointer(i, ptr); } void rtcSetUserPointer(int i, void *ptr) { setUserPointer(i, ptr); }
int rtcCreatePeerConnection(const rtcConfiguration *config) { int rtcCreatePeerConnection(const rtcConfiguration *config) {
Configuration c; return WRAP({
for (int i = 0; i < config->iceServersCount; ++i) Configuration c;
c.iceServers.emplace_back(string(config->iceServers[i])); for (int i = 0; i < config->iceServersCount; ++i)
c.iceServers.emplace_back(string(config->iceServers[i]));
if (config->portRangeBegin || config->portRangeEnd) { if (config->portRangeBegin || config->portRangeEnd) {
c.portRangeBegin = config->portRangeBegin; c.portRangeBegin = config->portRangeBegin;
c.portRangeEnd = config->portRangeEnd; c.portRangeEnd = config->portRangeEnd;
} }
return emplacePeerConnection(std::make_shared<PeerConnection>(c)); return emplacePeerConnection(std::make_shared<PeerConnection>(c));
});
} }
int rtcDeletePeerConnection(int pc) { int rtcDeletePeerConnection(int pc) {
auto peerConnection = getPeerConnection(pc); return WRAP({
if (!peerConnection) auto peerConnection = getPeerConnection(pc);
return -1; peerConnection->onDataChannel(nullptr);
peerConnection->onLocalDescription(nullptr);
peerConnection->onLocalCandidate(nullptr);
peerConnection->onStateChange(nullptr);
peerConnection->onGatheringStateChange(nullptr);
peerConnection->onDataChannel(nullptr); erasePeerConnection(pc);
peerConnection->onLocalDescription(nullptr); });
peerConnection->onLocalCandidate(nullptr);
peerConnection->onStateChange(nullptr);
peerConnection->onGatheringStateChange(nullptr);
erasePeerConnection(pc);
return 0;
} }
int rtcCreateDataChannel(int pc, const char *label) { int rtcCreateDataChannel(int pc, const char *label) {
auto peerConnection = getPeerConnection(pc); return WRAP({
if (!peerConnection) auto peerConnection = getPeerConnection(pc);
return -1; int dc = emplaceDataChannel(peerConnection->createDataChannel(string(label)));
rtcSetUserPointer(dc, getUserPointer(pc));
int dc = emplaceDataChannel(peerConnection->createDataChannel(string(label))); return dc;
void *ptr = getUserPointer(pc); });
rtcSetUserPointer(dc, ptr);
return dc;
} }
int rtcDeleteDataChannel(int dc) { int rtcDeleteDataChannel(int dc) {
auto dataChannel = getDataChannel(dc); return WRAP({
if (!dataChannel) auto dataChannel = getDataChannel(dc);
return -1; dataChannel->onOpen(nullptr);
dataChannel->onClosed(nullptr);
dataChannel->onError(nullptr);
dataChannel->onMessage(nullptr);
dataChannel->onBufferedAmountLow(nullptr);
dataChannel->onAvailable(nullptr);
dataChannel->onOpen(nullptr); eraseDataChannel(dc);
dataChannel->onClosed(nullptr); });
dataChannel->onError(nullptr);
dataChannel->onMessage(nullptr);
dataChannel->onBufferedAmountLow(nullptr);
dataChannel->onAvailable(nullptr);
eraseDataChannel(dc);
return 0;
} }
#if RTC_ENABLE_WEBSOCKET #if RTC_ENABLE_WEBSOCKET
int rtcCreateWebSocket(const char *url) { int rtcCreateWebSocket(const char *url) {
auto ws = std::make_shared<WebSocket>(); return WRAP({
ws->open(url); auto ws = std::make_shared<WebSocket>();
return emplaceWebSocket(ws); ws->open(url);
} return emplaceWebSocket(ws);
int rtcDeleteWebsocket(int ws) {
auto webSocket = getWebSocket(ws);
if (!webSocket)
return -1;
webSocket->onOpen(nullptr);
webSocket->onClosed(nullptr);
webSocket->onError(nullptr);
webSocket->onMessage(nullptr);
webSocket->onBufferedAmountLow(nullptr);
webSocket->onAvailable(nullptr);
eraseWebSocket(ws);
return 0;
}
#endif
int rtcSetDataChannelCallback(int pc, dataChannelCallbackFunc cb) {
auto peerConnection = getPeerConnection(pc);
if (!peerConnection)
return -1;
if (cb)
peerConnection->onDataChannel([pc, cb](std::shared_ptr<DataChannel> dataChannel) {
int dc = emplaceDataChannel(dataChannel);
void *ptr = getUserPointer(pc);
rtcSetUserPointer(dc, ptr);
cb(dc, ptr);
});
else
peerConnection->onDataChannel(nullptr);
return 0;
}
int rtcSetLocalDescriptionCallback(int pc, descriptionCallbackFunc cb) {
auto peerConnection = getPeerConnection(pc);
if (!peerConnection)
return -1;
if (cb)
peerConnection->onLocalDescription([pc, cb](const Description &desc) {
cb(string(desc).c_str(), desc.typeString().c_str(), getUserPointer(pc));
});
else
peerConnection->onLocalDescription(nullptr);
return 0;
}
int rtcSetLocalCandidateCallback(int pc, candidateCallbackFunc cb) {
auto peerConnection = getPeerConnection(pc);
if (!peerConnection)
return -1;
if (cb)
peerConnection->onLocalCandidate([pc, cb](const Candidate &cand) {
cb(cand.candidate().c_str(), cand.mid().c_str(), getUserPointer(pc));
});
else
peerConnection->onLocalCandidate(nullptr);
return 0;
}
int rtcSetStateChangeCallback(int pc, stateChangeCallbackFunc cb) {
auto peerConnection = getPeerConnection(pc);
if (!peerConnection)
return -1;
if (cb)
peerConnection->onStateChange([pc, cb](PeerConnection::State state) {
cb(static_cast<rtcState>(state), getUserPointer(pc));
});
else
peerConnection->onStateChange(nullptr);
return 0;
}
int rtcSetGatheringStateChangeCallback(int pc, gatheringStateCallbackFunc cb) {
auto peerConnection = getPeerConnection(pc);
if (!peerConnection)
return -1;
if (cb)
peerConnection->onGatheringStateChange([pc, cb](PeerConnection::GatheringState state) {
cb(static_cast<rtcGatheringState>(state), getUserPointer(pc));
});
else
peerConnection->onGatheringStateChange(nullptr);
return 0;
}
int rtcSetRemoteDescription(int pc, const char *sdp, const char *type) {
auto peerConnection = getPeerConnection(pc);
if (!peerConnection)
return -1;
CATCH(peerConnection->setRemoteDescription({string(sdp), type ? string(type) : ""}));
return 0;
}
int rtcAddRemoteCandidate(int pc, const char *cand, const char *mid) {
auto peerConnection = getPeerConnection(pc);
if (!peerConnection)
return -1;
CATCH(peerConnection->addRemoteCandidate({string(cand), mid ? string(mid) : ""}))
return 0;
}
int rtcGetLocalAddress(int pc, char *buffer, int size) {
auto peerConnection = getPeerConnection(pc);
if (!peerConnection)
return -1;
if (auto addr = peerConnection->localAddress()) {
size = std::min(size_t(size - 1), addr->size());
std::copy(addr->data(), addr->data() + size, buffer);
buffer[size] = '\0';
return size + 1;
}
return -1;
}
int rtcGetRemoteAddress(int pc, char *buffer, int size) {
auto peerConnection = getPeerConnection(pc);
if (!peerConnection)
return -1;
if (auto addr = peerConnection->remoteAddress()) {
size = std::min(size_t(size - 1), addr->size());
std::copy(addr->data(), addr->data() + size, buffer);
buffer[size] = '\0';
return size + 1;
}
return -1;
}
int rtcGetDataChannelLabel(int dc, char *buffer, int size) {
auto dataChannel = getDataChannel(dc);
if (!dataChannel)
return -1;
if (!size)
return 0;
string label = dataChannel->label();
size = std::min(size_t(size - 1), label.size());
std::copy(label.data(), label.data() + size, buffer);
buffer[size] = '\0';
return size + 1;
}
int rtcSetOpenCallback(int id, openCallbackFunc cb) {
auto channel = getChannel(id);
if (!channel)
return -1;
if (cb)
channel->onOpen([id, cb]() { cb(getUserPointer(id)); });
else
channel->onOpen(nullptr);
return 0;
}
int rtcSetClosedCallback(int id, closedCallbackFunc cb) {
auto channel = getChannel(id);
if (!channel)
return -1;
if (cb)
channel->onClosed([id, cb]() { cb(getUserPointer(id)); });
else
channel->onClosed(nullptr);
return 0;
}
int rtcSetErrorCallback(int id, errorCallbackFunc cb) {
auto channel = getChannel(id);
if (!channel)
return -1;
if (cb)
channel->onError([id, cb](const string &error) { cb(error.c_str(), getUserPointer(id)); });
else
channel->onError(nullptr);
return 0;
}
int rtcSetMessageCallback(int id, messageCallbackFunc cb) {
auto channel = getChannel(id);
if (!channel)
return -1;
if (cb)
channel->onMessage(
[id, cb](const binary &b) {
cb(reinterpret_cast<const char *>(b.data()), b.size(), getUserPointer(id));
},
[id, cb](const string &s) { cb(s.c_str(), -1, getUserPointer(id)); });
else
channel->onMessage(nullptr);
return 0;
}
int rtcSendMessage(int id, const char *data, int size) {
auto channel = getChannel(id);
if (!channel)
return -1;
if (size >= 0) {
auto b = reinterpret_cast<const byte *>(data);
CATCH(channel->send(binary(b, b + size)));
return size;
} else {
string str(data);
int len = str.size();
CATCH(channel->send(std::move(str)));
return len;
}
}
int rtcGetBufferedAmount(int id) {
auto channel = getChannel(id);
if (!channel)
return -1;
CATCH(return int(channel->bufferedAmount()));
}
int rtcSetBufferedAmountLowThreshold(int id, int amount) {
auto channel = getChannel(id);
if (!channel)
return -1;
CATCH(channel->setBufferedAmountLowThreshold(size_t(amount)));
return 0;
}
int rtcSetBufferedAmountLowCallback(int id, bufferedAmountLowCallbackFunc cb) {
auto channel = getChannel(id);
if (!channel)
return -1;
if (cb)
channel->onBufferedAmountLow([id, cb]() { cb(getUserPointer(id)); });
else
channel->onBufferedAmountLow(nullptr);
return 0;
}
int rtcGetAvailableAmount(int id) {
auto channel = getChannel(id);
if (!channel)
return -1;
CATCH(return int(channel->availableAmount()));
}
int rtcSetAvailableCallback(int id, availableCallbackFunc cb) {
auto channel = getChannel(id);
if (!channel)
return -1;
if (cb)
channel->onOpen([id, cb]() { cb(getUserPointer(id)); });
else
channel->onOpen(nullptr);
return 0;
}
int rtcReceiveMessage(int id, char *buffer, int *size) {
auto channel = getChannel(id);
if (!channel)
return -1;
if (!size)
return -1;
CATCH({
auto message = channel->receive();
if (!message)
return 0;
return std::visit( //
overloaded{ //
[&](const binary &b) {
*size = std::min(*size, int(b.size()));
auto data = reinterpret_cast<const char *>(b.data());
std::copy(data, data + *size, buffer);
return *size;
},
[&](const string &s) {
int len = std::min(*size - 1, int(s.size()));
if (len >= 0) {
std::copy(s.data(), s.data() + len, buffer);
buffer[len] = '\0';
}
*size = -(len + 1);
return len + 1;
}},
*message);
}); });
} }
int rtcDeleteWebsocket(int ws) {
return WRAP({
auto webSocket = getWebSocket(ws);
webSocket->onOpen(nullptr);
webSocket->onClosed(nullptr);
webSocket->onError(nullptr);
webSocket->onMessage(nullptr);
webSocket->onBufferedAmountLow(nullptr);
webSocket->onAvailable(nullptr);
eraseWebSocket(ws);
});
}
#endif
int rtcSetDataChannelCallback(int pc, dataChannelCallbackFunc cb) {
return WRAP({
auto peerConnection = getPeerConnection(pc);
if (cb)
peerConnection->onDataChannel([pc, cb](std::shared_ptr<DataChannel> dataChannel) {
int dc = emplaceDataChannel(dataChannel);
void *ptr = getUserPointer(pc);
rtcSetUserPointer(dc, ptr);
cb(dc, ptr);
});
else
peerConnection->onDataChannel(nullptr);
});
}
int rtcSetLocalDescriptionCallback(int pc, descriptionCallbackFunc cb) {
return WRAP({
auto peerConnection = getPeerConnection(pc);
if (cb)
peerConnection->onLocalDescription([pc, cb](const Description &desc) {
cb(string(desc).c_str(), desc.typeString().c_str(), getUserPointer(pc));
});
else
peerConnection->onLocalDescription(nullptr);
});
}
int rtcSetLocalCandidateCallback(int pc, candidateCallbackFunc cb) {
return WRAP({
auto peerConnection = getPeerConnection(pc);
if (cb)
peerConnection->onLocalCandidate([pc, cb](const Candidate &cand) {
cb(cand.candidate().c_str(), cand.mid().c_str(), getUserPointer(pc));
});
else
peerConnection->onLocalCandidate(nullptr);
});
}
int rtcSetStateChangeCallback(int pc, stateChangeCallbackFunc cb) {
return WRAP({
auto peerConnection = getPeerConnection(pc);
if (cb)
peerConnection->onStateChange([pc, cb](PeerConnection::State state) {
cb(static_cast<rtcState>(state), getUserPointer(pc));
});
else
peerConnection->onStateChange(nullptr);
});
}
int rtcSetGatheringStateChangeCallback(int pc, gatheringStateCallbackFunc cb) {
return WRAP({
auto peerConnection = getPeerConnection(pc);
if (cb)
peerConnection->onGatheringStateChange([pc, cb](PeerConnection::GatheringState state) {
cb(static_cast<rtcGatheringState>(state), getUserPointer(pc));
});
else
peerConnection->onGatheringStateChange(nullptr);
});
}
int rtcSetRemoteDescription(int pc, const char *sdp, const char *type) {
return WRAP({
auto peerConnection = getPeerConnection(pc);
if (!sdp)
throw std::invalid_argument("Unexpected null pointer");
peerConnection->setRemoteDescription({string(sdp), type ? string(type) : ""});
});
}
int rtcAddRemoteCandidate(int pc, const char *cand, const char *mid) {
return WRAP({
auto peerConnection = getPeerConnection(pc);
if (!cand)
throw std::invalid_argument("Unexpected null pointer");
peerConnection->addRemoteCandidate({string(cand), mid ? string(mid) : ""});
});
}
int rtcGetLocalAddress(int pc, char *buffer, int size) {
return WRAP({
auto peerConnection = getPeerConnection(pc);
if (!buffer)
throw std::invalid_argument("Unexpected null pointer");
if (auto addr = peerConnection->localAddress()) {
size = std::min(size_t(size - 1), addr->size());
std::copy(addr->data(), addr->data() + size, buffer);
buffer[size] = '\0';
return size + 1;
}
});
}
int rtcGetRemoteAddress(int pc, char *buffer, int size) {
return WRAP({
auto peerConnection = getPeerConnection(pc);
if (!buffer)
throw std::invalid_argument("Unexpected null pointer");
if (auto addr = peerConnection->remoteAddress()) {
size = std::min(size_t(size - 1), addr->size());
std::copy(addr->data(), addr->data() + size, buffer);
buffer[size] = '\0';
return size + 1;
}
});
}
int rtcGetDataChannelLabel(int dc, char *buffer, int size) {
return WRAP({
auto dataChannel = getDataChannel(dc);
if (!buffer)
throw std::invalid_argument("Unexpected null pointer");
if (size >= 0) {
string label = dataChannel->label();
size = std::min(size_t(size - 1), label.size());
std::copy(label.data(), label.data() + size, buffer);
buffer[size] = '\0';
return size + 1;
} else {
return 0;
}
});
}
int rtcSetOpenCallback(int id, openCallbackFunc cb) {
return WRAP({
auto channel = getChannel(id);
if (cb)
channel->onOpen([id, cb]() { cb(getUserPointer(id)); });
else
channel->onOpen(nullptr);
});
}
int rtcSetClosedCallback(int id, closedCallbackFunc cb) {
return WRAP({
auto channel = getChannel(id);
if (cb)
channel->onClosed([id, cb]() { cb(getUserPointer(id)); });
else
channel->onClosed(nullptr);
});
}
int rtcSetErrorCallback(int id, errorCallbackFunc cb) {
return WRAP({
auto channel = getChannel(id);
if (cb)
channel->onError(
[id, cb](const string &error) { cb(error.c_str(), getUserPointer(id)); });
else
channel->onError(nullptr);
});
}
int rtcSetMessageCallback(int id, messageCallbackFunc cb) {
return WRAP({
auto channel = getChannel(id);
if (cb)
channel->onMessage(
[id, cb](const binary &b) {
cb(reinterpret_cast<const char *>(b.data()), b.size(), getUserPointer(id));
},
[id, cb](const string &s) { cb(s.c_str(), -1, getUserPointer(id)); });
else
channel->onMessage(nullptr);
});
}
int rtcSendMessage(int id, const char *data, int size) {
return WRAP({
auto channel = getChannel(id);
if (!data)
throw std::invalid_argument("Unexpected null pointer");
if (size >= 0) {
auto b = reinterpret_cast<const byte *>(data);
channel->send(binary(b, b + size));
return size;
} else {
string str(data);
int len = str.size();
channel->send(std::move(str));
return len;
}
});
}
int rtcGetBufferedAmount(int id) {
return WRAP({
auto channel = getChannel(id);
return int(channel->bufferedAmount());
});
}
int rtcSetBufferedAmountLowThreshold(int id, int amount) {
return WRAP({
auto channel = getChannel(id);
channel->setBufferedAmountLowThreshold(size_t(amount));
});
}
int rtcSetBufferedAmountLowCallback(int id, bufferedAmountLowCallbackFunc cb) {
return WRAP({
auto channel = getChannel(id);
if (cb)
channel->onBufferedAmountLow([id, cb]() { cb(getUserPointer(id)); });
else
channel->onBufferedAmountLow(nullptr);
});
}
int rtcGetAvailableAmount(int id) {
return WRAP({ return int(getChannel(id)->availableAmount()); });
}
int rtcSetAvailableCallback(int id, availableCallbackFunc cb) {
return WRAP({
auto channel = getChannel(id);
if (cb)
channel->onOpen([id, cb]() { cb(getUserPointer(id)); });
else
channel->onOpen(nullptr);
});
}
int rtcReceiveMessage(int id, char *buffer, int *size) {
return WRAP({
auto channel = getChannel(id);
if (!buffer || !size)
throw std::invalid_argument("Unexpected null pointer");
if (auto message = channel->receive())
return std::visit( //
overloaded{ //
[&](const binary &b) {
*size = std::min(*size, int(b.size()));
auto data = reinterpret_cast<const char *>(b.data());
std::copy(data, data + *size, buffer);
return 1;
},
[&](const string &s) {
int len = std::min(*size - 1, int(s.size()));
if (len >= 0) {
std::copy(s.data(), s.data() + len, buffer);
buffer[len] = '\0';
}
*size = -(len + 1);
return 1;
}},
*message);
else
return 0;
});
}
void rtcPreload() { rtc::Preload(); }
void rtcCleanup() { rtc::Cleanup(); } void rtcCleanup() { rtc::Cleanup(); }

View File

@ -35,7 +35,8 @@ using chrono::steady_clock;
template <class T> weak_ptr<T> make_weak_ptr(shared_ptr<T> ptr) { return ptr; } template <class T> weak_ptr<T> make_weak_ptr(shared_ptr<T> ptr) { return ptr; }
size_t benchmark(milliseconds duration) { size_t benchmark(milliseconds duration) {
InitLogger(LogLevel::Warning); rtc::InitLogger(LogLevel::Warning);
rtc::Preload();
Configuration config1; Configuration config1;
// config1.iceServers.emplace_back("stun:stun.l.google.com:19302"); // config1.iceServers.emplace_back("stun:stun.l.google.com:19302");
@ -177,19 +178,17 @@ size_t benchmark(milliseconds duration) {
pc2->close(); pc2->close();
this_thread::sleep_for(1s); this_thread::sleep_for(1s);
rtc::Cleanup();
return goodput; return goodput;
} }
#ifdef BENCHMARK_MAIN #ifdef BENCHMARK_MAIN
int main(int argc, char **argv) { int main(int argc, char **argv) {
try { try {
rtc::Preload();
size_t goodput = benchmark(30s); size_t goodput = benchmark(30s);
if (goodput == 0) if (goodput == 0)
throw runtime_error("No data received"); throw runtime_error("No data received");
rtc::Cleanup();
return 0; return 0;
} catch (const std::exception &e) { } catch (const std::exception &e) {