/*************************************************************************/ /* WebRTCLibDataChannel.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ /* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ /* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ /* "Software"), to deal in the Software without restriction, including */ /* without limitation the rights to use, copy, modify, merge, publish, */ /* distribute, sublicense, and/or sell copies of the Software, and to */ /* permit persons to whom the Software is furnished to do so, subject to */ /* the following conditions: */ /* */ /* The above copyright notice and this permission notice shall be */ /* included in all copies or substantial portions of the Software. */ /* */ /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #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(); } int WebRTCLibDataChannel::get_buffered_amount() const { ERR_FAIL_COND_V(channel.get() == nullptr, 0); return channel->buffered_amount(); } 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; }