Added WebSocket support to C API

This commit is contained in:
Paul-Louis Ageneau
2020-03-16 18:07:37 +01:00
parent adeaf5dedc
commit 03a48c1c09
3 changed files with 153 additions and 81 deletions

View File

@ -42,8 +42,7 @@ typedef enum {
RTC_GATHERING_COMPLETE = 2 RTC_GATHERING_COMPLETE = 2
} rtcGatheringState; } rtcGatheringState;
// Don't change, it must match plog severity typedef enum { // Don't change, it must match plog severity
typedef enum {
RTC_LOG_NONE = 0, RTC_LOG_NONE = 0,
RTC_LOG_FATAL = 1, RTC_LOG_FATAL = 1,
RTC_LOG_ERROR = 2, RTC_LOG_ERROR = 2,
@ -76,10 +75,10 @@ typedef void (*availableCallbackFunc)(void *ptr);
void rtcInitLogger(rtcLogLevel level); void rtcInitLogger(rtcLogLevel level);
// User pointer // User pointer
void rtcSetUserPointer(int i, void *ptr); void rtcSetUserPointer(int id, void *ptr);
// PeerConnection // PeerConnection
int rtcCreatePeerConnection(const rtcConfiguration *config); int rtcCreatePeerConnection(const rtcConfiguration *config); // returns pc id
int rtcDeletePeerConnection(int pc); int rtcDeletePeerConnection(int pc);
int rtcSetDataChannelCallback(int pc, dataChannelCallbackFunc cb); int rtcSetDataChannelCallback(int pc, dataChannelCallbackFunc cb);
@ -95,24 +94,32 @@ int rtcGetLocalAddress(int pc, char *buffer, int size);
int rtcGetRemoteAddress(int pc, char *buffer, int size); int rtcGetRemoteAddress(int pc, char *buffer, int size);
// DataChannel // DataChannel
int rtcCreateDataChannel(int pc, const char *label); int rtcCreateDataChannel(int pc, const char *label); // returns dc id
int rtcDeleteDataChannel(int dc); int rtcDeleteDataChannel(int dc);
int rtcGetDataChannelLabel(int dc, char *buffer, int size); int rtcGetDataChannelLabel(int dc, char *buffer, int size);
int rtcSetOpenCallback(int dc, openCallbackFunc cb);
int rtcSetClosedCallback(int dc, closedCallbackFunc cb);
int rtcSetErrorCallback(int dc, errorCallbackFunc cb);
int rtcSetMessageCallback(int dc, messageCallbackFunc cb);
int rtcSendMessage(int dc, const char *data, int size);
int rtcGetBufferedAmount(int dc); // total size buffered to send // WebSocket
int rtcSetBufferedAmountLowThreshold(int dc, int amount); #if ENABLE_WEBSOCKET
int rtcSetBufferedAmountLowCallback(int dc, bufferedAmountLowCallbackFunc cb); int rtcCreateWebSocket(const char *url); // returns ws id
int rtcDeleteWebsocket(int ws);
#endif
// DataChannel extended API // DataChannel and WebSocket common API
int rtcGetAvailableAmount(int dc); // total size available to receive int rtcSetOpenCallback(int id, openCallbackFunc cb);
int rtcSetAvailableCallback(int dc, availableCallbackFunc cb); int rtcSetClosedCallback(int id, closedCallbackFunc cb);
int rtcReceiveMessage(int dc, char *buffer, int *size); int rtcSetErrorCallback(int id, errorCallbackFunc cb);
int rtcSetMessageCallback(int id, messageCallbackFunc cb);
int rtcSendMessage(int id, const char *data, int size);
int rtcGetBufferedAmount(int id); // total size buffered to send
int rtcSetBufferedAmountLowThreshold(int id, int amount);
int rtcSetBufferedAmountLowCallback(int id, bufferedAmountLowCallbackFunc cb);
// DataChannel and WebSocket common extended API
int rtcGetAvailableAmount(int id); // total size available to receive
int rtcSetAvailableCallback(int id, availableCallbackFunc cb);
int rtcReceiveMessage(int id, char *buffer, int *size);
#ifdef __cplusplus #ifdef __cplusplus
} // extern "C" } // extern "C"

View File

@ -16,10 +16,15 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#include "datachannel.hpp"
#include "include.hpp" #include "include.hpp"
#include "datachannel.hpp"
#include "peerconnection.hpp" #include "peerconnection.hpp"
#if ENABLE_WEBSOCKET
#include "websocket.hpp"
#endif
#include <rtc.h> #include <rtc.h>
#include <exception> #include <exception>
@ -43,6 +48,9 @@ namespace {
std::unordered_map<int, shared_ptr<PeerConnection>> peerConnectionMap; std::unordered_map<int, shared_ptr<PeerConnection>> peerConnectionMap;
std::unordered_map<int, shared_ptr<DataChannel>> dataChannelMap; std::unordered_map<int, shared_ptr<DataChannel>> dataChannelMap;
#if ENABLE_WEBSOCKET
std::unordered_map<int, shared_ptr<WebSocket>> webSocketMap;
#endif
std::unordered_map<int, void *> userPointerMap; std::unordered_map<int, void *> userPointerMap;
std::mutex mutex; std::mutex mutex;
int lastId = 0; int lastId = 0;
@ -103,6 +111,40 @@ bool eraseDataChannel(int dc) {
return true; return true;
} }
#if ENABLE_WEBSOCKET
shared_ptr<WebSocket> getWebSocket(int id) {
std::lock_guard lock(mutex);
auto it = webSocketMap.find(id);
return it != webSocketMap.end() ? it->second : nullptr;
}
int emplaceWebSocket(shared_ptr<WebSocket> ptr) {
std::lock_guard lock(mutex);
int ws = ++lastId;
webSocketMap.emplace(std::make_pair(ws, ptr));
return ws;
}
bool eraseWebSocket(int ws) {
std::lock_guard lock(mutex);
if (webSocketMap.erase(ws) == 0)
return false;
userPointerMap.erase(ws);
return true;
}
#endif
shared_ptr<Channel> getChannel(int id) {
std::lock_guard lock(mutex);
if (auto it = dataChannelMap.find(id); it != dataChannelMap.end())
return it->second;
#if ENABLE_WEBSOCKET
if (auto it = webSocketMap.find(id); it != webSocketMap.end())
return it->second;
#endif
return nullptr;
}
} // namespace } // namespace
void rtcInitLogger(rtcLogLevel level) { InitLogger(static_cast<LogLevel>(level)); } void rtcInitLogger(rtcLogLevel level) { InitLogger(static_cast<LogLevel>(level)); }
@ -164,6 +206,29 @@ int rtcDeleteDataChannel(int dc) {
return 0; return 0;
} }
#if ENABLE_WEBSOCKET
int rtcCreateWebSocket(const char *url) {
return emplaceWebSocket(std::make_shared<WebSocket>(url));
}
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) { int rtcSetDataChannelCallback(int pc, dataChannelCallbackFunc cb) {
auto peerConnection = getPeerConnection(pc); auto peerConnection = getPeerConnection(pc);
if (!peerConnection) if (!peerConnection)
@ -298,135 +363,135 @@ int rtcGetDataChannelLabel(int dc, char *buffer, int size) {
return size + 1; return size + 1;
} }
int rtcSetOpenCallback(int dc, openCallbackFunc cb) { int rtcSetOpenCallback(int id, openCallbackFunc cb) {
auto dataChannel = getDataChannel(dc); auto channel = getChannel(id);
if (!dataChannel) if (!channel)
return -1; return -1;
if (cb) if (cb)
dataChannel->onOpen([dc, cb]() { cb(getUserPointer(dc)); }); channel->onOpen([id, cb]() { cb(getUserPointer(id)); });
else else
dataChannel->onOpen(nullptr); channel->onOpen(nullptr);
return 0; return 0;
} }
int rtcSetClosedCallback(int dc, closedCallbackFunc cb) { int rtcSetClosedCallback(int id, closedCallbackFunc cb) {
auto dataChannel = getDataChannel(dc); auto channel = getChannel(id);
if (!dataChannel) if (!channel)
return -1; return -1;
if (cb) if (cb)
dataChannel->onClosed([dc, cb]() { cb(getUserPointer(dc)); }); channel->onClosed([id, cb]() { cb(getUserPointer(id)); });
else else
dataChannel->onClosed(nullptr); channel->onClosed(nullptr);
return 0; return 0;
} }
int rtcSetErrorCallback(int dc, errorCallbackFunc cb) { int rtcSetErrorCallback(int id, errorCallbackFunc cb) {
auto dataChannel = getDataChannel(dc); auto channel = getChannel(id);
if (!dataChannel) if (!channel)
return -1; return -1;
if (cb) if (cb)
dataChannel->onError( channel->onError([id, cb](const string &error) { cb(error.c_str(), getUserPointer(id)); });
[dc, cb](const string &error) { cb(error.c_str(), getUserPointer(dc)); });
else else
dataChannel->onError(nullptr); channel->onError(nullptr);
return 0; return 0;
} }
int rtcSetMessageCallback(int dc, messageCallbackFunc cb) { int rtcSetMessageCallback(int id, messageCallbackFunc cb) {
auto dataChannel = getDataChannel(dc); auto channel = getChannel(id);
if (!dataChannel) if (!channel)
return -1; return -1;
if (cb) if (cb)
dataChannel->onMessage( channel->onMessage(
[dc, cb](const binary &b) { [id, cb](const binary &b) {
cb(reinterpret_cast<const char *>(b.data()), b.size(), getUserPointer(dc)); cb(reinterpret_cast<const char *>(b.data()), b.size(), getUserPointer(id));
}, },
[dc, cb](const string &s) { cb(s.c_str(), -1, getUserPointer(dc)); }); [id, cb](const string &s) { cb(s.c_str(), -1, getUserPointer(id)); });
else else
dataChannel->onMessage(nullptr); channel->onMessage(nullptr);
return 0; return 0;
} }
int rtcSendMessage(int dc, const char *data, int size) { int rtcSendMessage(int id, const char *data, int size) {
auto dataChannel = getDataChannel(dc); auto channel = getChannel(id);
if (!dataChannel) if (!channel)
return -1; return -1;
if (size >= 0) { if (size >= 0) {
auto b = reinterpret_cast<const byte *>(data); auto b = reinterpret_cast<const byte *>(data);
CATCH(dataChannel->send(b, size)); CATCH(channel->send(binary(b, b + size)));
return size; return size;
} else { } else {
string s(data); string str(data);
CATCH(dataChannel->send(s)); int len = str.size();
return s.size(); CATCH(channel->send(std::move(str)));
return len;
} }
} }
int rtcGetBufferedAmount(int dc) { int rtcGetBufferedAmount(int id) {
auto dataChannel = getDataChannel(dc); auto channel = getChannel(id);
if (!dataChannel) if (!channel)
return -1; return -1;
CATCH(return int(dataChannel->bufferedAmount())); CATCH(return int(channel->bufferedAmount()));
} }
int rtcSetBufferedAmountLowThreshold(int dc, int amount) { int rtcSetBufferedAmountLowThreshold(int id, int amount) {
auto dataChannel = getDataChannel(dc); auto channel = getChannel(id);
if (!dataChannel) if (!channel)
return -1; return -1;
CATCH(dataChannel->setBufferedAmountLowThreshold(size_t(amount))); CATCH(channel->setBufferedAmountLowThreshold(size_t(amount)));
return 0; return 0;
} }
int rtcSetBufferedAmountLowCallback(int dc, bufferedAmountLowCallbackFunc cb) { int rtcSetBufferedAmountLowCallback(int id, bufferedAmountLowCallbackFunc cb) {
auto dataChannel = getDataChannel(dc); auto channel = getChannel(id);
if (!dataChannel) if (!channel)
return -1; return -1;
if (cb) if (cb)
dataChannel->onBufferedAmountLow([dc, cb]() { cb(getUserPointer(dc)); }); channel->onBufferedAmountLow([id, cb]() { cb(getUserPointer(id)); });
else else
dataChannel->onBufferedAmountLow(nullptr); channel->onBufferedAmountLow(nullptr);
return 0; return 0;
} }
int rtcGetAvailableAmount(int dc) { int rtcGetAvailableAmount(int id) {
auto dataChannel = getDataChannel(dc); auto channel = getChannel(id);
if (!dataChannel) if (!channel)
return -1; return -1;
CATCH(return int(dataChannel->availableAmount())); CATCH(return int(channel->availableAmount()));
} }
int rtcSetAvailableCallback(int dc, availableCallbackFunc cb) { int rtcSetAvailableCallback(int id, availableCallbackFunc cb) {
auto dataChannel = getDataChannel(dc); auto channel = getChannel(id);
if (!dataChannel) if (!channel)
return -1; return -1;
if (cb) if (cb)
dataChannel->onOpen([dc, cb]() { cb(getUserPointer(dc)); }); channel->onOpen([id, cb]() { cb(getUserPointer(id)); });
else else
dataChannel->onOpen(nullptr); channel->onOpen(nullptr);
return 0; return 0;
} }
int rtcReceiveMessage(int dc, char *buffer, int *size) { int rtcReceiveMessage(int id, char *buffer, int *size) {
auto dataChannel = getDataChannel(dc); auto channel = getChannel(id);
if (!dataChannel) if (!channel)
return -1; return -1;
if (!size) if (!size)
return -1; return -1;
CATCH({ CATCH({
auto message = dataChannel->receive(); auto message = channel->receive();
if (!message) if (!message)
return 0; return 0;

View File

@ -25,19 +25,19 @@ void test_capi();
int main(int argc, char **argv) { int main(int argc, char **argv) {
try { try {
std::cout << "*** Running connectivity test..." << std::endl; cout << endl << "*** Running connectivity test..." << endl;
test_connectivity(); test_connectivity();
std::cout << "*** Finished connectivity test" << std::endl; cout << "*** Finished connectivity test" << endl;
} catch (const exception &e) { } catch (const exception &e) {
std::cerr << "Connectivity test failed: " << e.what() << endl; cerr << "Connectivity test failed: " << e.what() << endl;
return -1; return -1;
} }
try { try {
std::cout << "*** Running C API test..." << std::endl; cout << endl << "*** Running C API test..." << endl;
test_capi(); test_capi();
std::cout << "*** Finished C API test" << std::endl; cout << "*** Finished C API test" << endl;
} catch (const exception &e) { } catch (const exception &e) {
std::cerr << "C API test failed: " << e.what() << endl; cerr << "C API test failed: " << e.what() << endl;
return -1; return -1;
} }
return 0; return 0;