|
@@ -22,195 +22,319 @@
|
|
|
|
|
|
#include <rtc.h>
|
|
|
|
|
|
+#include <exception>
|
|
|
+#include <mutex>
|
|
|
#include <unordered_map>
|
|
|
-
|
|
|
-#include <plog/Appenders/ColorConsoleAppender.h>
|
|
|
+#include <utility>
|
|
|
|
|
|
using namespace rtc;
|
|
|
using std::shared_ptr;
|
|
|
using std::string;
|
|
|
|
|
|
+#define CATCH(statement) \
|
|
|
+ try { \
|
|
|
+ statement; \
|
|
|
+ } catch (const std::exception &e) { \
|
|
|
+ PLOG_ERROR << e.what(); \
|
|
|
+ return -1; \
|
|
|
+ }
|
|
|
+
|
|
|
namespace {
|
|
|
|
|
|
std::unordered_map<int, shared_ptr<PeerConnection>> peerConnectionMap;
|
|
|
std::unordered_map<int, shared_ptr<DataChannel>> dataChannelMap;
|
|
|
std::unordered_map<int, void *> userPointerMap;
|
|
|
+std::mutex mutex;
|
|
|
int lastId = 0;
|
|
|
|
|
|
void *getUserPointer(int id) {
|
|
|
+ std::lock_guard lock(mutex);
|
|
|
auto it = userPointerMap.find(id);
|
|
|
return it != userPointerMap.end() ? it->second : nullptr;
|
|
|
}
|
|
|
|
|
|
+shared_ptr<PeerConnection> getPeerConnection(int id) {
|
|
|
+ std::lock_guard lock(mutex);
|
|
|
+ auto it = peerConnectionMap.find(id);
|
|
|
+ return it != peerConnectionMap.end() ? it->second : nullptr;
|
|
|
+}
|
|
|
+
|
|
|
+shared_ptr<DataChannel> getDataChannel(int id) {
|
|
|
+ std::lock_guard lock(mutex);
|
|
|
+ auto it = dataChannelMap.find(id);
|
|
|
+ return it != dataChannelMap.end() ? it->second : nullptr;
|
|
|
+}
|
|
|
+
|
|
|
+int emplacePeerConnection(shared_ptr<PeerConnection> ptr) {
|
|
|
+ std::lock_guard lock(mutex);
|
|
|
+ int pc = ++lastId;
|
|
|
+ peerConnectionMap.emplace(std::make_pair(pc, ptr));
|
|
|
+ return pc;
|
|
|
+}
|
|
|
+
|
|
|
+int emplaceDataChannel(shared_ptr<DataChannel> ptr) {
|
|
|
+ std::lock_guard lock(mutex);
|
|
|
+ int dc = ++lastId;
|
|
|
+ dataChannelMap.emplace(std::make_pair(dc, ptr));
|
|
|
+ return dc;
|
|
|
+}
|
|
|
+
|
|
|
+bool erasePeerConnection(int pc) {
|
|
|
+ std::lock_guard lock(mutex);
|
|
|
+ if (peerConnectionMap.erase(pc) == 0)
|
|
|
+ return false;
|
|
|
+ userPointerMap.erase(pc);
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+bool eraseDataChannel(int dc) {
|
|
|
+ std::lock_guard lock(mutex);
|
|
|
+ if (dataChannelMap.erase(dc) == 0)
|
|
|
+ return false;
|
|
|
+ userPointerMap.erase(dc);
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
} // namespace
|
|
|
|
|
|
-void rtcInitLogger(rtc_log_level_t level) { InitLogger(static_cast<LogLevel>(level)); }
|
|
|
+void rtcInitLogger(rtcLogLevel level) { InitLogger(static_cast<LogLevel>(level)); }
|
|
|
+
|
|
|
+void rtcSetUserPointer(int i, void *ptr) {
|
|
|
+ if (ptr)
|
|
|
+ userPointerMap.insert(std::make_pair(i, ptr));
|
|
|
+ else
|
|
|
+ userPointerMap.erase(i);
|
|
|
+}
|
|
|
|
|
|
int rtcCreatePeerConnection(const char **iceServers, int iceServersCount) {
|
|
|
Configuration config;
|
|
|
for (int i = 0; i < iceServersCount; ++i) {
|
|
|
config.iceServers.emplace_back(IceServer(string(iceServers[i])));
|
|
|
}
|
|
|
- int pc = ++lastId;
|
|
|
- peerConnectionMap.emplace(std::make_pair(pc, std::make_shared<PeerConnection>(config)));
|
|
|
- return pc;
|
|
|
+ return emplacePeerConnection(std::make_shared<PeerConnection>(config));
|
|
|
}
|
|
|
|
|
|
-void rtcDeletePeerConnection(int pc) { peerConnectionMap.erase(pc); }
|
|
|
+int rtcDeletePeerConnection(int pc) { return erasePeerConnection(pc) ? 0 : -1; }
|
|
|
|
|
|
int rtcCreateDataChannel(int pc, const char *label) {
|
|
|
- auto it = peerConnectionMap.find(pc);
|
|
|
- if (it == peerConnectionMap.end())
|
|
|
- return 0;
|
|
|
- auto dataChannel = it->second->createDataChannel(string(label));
|
|
|
- int dc = ++lastId;
|
|
|
- dataChannelMap.emplace(std::make_pair(dc, dataChannel));
|
|
|
- return dc;
|
|
|
+ auto peerConnection = getPeerConnection(pc);
|
|
|
+ if (!peerConnection)
|
|
|
+ return -1;
|
|
|
+
|
|
|
+ return emplaceDataChannel(peerConnection->createDataChannel(string(label)));
|
|
|
}
|
|
|
|
|
|
-void rtcDeleteDataChannel(int dc) { dataChannelMap.erase(dc); }
|
|
|
+int rtcDeleteDataChannel(int dc) { return eraseDataChannel(dc) ? 0 : -1; }
|
|
|
|
|
|
-void rtcSetDataChannelCallback(int pc, void (*dataChannelCallback)(int, void *)) {
|
|
|
- auto it = peerConnectionMap.find(pc);
|
|
|
- if (it == peerConnectionMap.end())
|
|
|
- return;
|
|
|
+int rtcSetDataChannelCallback(int pc, dataChannelCallbackFunc cb) {
|
|
|
+ auto peerConnection = getPeerConnection(pc);
|
|
|
+ if (!peerConnection)
|
|
|
+ return -1;
|
|
|
|
|
|
- it->second->onDataChannel([pc, dataChannelCallback](std::shared_ptr<DataChannel> dataChannel) {
|
|
|
- int dc = ++lastId;
|
|
|
- dataChannelMap.emplace(std::make_pair(dc, dataChannel));
|
|
|
- dataChannelCallback(dc, getUserPointer(pc));
|
|
|
+ peerConnection->onDataChannel([pc, cb](std::shared_ptr<DataChannel> dataChannel) {
|
|
|
+ int dc = emplaceDataChannel(dataChannel);
|
|
|
+ cb(dc, getUserPointer(pc));
|
|
|
});
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
-void rtcSetLocalDescriptionCallback(int pc, void (*descriptionCallback)(const char *, const char *,
|
|
|
- void *)) {
|
|
|
- auto it = peerConnectionMap.find(pc);
|
|
|
- if (it == peerConnectionMap.end())
|
|
|
- return;
|
|
|
+int rtcSetLocalDescriptionCallback(int pc, descriptionCallbackFunc cb) {
|
|
|
+ auto peerConnection = getPeerConnection(pc);
|
|
|
+ if (!peerConnection)
|
|
|
+ return -1;
|
|
|
|
|
|
- it->second->onLocalDescription([pc, descriptionCallback](const Description &description) {
|
|
|
- descriptionCallback(string(description).c_str(), description.typeString().c_str(),
|
|
|
- getUserPointer(pc));
|
|
|
+ peerConnection->onLocalDescription([pc, cb](const Description &desc) {
|
|
|
+ cb(string(desc).c_str(), desc.typeString().c_str(), getUserPointer(pc));
|
|
|
});
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
-void rtcSetLocalCandidateCallback(int pc,
|
|
|
- void (*candidateCallback)(const char *, const char *, void *)) {
|
|
|
- auto it = peerConnectionMap.find(pc);
|
|
|
- if (it == peerConnectionMap.end())
|
|
|
- return;
|
|
|
+int rtcSetLocalCandidateCallback(int pc, candidateCallbackFunc cb) {
|
|
|
+ auto peerConnection = getPeerConnection(pc);
|
|
|
+ if (!peerConnection)
|
|
|
+ return -1;
|
|
|
|
|
|
- it->second->onLocalCandidate([pc, candidateCallback](const Candidate &candidate) {
|
|
|
- candidateCallback(candidate.candidate().c_str(), candidate.mid().c_str(),
|
|
|
- getUserPointer(pc));
|
|
|
+ peerConnection->onLocalCandidate([pc, cb](const Candidate &cand) {
|
|
|
+ cb(cand.candidate().c_str(), cand.mid().c_str(), getUserPointer(pc));
|
|
|
});
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
-void rtcSetStateChangeCallback(int pc, void (*stateCallback)(rtc_state_t state, void *)) {
|
|
|
- auto it = peerConnectionMap.find(pc);
|
|
|
- if (it == peerConnectionMap.end())
|
|
|
- return;
|
|
|
+int rtcSetStateChangeCallback(int pc, stateChangeCallbackFunc cb) {
|
|
|
+ auto peerConnection = getPeerConnection(pc);
|
|
|
+ if (!peerConnection)
|
|
|
+ return -1;
|
|
|
|
|
|
- it->second->onStateChange([pc, stateCallback](PeerConnection::State state) {
|
|
|
- stateCallback(static_cast<rtc_state_t>(state), getUserPointer(pc));
|
|
|
+ peerConnection->onStateChange([pc, cb](PeerConnection::State state) {
|
|
|
+ cb(static_cast<rtcState>(state), getUserPointer(pc));
|
|
|
});
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
-void rtcSetGatheringStateChangeCallback(int pc,
|
|
|
- void (*gatheringStateCallback)(rtc_gathering_state_t state,
|
|
|
- void *)) {
|
|
|
- auto it = peerConnectionMap.find(pc);
|
|
|
- if (it == peerConnectionMap.end())
|
|
|
- return;
|
|
|
+int rtcSetGatheringStateChangeCallback(int pc, gatheringStateCallbackFunc cb) {
|
|
|
+ auto peerConnection = getPeerConnection(pc);
|
|
|
+ if (!peerConnection)
|
|
|
+ return -1;
|
|
|
|
|
|
- it->second->onGatheringStateChange(
|
|
|
- [pc, gatheringStateCallback](PeerConnection::GatheringState state) {
|
|
|
- gatheringStateCallback(static_cast<rtc_gathering_state_t>(state), getUserPointer(pc));
|
|
|
- });
|
|
|
+ peerConnection->onGatheringStateChange([pc, cb](PeerConnection::GatheringState state) {
|
|
|
+ cb(static_cast<rtcGatheringState>(state), getUserPointer(pc));
|
|
|
+ });
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
-void rtcSetRemoteDescription(int pc, const char *sdp, const char *type) {
|
|
|
- auto it = peerConnectionMap.find(pc);
|
|
|
- if (it == peerConnectionMap.end())
|
|
|
- return;
|
|
|
+int rtcSetRemoteDescription(int pc, const char *sdp, const char *type) {
|
|
|
+ auto peerConnection = getPeerConnection(pc);
|
|
|
+ if (!peerConnection)
|
|
|
+ return -1;
|
|
|
|
|
|
- it->second->setRemoteDescription(Description(string(sdp), type ? string(type) : ""));
|
|
|
+ CATCH(peerConnection->setRemoteDescription({string(sdp), type ? string(type) : ""}));
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
-void rtcAddRemoteCandidate(int pc, const char *candidate, const char *mid) {
|
|
|
- auto it = peerConnectionMap.find(pc);
|
|
|
- if (it == peerConnectionMap.end())
|
|
|
- return;
|
|
|
+int rtcAddRemoteCandidate(int pc, const char *cand, const char *mid) {
|
|
|
+ auto peerConnection = getPeerConnection(pc);
|
|
|
+ if (!peerConnection)
|
|
|
+ return -1;
|
|
|
|
|
|
- it->second->addRemoteCandidate(Candidate(string(candidate), mid ? string(mid) : ""));
|
|
|
+ CATCH(peerConnection->addRemoteCandidate({string(cand), mid ? string(mid) : ""}))
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
int rtcGetDataChannelLabel(int dc, char *buffer, int size) {
|
|
|
- auto it = dataChannelMap.find(dc);
|
|
|
- if (it == dataChannelMap.end())
|
|
|
- return 0;
|
|
|
+ auto dataChannel = getDataChannel(dc);
|
|
|
+ if (!dataChannel)
|
|
|
+ return -1;
|
|
|
|
|
|
if (!size)
|
|
|
return 0;
|
|
|
|
|
|
- string label = it->second->label();
|
|
|
+ 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;
|
|
|
}
|
|
|
|
|
|
-void rtcSetOpenCallback(int dc, void (*openCallback)(void *)) {
|
|
|
- auto it = dataChannelMap.find(dc);
|
|
|
- if (it == dataChannelMap.end())
|
|
|
- return;
|
|
|
+int rtcSetOpenCallback(int dc, openCallbackFunc cb) {
|
|
|
+ auto dataChannel = getDataChannel(dc);
|
|
|
+ if (!dataChannel)
|
|
|
+ return -1;
|
|
|
|
|
|
- it->second->onOpen([dc, openCallback]() { openCallback(getUserPointer(dc)); });
|
|
|
+ dataChannel->onOpen([dc, cb]() { cb(getUserPointer(dc)); });
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
-void rtcSetErrorCallback(int dc, void (*errorCallback)(const char *, void *)) {
|
|
|
- auto it = dataChannelMap.find(dc);
|
|
|
- if (it == dataChannelMap.end())
|
|
|
- return;
|
|
|
+int rtcSetErrorCallback(int dc, errorCallbackFunc cb) {
|
|
|
+ auto dataChannel = getDataChannel(dc);
|
|
|
+ if (!dataChannel)
|
|
|
+ return -1;
|
|
|
|
|
|
- it->second->onError([dc, errorCallback](const string &error) {
|
|
|
- errorCallback(error.c_str(), getUserPointer(dc));
|
|
|
- });
|
|
|
+ dataChannel->onError([dc, cb](const string &error) { cb(error.c_str(), getUserPointer(dc)); });
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
-void rtcSetMessageCallback(int dc, void (*messageCallback)(const char *, int, void *)) {
|
|
|
- auto it = dataChannelMap.find(dc);
|
|
|
- if (it == dataChannelMap.end())
|
|
|
- return;
|
|
|
+int rtcSetMessageCallback(int dc, messageCallbackFunc cb) {
|
|
|
+ auto dataChannel = getDataChannel(dc);
|
|
|
+ if (!dataChannel)
|
|
|
+ return -1;
|
|
|
|
|
|
- it->second->onMessage(
|
|
|
- [dc, messageCallback](const binary &b) {
|
|
|
- messageCallback(reinterpret_cast<const char *>(b.data()), b.size(), getUserPointer(dc));
|
|
|
+ dataChannel->onMessage(
|
|
|
+ [dc, cb](const binary &b) {
|
|
|
+ cb(reinterpret_cast<const char *>(b.data()), b.size(), getUserPointer(dc));
|
|
|
},
|
|
|
- [dc, messageCallback](const string &s) {
|
|
|
- messageCallback(s.c_str(), -1, getUserPointer(dc));
|
|
|
- });
|
|
|
+ [dc, cb](const string &s) { cb(s.c_str(), -1, getUserPointer(dc)); });
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
int rtcSendMessage(int dc, const char *data, int size) {
|
|
|
- auto it = dataChannelMap.find(dc);
|
|
|
- if (it == dataChannelMap.end())
|
|
|
- return 0;
|
|
|
+ auto dataChannel = getDataChannel(dc);
|
|
|
+ if (!dataChannel)
|
|
|
+ return -1;
|
|
|
|
|
|
if (size >= 0) {
|
|
|
auto b = reinterpret_cast<const byte *>(data);
|
|
|
- it->second->send(b, size);
|
|
|
+ CATCH(dataChannel->send(b, size));
|
|
|
return size;
|
|
|
} else {
|
|
|
string s(data);
|
|
|
- it->second->send(s);
|
|
|
+ CATCH(dataChannel->send(s));
|
|
|
return s.size();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-void rtcSetUserPointer(int i, void *ptr) {
|
|
|
- if (ptr)
|
|
|
- userPointerMap.insert(std::make_pair(i, ptr));
|
|
|
- else
|
|
|
- userPointerMap.erase(i);
|
|
|
+int rtcGetBufferedAmount(int dc) {
|
|
|
+ auto dataChannel = getDataChannel(dc);
|
|
|
+ if (!dataChannel)
|
|
|
+ return -1;
|
|
|
+
|
|
|
+ CATCH(return int(dataChannel->bufferedAmount()));
|
|
|
+}
|
|
|
+
|
|
|
+int rtcSetBufferedAmountLowThreshold(int dc, int amount) {
|
|
|
+ auto dataChannel = getDataChannel(dc);
|
|
|
+ if (!dataChannel)
|
|
|
+ return -1;
|
|
|
+
|
|
|
+ CATCH(dataChannel->setBufferedAmountLowThreshold(size_t(amount)));
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int rtcSetBufferedAmountLowCallback(int dc, bufferedAmountLowCallbackFunc cb) {
|
|
|
+ auto dataChannel = getDataChannel(dc);
|
|
|
+ if (!dataChannel)
|
|
|
+ return -1;
|
|
|
+
|
|
|
+ dataChannel->onOpen([dc, cb]() { cb(getUserPointer(dc)); });
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int rtcGetAvailableAmount(int dc) {
|
|
|
+ auto dataChannel = getDataChannel(dc);
|
|
|
+ if (!dataChannel)
|
|
|
+ return -1;
|
|
|
+
|
|
|
+ CATCH(return int(dataChannel->availableAmount()));
|
|
|
+}
|
|
|
+
|
|
|
+int rtcSetAvailableCallback(int dc, availableCallbackFunc cb) {
|
|
|
+ auto dataChannel = getDataChannel(dc);
|
|
|
+ if (!dataChannel)
|
|
|
+ return -1;
|
|
|
+
|
|
|
+ dataChannel->onOpen([dc, cb]() { cb(getUserPointer(dc)); });
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int rtcReceiveMessage(int dc, char *buffer, int *size) {
|
|
|
+ auto dataChannel = getDataChannel(dc);
|
|
|
+ if (!dataChannel)
|
|
|
+ return -1;
|
|
|
+
|
|
|
+ if (!size)
|
|
|
+ return -1;
|
|
|
+
|
|
|
+ CATCH({
|
|
|
+ auto message = dataChannel->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()));
|
|
|
+ *size = -1;
|
|
|
+ if (len >= 0) {
|
|
|
+ std::copy(s.data(), s.data() + len, buffer);
|
|
|
+ buffer[len] = '\0';
|
|
|
+ }
|
|
|
+ return len + 1;
|
|
|
+ }},
|
|
|
+ *message);
|
|
|
+ });
|
|
|
}
|