#include "rtc_bridge.h" #include #include #ifdef _WIN32 #include #include #else #include #endif static std::mutex *g_rtc_mutex = new std::mutex; static std::deque *g_rtc_events = new std::deque; static void rtc_push(RtcEvent &&ev) { std::lock_guard lock(*g_rtc_mutex); g_rtc_events->push_back(std::move(ev)); } bool runt_rtc_poll_event(RtcEvent &out) { std::lock_guard lock(*g_rtc_mutex); if (g_rtc_events->empty()) return false; out = std::move(g_rtc_events->front()); g_rtc_events->pop_front(); return true; } static void RTC_API rtc_description_cb(int pc, const char *sdp, const char *type, void *ptr) { RtcEvent ev; ev.type = RtcEventType::LocalDescription; ev.id = pc; ev.s1 = sdp != nullptr ? sdp : ""; ev.s2 = type != nullptr ? type : ""; rtc_push(std::move(ev)); } static void RTC_API rtc_candidate_cb(int pc, const char *cand, const char *mid, void *ptr) { RtcEvent ev; ev.type = RtcEventType::LocalCandidate; ev.id = pc; ev.s1 = cand != nullptr ? cand : ""; ev.s2 = mid != nullptr ? mid : ""; rtc_push(std::move(ev)); } static void RTC_API rtc_open_cb(int id, void *ptr); static void RTC_API rtc_closed_cb(int id, void *ptr); static void RTC_API rtc_error_cb(int id, const char *error, void *ptr); static void RTC_API rtc_message_cb(int id, const char *message, int size, void *ptr); static void RTC_API rtc_state_cb(int pc, rtcState state, void *ptr) { RtcEvent ev; ev.type = RtcEventType::StateChange; ev.id = pc; ev.arg = (int)state; rtc_push(std::move(ev)); } static void RTC_API rtc_gathering_cb(int pc, rtcGatheringState state, void *ptr) { RtcEvent ev; ev.type = RtcEventType::GatheringState; ev.id = pc; ev.arg = (int)state; rtc_push(std::move(ev)); } static void rtc_register_dc_callbacks(int dc) { rtcSetOpenCallback(dc, rtc_open_cb); rtcSetClosedCallback(dc, rtc_closed_cb); rtcSetErrorCallback(dc, rtc_error_cb); rtcSetMessageCallback(dc, rtc_message_cb); } static void RTC_API rtc_datachannel_cb(int pc, int dc, void *ptr) { rtc_register_dc_callbacks(dc); RtcEvent ev; ev.type = RtcEventType::DataChannel; ev.id = pc; ev.arg = dc; rtc_push(std::move(ev)); } static void RTC_API rtc_open_cb(int id, void *ptr) { RtcEvent ev; ev.type = RtcEventType::Open; ev.id = id; rtc_push(std::move(ev)); } static void RTC_API rtc_closed_cb(int id, void *ptr) { RtcEvent ev; ev.type = RtcEventType::Closed; ev.id = id; rtc_push(std::move(ev)); } static void RTC_API rtc_error_cb(int id, const char *error, void *ptr) { RtcEvent ev; ev.type = RtcEventType::Error; ev.id = id; ev.s1 = error != nullptr ? error : ""; rtc_push(std::move(ev)); } static void RTC_API rtc_message_cb(int id, const char *message, int size, void *ptr) { RtcEvent ev; ev.type = RtcEventType::Message; ev.id = id; if (size < 0) { ev.isString = true; ev.s1 = message != nullptr ? message : ""; } else { ev.data.assign(message, message + size); } rtc_push(std::move(ev)); } int runt_rtc_init() { return rtcPreload() ? 0 : -1; } void runt_rtc_cleanup() { rtcCleanup(); } int runt_rtc_create_peer_connection(const std::vector &iceServers) { rtcConfiguration conf; memset(&conf, 0, sizeof(conf)); std::vector servers(iceServers.size()); for (size_t i = 0; i < iceServers.size(); i++) { servers[i] = iceServers[i].c_str(); } conf.iceServers = servers.data(); conf.iceServersCount = (int)servers.size(); int pc = rtcCreatePeerConnection(&conf); if (pc < 0) return pc; rtcSetLocalDescriptionCallback(pc, rtc_description_cb); rtcSetLocalCandidateCallback(pc, rtc_candidate_cb); rtcSetStateChangeCallback(pc, rtc_state_cb); rtcSetGatheringStateChangeCallback(pc, rtc_gathering_cb); rtcSetDataChannelCallback(pc, rtc_datachannel_cb); return pc; } void runt_rtc_close_peer_connection(int pc) { rtcClosePeerConnection(pc); } void runt_rtc_delete_peer_connection(int pc) { rtcDeletePeerConnection(pc); } void runt_rtc_set_local_description(int pc, const char *type) { rtcSetLocalDescription(pc, type); } int runt_rtc_set_remote_description(int pc, const char *sdp, const char *type) { return rtcSetRemoteDescription(pc, sdp, type); } int runt_rtc_add_remote_candidate(int pc, const char *cand, const char *mid) { return rtcAddRemoteCandidate(pc, cand, mid); } std::string runt_rtc_get_local_description(int pc) { int size = rtcGetLocalDescription(pc, nullptr, 0); if (size <= 0) return ""; std::string buf(size, '\0'); rtcGetLocalDescription(pc, buf.data(), size); return std::string(buf.data(), strnlen(buf.data(), buf.size())); } std::string runt_rtc_get_local_description_type(int pc) { char buf[64]; int size = rtcGetLocalDescriptionType(pc, buf, sizeof(buf)); if (size <= 0) return ""; return std::string(buf, strnlen(buf, sizeof(buf))); } int runt_rtc_create_data_channel(int pc, const char *label, bool unordered, int maxRetransmits) { rtcDataChannelInit init; memset(&init, 0, sizeof(init)); init.reliability.unordered = unordered; init.reliability.unreliable = maxRetransmits >= 0; init.reliability.maxRetransmits = maxRetransmits >= 0 ? (unsigned int)maxRetransmits : 0; int dc = rtcCreateDataChannelEx(pc, label, &init); if (dc < 0) return dc; rtc_register_dc_callbacks(dc); return dc; } void runt_rtc_delete_data_channel(int dc) { rtcDeleteDataChannel(dc); } int runt_rtc_send_message(int id, const char *data, int size) { return rtcSendMessage(id, data, size); } void runt_rtc_close(int id) { rtcClose(id); } void runt_rtc_delete(int id) { rtcDelete(id); } bool runt_rtc_is_open(int id) { return rtcIsOpen(id); } int runt_rtc_get_buffered_amount(int id) { return rtcGetBufferedAmount(id); } bool runt_rtc_random_bytes(char *out, int len) { #ifdef _WIN32 return BCryptGenRandom(nullptr, reinterpret_cast(out), static_cast(len), BCRYPT_USE_SYSTEM_PREFERRED_RNG) == 0; #else FILE *f = fopen("/dev/urandom", "rb"); if (f == nullptr) return false; size_t n = fread(out, 1, static_cast(len), f); fclose(f); return n == static_cast(len); #endif }