#include "WebRTCLibDataChannel.hpp" #include "GDNativeLibrary.hpp" #include "NativeScript.hpp" 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(), buffer.data.size()); } void WebRTCLibDataChannel::ChannelObserver::OnStateChange() { } void WebRTCLibDataChannel::ChannelObserver::OnBufferedAmountChange(uint64_t previous_amount) { } // DataChannel WebRTCLibDataChannel *WebRTCLibDataChannel::new_data_channel(rtc::scoped_refptr p_channel) { // Invalid channel result in NULL return ERR_FAIL_COND_V(p_channel.get() == nullptr, NULL); // 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_object *)godot::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(out); tmp->bind_channel(p_channel); return tmp; } void WebRTCLibDataChannel::bind_channel(rtc::scoped_refptr p_channel) { ERR_FAIL_COND(p_channel.get() == nullptr); 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) { mutex->lock(); godot::PoolByteArray packet; packet.resize(size); { godot::PoolByteArray::Write w = packet.write(); memcpy(w.ptr(), data, size); } packet_queue.push(packet); mutex->unlock(); } void WebRTCLibDataChannel::set_write_mode(godot_int mode) { } godot_int WebRTCLibDataChannel::get_write_mode() const { return 0; } bool WebRTCLibDataChannel::was_string_packet() const { return false; } WebRTCLibDataChannel::ChannelState WebRTCLibDataChannel::get_ready_state() const { ERR_FAIL_COND_V(channel.get() == nullptr, STATE_CLOSED); return (ChannelState)channel->state(); } const char *WebRTCLibDataChannel::get_label() const { ERR_FAIL_COND_V(channel.get() == nullptr, ""); return label.c_str(); } bool WebRTCLibDataChannel::is_ordered() const { ERR_FAIL_COND_V(channel.get() == nullptr, false); return channel->ordered(); } int WebRTCLibDataChannel::get_id() const { ERR_FAIL_COND_V(channel.get() == nullptr, -1); return channel->id(); } int WebRTCLibDataChannel::get_max_packet_life_time() const { ERR_FAIL_COND_V(channel.get() == nullptr, 0); return channel->maxRetransmitTime(); } int WebRTCLibDataChannel::get_max_retransmits() const { ERR_FAIL_COND_V(channel.get() == nullptr, 0); return channel->maxRetransmits(); } const char *WebRTCLibDataChannel::get_protocol() const { ERR_FAIL_COND_V(channel.get() == nullptr, ""); return protocol.c_str(); } bool WebRTCLibDataChannel::is_negotiated() const { ERR_FAIL_COND_V(channel.get() == nullptr, false); return channel->negotiated(); } godot_error WebRTCLibDataChannel::poll() { return GODOT_OK; } void WebRTCLibDataChannel::close() { if(channel.get() != nullptr) { channel->Close(); channel->UnregisterObserver(); } } godot_error WebRTCLibDataChannel::get_packet(const uint8_t **r_buffer, int *r_len) { ERR_FAIL_COND_V(packet_queue.empty(), GODOT_ERR_UNAVAILABLE); mutex->lock(); // Update current packet and pop queue 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(); mutex->unlock(); return GODOT_OK; } 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; } godot_int WebRTCLibDataChannel::get_available_packet_count() const { return packet_queue.size(); } godot_int WebRTCLibDataChannel::get_max_packet_size() const { return 1200; } void WebRTCLibDataChannel::_register_methods() { } void WebRTCLibDataChannel::_init() { register_interface(&interface); } WebRTCLibDataChannel::WebRTCLibDataChannel() : observer(this) { mutex = new std::mutex; } WebRTCLibDataChannel::~WebRTCLibDataChannel() { close(); if (_owner) { register_interface(NULL); } delete mutex; }