summaryrefslogtreecommitdiff
path: root/src/WebRTCLibDataChannel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/WebRTCLibDataChannel.cpp')
-rw-r--r--src/WebRTCLibDataChannel.cpp232
1 files changed, 124 insertions, 108 deletions
diff --git a/src/WebRTCLibDataChannel.cpp b/src/WebRTCLibDataChannel.cpp
index bab9c79..5c4ad5d 100644
--- a/src/WebRTCLibDataChannel.cpp
+++ b/src/WebRTCLibDataChannel.cpp
@@ -30,138 +30,155 @@
#include "WebRTCLibDataChannel.hpp"
+#ifdef GDNATIVE_WEBRTC
#include "GDNativeLibrary.hpp"
#include "NativeScript.hpp"
+#define ERR_UNAVAILABLE GODOT_ERR_UNAVAILABLE
+#define FAILED GODOT_FAILED
+#define ERR_INVALID_PARAMETER GODOT_ERR_INVALID_PARAMETER
+#define OK GODOT_OK
+#endif
-using namespace godot_webrtc;
-
-// Channel observer
-WebRTCLibDataChannel::ChannelObserver::ChannelObserver(WebRTCLibDataChannel *parent) {
- this->parent = parent;
-}
-
-void WebRTCLibDataChannel::ChannelObserver::OnMessage(const webrtc::DataBuffer &buffer) {
- parent->queue_packet(buffer.data.data<uint8_t>(), buffer.data.size());
-}
-
-void WebRTCLibDataChannel::ChannelObserver::OnStateChange() {
-}
+#include <stdio.h>
+#include <string.h>
+#include <cstring>
-void WebRTCLibDataChannel::ChannelObserver::OnBufferedAmountChange(uint64_t previous_amount) {
-}
+using namespace godot;
+using namespace godot_webrtc;
// DataChannel
-WebRTCLibDataChannel *WebRTCLibDataChannel::new_data_channel(rtc::scoped_refptr<webrtc::DataChannelInterface> p_channel) {
+WebRTCLibDataChannel *WebRTCLibDataChannel::new_data_channel(std::shared_ptr<rtc::DataChannel> p_channel, bool p_negotiated) {
// Invalid channel result in NULL return
- ERR_FAIL_COND_V(p_channel.get() == nullptr, NULL);
+ ERR_FAIL_COND_V(!p_channel, nullptr);
+#ifdef GDNATIVE_WEBRTC
// Instance a WebRTCDataChannelGDNative object
- godot::WebRTCDataChannelGDNative *out = godot::WebRTCDataChannelGDNative::_new();
- // Set our implementation as it's script
- godot::NativeScript *script = godot::NativeScript::_new();
- script->set_library(godot::detail::get_wrapper<godot::GDNativeLibrary>((godot_object *)godot::gdnlib));
+ WebRTCDataChannelGDNative *native = WebRTCDataChannelGDNative::_new();
+ // Set our implementation as its script
+ NativeScript *script = NativeScript::_new();
+ script->set_library(detail::get_wrapper<GDNativeLibrary>((godot_object *)gdnlib));
script->set_class_name("WebRTCLibDataChannel");
- out->set_script(script);
-
- // Bind the data channel to the ScriptInstance userdata (our script)
- WebRTCLibDataChannel *tmp = out->cast_to<WebRTCLibDataChannel>(out);
- tmp->bind_channel(p_channel);
-
- return tmp;
+ native->set_script(script);
+ WebRTCLibDataChannel *out = native->cast_to<WebRTCLibDataChannel>(native);
+#else
+ WebRTCLibDataChannel *out = memnew(WebRTCLibDataChannel);
+#endif
+ // Bind the library data channel to our object.
+ out->bind_channel(p_channel, p_negotiated);
+ return out;
}
-void WebRTCLibDataChannel::bind_channel(rtc::scoped_refptr<webrtc::DataChannelInterface> p_channel) {
- ERR_FAIL_COND(p_channel.get() == nullptr);
+void WebRTCLibDataChannel::bind_channel(std::shared_ptr<rtc::DataChannel> p_channel, bool p_negotiated) {
+ ERR_FAIL_COND(!p_channel);
channel = p_channel;
- label = p_channel->label();
- protocol = p_channel->protocol();
- channel->RegisterObserver(&observer);
-}
-
-void WebRTCLibDataChannel::queue_packet(const uint8_t *data, uint32_t size) {
+ negotiated = p_negotiated;
+
+ // Binding this should be fine as long as we call close when going out of scope.
+ p_channel->onMessage([this](auto message) {
+ if (std::holds_alternative<rtc::string>(message)) {
+ rtc::string str = std::get<rtc::string>(message);
+ queue_packet(reinterpret_cast<const uint8_t *>(str.c_str()), str.size(), true);
+ } else if (std::holds_alternative<rtc::binary>(message)) {
+ rtc::binary bin = std::get<rtc::binary>(message);
+ queue_packet(reinterpret_cast<const uint8_t *>(&bin[0]), bin.size(), false);
+ } else {
+ ERR_PRINT("Message parsing bug. Unknown message type.");
+ }
+ });
+ p_channel->onOpen([this]() {
+ channel_state = STATE_OPEN;
+ });
+ p_channel->onClosed([this]() {
+ channel_state = STATE_CLOSED;
+ });
+ p_channel->onError([](auto error) {
+ ERR_PRINT("Channel Error: " + String(std::string(error).c_str()));
+ });
+}
+
+void WebRTCLibDataChannel::queue_packet(const uint8_t *data, uint32_t size, bool p_is_string) {
mutex->lock();
- godot::PoolByteArray packet;
+ std::vector<uint8_t> packet;
packet.resize(size);
- {
- godot::PoolByteArray::Write w = packet.write();
- memcpy(w.ptr(), data, size);
- }
- packet_queue.push(packet);
+ memcpy(&packet[0], data, size);
+ packet_queue.push(QueuedPacket(packet, p_is_string));
mutex->unlock();
}
-void WebRTCLibDataChannel::set_write_mode(godot_int mode) {
+void WebRTCLibDataChannel::_set_write_mode(int64_t p_mode) {
+ ERR_FAIL_COND(p_mode != WRITE_MODE_TEXT && p_mode != WRITE_MODE_BINARY);
+ write_mode = (WriteMode)p_mode;
}
-godot_int WebRTCLibDataChannel::get_write_mode() const {
- return 0;
+int64_t WebRTCLibDataChannel::_get_write_mode() const {
+ return write_mode;
}
-bool WebRTCLibDataChannel::was_string_packet() const {
- return false;
+bool WebRTCLibDataChannel::_was_string_packet() const {
+ return current_packet.second;
}
-WebRTCLibDataChannel::ChannelState WebRTCLibDataChannel::get_ready_state() const {
- ERR_FAIL_COND_V(channel.get() == nullptr, STATE_CLOSED);
- return (ChannelState)channel->state();
+int64_t WebRTCLibDataChannel::_get_ready_state() const {
+ ERR_FAIL_COND_V(!channel, STATE_CLOSED);
+ return channel_state;
}
-const char *WebRTCLibDataChannel::get_label() const {
- ERR_FAIL_COND_V(channel.get() == nullptr, "");
- return label.c_str();
+String WebRTCLibDataChannel::_get_label() const {
+ ERR_FAIL_COND_V(!channel, "");
+ return channel->label().c_str();
}
-bool WebRTCLibDataChannel::is_ordered() const {
- ERR_FAIL_COND_V(channel.get() == nullptr, false);
- return channel->ordered();
+bool WebRTCLibDataChannel::_is_ordered() const {
+ ERR_FAIL_COND_V(!channel, false);
+ return channel->reliability().unordered == false;
}
-int WebRTCLibDataChannel::get_id() const {
- ERR_FAIL_COND_V(channel.get() == nullptr, -1);
- return channel->id();
+int64_t WebRTCLibDataChannel::_get_id() const {
+ ERR_FAIL_COND_V(!channel, -1);
+ return channel->id().value_or(-1);
}
-int WebRTCLibDataChannel::get_max_packet_life_time() const {
- ERR_FAIL_COND_V(channel.get() == nullptr, 0);
- return channel->maxRetransmitTime();
+int64_t WebRTCLibDataChannel::_get_max_packet_life_time() const {
+ ERR_FAIL_COND_V(!channel, 0);
+ return channel->reliability().type == rtc::Reliability::Type::Timed ? std::get<std::chrono::milliseconds>(channel->reliability().rexmit).count() : -1;
}
-int WebRTCLibDataChannel::get_max_retransmits() const {
- ERR_FAIL_COND_V(channel.get() == nullptr, 0);
- return channel->maxRetransmits();
+int64_t WebRTCLibDataChannel::_get_max_retransmits() const {
+ ERR_FAIL_COND_V(!channel, 0);
+ return channel->reliability().type == rtc::Reliability::Type::Rexmit ? std::get<int>(channel->reliability().rexmit) : -1;
}
-const char *WebRTCLibDataChannel::get_protocol() const {
- ERR_FAIL_COND_V(channel.get() == nullptr, "");
- return protocol.c_str();
+String WebRTCLibDataChannel::_get_protocol() const {
+ ERR_FAIL_COND_V(!channel, "");
+ return channel->protocol().c_str();
}
-bool WebRTCLibDataChannel::is_negotiated() const {
- ERR_FAIL_COND_V(channel.get() == nullptr, false);
- return channel->negotiated();
+bool WebRTCLibDataChannel::_is_negotiated() const {
+ ERR_FAIL_COND_V(!channel, false);
+ return negotiated;
}
-int WebRTCLibDataChannel::get_buffered_amount() const {
- ERR_FAIL_COND_V(channel.get() == nullptr, 0);
- return channel->buffered_amount();
+int64_t WebRTCLibDataChannel::_get_buffered_amount() const {
+ ERR_FAIL_COND_V(!channel, 0);
+ return channel->bufferedAmount();
}
-godot_error WebRTCLibDataChannel::poll() {
- return GODOT_OK;
+int64_t WebRTCLibDataChannel::_poll() {
+ return OK;
}
-void WebRTCLibDataChannel::close() {
- if (channel.get() != nullptr) {
- channel->Close();
- channel->UnregisterObserver();
+void WebRTCLibDataChannel::_close() try {
+ if (channel) {
+ channel->close();
}
+} catch (...) {
}
-godot_error WebRTCLibDataChannel::get_packet(const uint8_t **r_buffer, int *r_len) {
- ERR_FAIL_COND_V(packet_queue.empty(), GODOT_ERR_UNAVAILABLE);
+int64_t WebRTCLibDataChannel::_get_packet(const uint8_t **r_buffer, int32_t *r_len) {
+ ERR_FAIL_COND_V(packet_queue.empty(), ERR_UNAVAILABLE);
mutex->lock();
@@ -169,47 +186,46 @@ godot_error WebRTCLibDataChannel::get_packet(const uint8_t **r_buffer, int *r_le
current_packet = packet_queue.front();
packet_queue.pop();
// Set out buffer and size (buffer will be gone at next get_packet or close)
- *r_buffer = current_packet.read().ptr();
- *r_len = current_packet.size();
+ *r_buffer = &current_packet.first[0];
+ *r_len = current_packet.first.size();
mutex->unlock();
- return GODOT_OK;
+ return 0;
}
-godot_error WebRTCLibDataChannel::put_packet(const uint8_t *p_buffer, int p_len) {
- ERR_FAIL_COND_V(channel.get() == nullptr, GODOT_ERR_UNAVAILABLE);
-
- webrtc::DataBuffer webrtc_buffer(rtc::CopyOnWriteBuffer(p_buffer, p_len), true);
- ERR_FAIL_COND_V(!channel->Send(webrtc_buffer), GODOT_FAILED);
-
- return GODOT_OK;
+int64_t WebRTCLibDataChannel::_put_packet(const uint8_t *p_buffer, int64_t p_len) try {
+ ERR_FAIL_COND_V(!channel, FAILED);
+ ERR_FAIL_COND_V(channel->isClosed(), FAILED);
+ if (write_mode == WRITE_MODE_TEXT) {
+ std::string str(p_len, '\x00');
+ std::strncpy(str.data(), (const char *)p_buffer, p_len);
+ channel->send(str);
+ } else if (write_mode == WRITE_MODE_BINARY) {
+ channel->send(reinterpret_cast<const std::byte *>(p_buffer), p_len);
+ } else {
+ ERR_FAIL_V(ERR_INVALID_PARAMETER);
+ }
+ return OK;
+} catch (const std::exception &e) {
+ ERR_PRINT(e.what());
+ ERR_FAIL_V(FAILED);
}
-godot_int WebRTCLibDataChannel::get_available_packet_count() const {
+int64_t WebRTCLibDataChannel::_get_available_packet_count() const {
return packet_queue.size();
}
-godot_int WebRTCLibDataChannel::get_max_packet_size() const {
- return 1200;
-}
-
-void WebRTCLibDataChannel::_register_methods() {
+int64_t WebRTCLibDataChannel::_get_max_packet_size() const {
+ return 16384; // See RFC-8831 section 6.6: https://datatracker.ietf.org/doc/rfc8831/
}
-void WebRTCLibDataChannel::_init() {
- register_interface(&interface);
-}
-
-WebRTCLibDataChannel::WebRTCLibDataChannel() :
- observer(this) {
+WebRTCLibDataChannel::WebRTCLibDataChannel() {
mutex = new std::mutex;
}
WebRTCLibDataChannel::~WebRTCLibDataChannel() {
- close();
- if (_owner) {
- register_interface(NULL);
- }
+ _close();
+ channel = nullptr;
delete mutex;
}