diff options
Diffstat (limited to 'modules/webrtc')
-rw-r--r-- | modules/webrtc/SCsub | 16 | ||||
-rw-r--r-- | modules/webrtc/config.py | 13 | ||||
-rw-r--r-- | modules/webrtc/register_types.cpp | 55 | ||||
-rw-r--r-- | modules/webrtc/register_types.h | 32 | ||||
-rw-r--r-- | modules/webrtc/webrtc_peer.cpp | 81 | ||||
-rw-r--r-- | modules/webrtc/webrtc_peer.h | 86 | ||||
-rw-r--r-- | modules/webrtc/webrtc_peer_gdnative.cpp | 114 | ||||
-rw-r--r-- | modules/webrtc/webrtc_peer_gdnative.h | 78 | ||||
-rw-r--r-- | modules/webrtc/webrtc_peer_js.cpp | 455 | ||||
-rw-r--r-- | modules/webrtc/webrtc_peer_js.h | 88 |
10 files changed, 1018 insertions, 0 deletions
diff --git a/modules/webrtc/SCsub b/modules/webrtc/SCsub new file mode 100644 index 0000000000..446bd530c2 --- /dev/null +++ b/modules/webrtc/SCsub @@ -0,0 +1,16 @@ +#!/usr/bin/env python + +Import('env') +Import('env_modules') + +# Thirdparty source files + +env_webrtc = env_modules.Clone() +use_gdnative = env_webrtc["module_gdnative_enabled"] + +if use_gdnative: # GDNative is retained in Javascript for export compatibility + env_webrtc.Append(CPPDEFINES=['WEBRTC_GDNATIVE_ENABLED']) + gdnative_includes = ["#modules/gdnative/include/"] + env_webrtc.Append(CPPPATH=gdnative_includes) + +env_webrtc.add_source_files(env.modules_sources, "*.cpp") diff --git a/modules/webrtc/config.py b/modules/webrtc/config.py new file mode 100644 index 0000000000..5ed245bad2 --- /dev/null +++ b/modules/webrtc/config.py @@ -0,0 +1,13 @@ +def can_build(env, platform): + return True + +def configure(env): + pass + +def get_doc_classes(): + return [ + "WebRTCPeer" + ] + +def get_doc_path(): + return "doc_classes" diff --git a/modules/webrtc/register_types.cpp b/modules/webrtc/register_types.cpp new file mode 100644 index 0000000000..ee7a766bd9 --- /dev/null +++ b/modules/webrtc/register_types.cpp @@ -0,0 +1,55 @@ +/*************************************************************************/ +/* register_types.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 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 "register_types.h" +#include "webrtc_peer.h" + +#ifdef JAVASCRIPT_ENABLED +#include "emscripten.h" +#include "webrtc_peer_js.h" +#endif +#ifdef WEBRTC_GDNATIVE_ENABLED +#include "webrtc_peer_gdnative.h" +#endif + +void register_webrtc_types() { +#ifdef JAVASCRIPT_ENABLED + WebRTCPeerJS::make_default(); +#elif defined(WEBRTC_GDNATIVE_ENABLED) + WebRTCPeerGDNative::make_default(); +#endif + + ClassDB::register_custom_instance_class<WebRTCPeer>(); +#ifdef WEBRTC_GDNATIVE_ENABLED + ClassDB::register_class<WebRTCPeerGDNative>(); +#endif +} + +void unregister_webrtc_types() {} diff --git a/modules/webrtc/register_types.h b/modules/webrtc/register_types.h new file mode 100644 index 0000000000..18a5dcc5aa --- /dev/null +++ b/modules/webrtc/register_types.h @@ -0,0 +1,32 @@ +/*************************************************************************/ +/* register_types.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 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. */ +/*************************************************************************/ + +void register_webrtc_types(); +void unregister_webrtc_types(); diff --git a/modules/webrtc/webrtc_peer.cpp b/modules/webrtc/webrtc_peer.cpp new file mode 100644 index 0000000000..30c4505df9 --- /dev/null +++ b/modules/webrtc/webrtc_peer.cpp @@ -0,0 +1,81 @@ +/*************************************************************************/ +/* webrtc_peer.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 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 "webrtc_peer.h" + +WebRTCPeer *(*WebRTCPeer::_create)() = NULL; + +Ref<WebRTCPeer> WebRTCPeer::create_ref() { + + if (!_create) + return Ref<WebRTCPeer>(); + return Ref<WebRTCPeer>(_create()); +} + +WebRTCPeer *WebRTCPeer::create() { + + if (!_create) + return NULL; + return _create(); +} + +void WebRTCPeer::_bind_methods() { + ClassDB::bind_method(D_METHOD("create_offer"), &WebRTCPeer::create_offer); + ClassDB::bind_method(D_METHOD("set_local_description", "type", "sdp"), &WebRTCPeer::set_local_description); + ClassDB::bind_method(D_METHOD("set_remote_description", "type", "sdp"), &WebRTCPeer::set_remote_description); + ClassDB::bind_method(D_METHOD("poll"), &WebRTCPeer::poll); + ClassDB::bind_method(D_METHOD("add_ice_candidate", "media", "index", "name"), &WebRTCPeer::add_ice_candidate); + + ClassDB::bind_method(D_METHOD("was_string_packet"), &WebRTCPeer::was_string_packet); + ClassDB::bind_method(D_METHOD("set_write_mode", "write_mode"), &WebRTCPeer::set_write_mode); + ClassDB::bind_method(D_METHOD("get_write_mode"), &WebRTCPeer::get_write_mode); + ClassDB::bind_method(D_METHOD("get_connection_state"), &WebRTCPeer::get_connection_state); + + ADD_SIGNAL(MethodInfo("offer_created", PropertyInfo(Variant::STRING, "type"), PropertyInfo(Variant::STRING, "sdp"))); + ADD_SIGNAL(MethodInfo("new_ice_candidate", PropertyInfo(Variant::STRING, "media"), PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::STRING, "name"))); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "write_mode", PROPERTY_HINT_ENUM), "set_write_mode", "get_write_mode"); + + BIND_ENUM_CONSTANT(WRITE_MODE_TEXT); + BIND_ENUM_CONSTANT(WRITE_MODE_BINARY); + + BIND_ENUM_CONSTANT(STATE_NEW); + BIND_ENUM_CONSTANT(STATE_CONNECTING); + BIND_ENUM_CONSTANT(STATE_CONNECTED); + BIND_ENUM_CONSTANT(STATE_DISCONNECTED); + BIND_ENUM_CONSTANT(STATE_FAILED); + BIND_ENUM_CONSTANT(STATE_CLOSED); +} + +WebRTCPeer::WebRTCPeer() { +} + +WebRTCPeer::~WebRTCPeer() { +} diff --git a/modules/webrtc/webrtc_peer.h b/modules/webrtc/webrtc_peer.h new file mode 100644 index 0000000000..e141c14655 --- /dev/null +++ b/modules/webrtc/webrtc_peer.h @@ -0,0 +1,86 @@ +/*************************************************************************/ +/* webrtc_peer.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 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. */ +/*************************************************************************/ + +#ifndef WEBRTC_PEER_H +#define WEBRTC_PEER_H + +#include "core/io/packet_peer.h" + +class WebRTCPeer : public PacketPeer { + GDCLASS(WebRTCPeer, PacketPeer); + +public: + enum WriteMode { + WRITE_MODE_TEXT, + WRITE_MODE_BINARY, + }; + + enum ConnectionState { + STATE_NEW, + STATE_CONNECTING, + STATE_CONNECTED, + STATE_DISCONNECTED, + STATE_FAILED, + STATE_CLOSED + }; + +protected: + static void _bind_methods(); + static WebRTCPeer *(*_create)(); + +public: + virtual void set_write_mode(WriteMode mode) = 0; + virtual WriteMode get_write_mode() const = 0; + virtual bool was_string_packet() const = 0; + virtual ConnectionState get_connection_state() const = 0; + + virtual Error create_offer() = 0; + virtual Error set_remote_description(String type, String sdp) = 0; + virtual Error set_local_description(String type, String sdp) = 0; + virtual Error add_ice_candidate(String sdpMidName, int sdpMlineIndexName, String sdpName) = 0; + virtual Error poll() = 0; + + /** Inherited from PacketPeer: **/ + virtual int get_available_packet_count() const = 0; + virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size) = 0; ///< buffer is GONE after next get_packet + virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size) = 0; + + virtual int get_max_packet_size() const = 0; + + static Ref<WebRTCPeer> create_ref(); + static WebRTCPeer *create(); + + WebRTCPeer(); + ~WebRTCPeer(); +}; + +VARIANT_ENUM_CAST(WebRTCPeer::WriteMode); +VARIANT_ENUM_CAST(WebRTCPeer::ConnectionState); +#endif // WEBRTC_PEER_H diff --git a/modules/webrtc/webrtc_peer_gdnative.cpp b/modules/webrtc/webrtc_peer_gdnative.cpp new file mode 100644 index 0000000000..f782944980 --- /dev/null +++ b/modules/webrtc/webrtc_peer_gdnative.cpp @@ -0,0 +1,114 @@ +/*************************************************************************/ +/* webrtc_peer_gdnative.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 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. */ +/*************************************************************************/ + +#ifdef WEBRTC_GDNATIVE_ENABLED + +#include "webrtc_peer_gdnative.h" + +void WebRTCPeerGDNative::_bind_methods() { +} + +WebRTCPeerGDNative::WebRTCPeerGDNative() { + interface = NULL; +} + +WebRTCPeerGDNative::~WebRTCPeerGDNative() { +} + +Error WebRTCPeerGDNative::create_offer() { + ERR_FAIL_COND_V(interface == NULL, ERR_UNCONFIGURED); + return (Error)interface->create_offer(interface->data); +} + +Error WebRTCPeerGDNative::set_local_description(String p_type, String p_sdp) { + ERR_FAIL_COND_V(interface == NULL, ERR_UNCONFIGURED); + return (Error)interface->set_local_description(interface->data, p_type.utf8().get_data(), p_sdp.utf8().get_data()); +} + +Error WebRTCPeerGDNative::set_remote_description(String p_type, String p_sdp) { + ERR_FAIL_COND_V(interface == NULL, ERR_UNCONFIGURED); + return (Error)interface->set_remote_description(interface->data, p_type.utf8().get_data(), p_sdp.utf8().get_data()); +} + +Error WebRTCPeerGDNative::add_ice_candidate(String sdpMidName, int sdpMlineIndexName, String sdpName) { + ERR_FAIL_COND_V(interface == NULL, ERR_UNCONFIGURED); + return (Error)interface->add_ice_candidate(interface->data, sdpMidName.utf8().get_data(), sdpMlineIndexName, sdpName.utf8().get_data()); +} + +Error WebRTCPeerGDNative::poll() { + ERR_FAIL_COND_V(interface == NULL, ERR_UNCONFIGURED); + return (Error)interface->poll(interface->data); +} + +void WebRTCPeerGDNative::set_write_mode(WriteMode p_mode) { + ERR_FAIL_COND(interface == NULL); + interface->set_write_mode(interface->data, p_mode); +} + +WebRTCPeer::WriteMode WebRTCPeerGDNative::get_write_mode() const { + ERR_FAIL_COND_V(interface == NULL, WRITE_MODE_BINARY); + return (WriteMode)interface->get_write_mode(interface->data); +} + +bool WebRTCPeerGDNative::was_string_packet() const { + ERR_FAIL_COND_V(interface == NULL, false); + return interface->was_string_packet(interface->data); +} + +WebRTCPeer::ConnectionState WebRTCPeerGDNative::get_connection_state() const { + ERR_FAIL_COND_V(interface == NULL, STATE_DISCONNECTED); + return STATE_DISCONNECTED; +} + +Error WebRTCPeerGDNative::get_packet(const uint8_t **r_buffer, int &r_buffer_size) { + ERR_FAIL_COND_V(interface == NULL, ERR_UNCONFIGURED); + return (Error)interface->get_packet(interface->data, r_buffer, &r_buffer_size); +} + +Error WebRTCPeerGDNative::put_packet(const uint8_t *p_buffer, int p_buffer_size) { + ERR_FAIL_COND_V(interface == NULL, ERR_UNCONFIGURED); + return (Error)interface->put_packet(interface->data, p_buffer, p_buffer_size); +} + +int WebRTCPeerGDNative::get_max_packet_size() const { + ERR_FAIL_COND_V(interface == NULL, 0); + return interface->get_max_packet_size(interface->data); +} + +int WebRTCPeerGDNative::get_available_packet_count() const { + ERR_FAIL_COND_V(interface == NULL, 0); + return interface->get_available_packet_count(interface->data); +} + +void WebRTCPeerGDNative::set_native_webrtc_peer(const godot_net_webrtc_peer *p_impl) { + interface = p_impl; +} + +#endif // WEBRTC_GDNATIVE_ENABLED diff --git a/modules/webrtc/webrtc_peer_gdnative.h b/modules/webrtc/webrtc_peer_gdnative.h new file mode 100644 index 0000000000..6786cec8ea --- /dev/null +++ b/modules/webrtc/webrtc_peer_gdnative.h @@ -0,0 +1,78 @@ +/*************************************************************************/ +/* webrtc_peer_gdnative.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 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. */ +/*************************************************************************/ + +#ifdef WEBRTC_GDNATIVE_ENABLED + +#ifndef WEBRTC_PEER_GDNATIVE_H +#define WEBRTC_PEER_GDNATIVE_H + +#include "modules/gdnative/include/net/godot_net.h" +#include "webrtc_peer.h" + +class WebRTCPeerGDNative : public WebRTCPeer { + GDCLASS(WebRTCPeerGDNative, WebRTCPeer); + +protected: + static void _bind_methods(); + +private: + const godot_net_webrtc_peer *interface; + +public: + static WebRTCPeer *_create() { return memnew(WebRTCPeerGDNative); } + static void make_default() { WebRTCPeer::_create = WebRTCPeerGDNative::_create; } + + void set_native_webrtc_peer(const godot_net_webrtc_peer *p_impl); + + virtual void set_write_mode(WriteMode mode); + virtual WriteMode get_write_mode() const; + virtual bool was_string_packet() const; + virtual ConnectionState get_connection_state() const; + + virtual Error create_offer(); + virtual Error set_remote_description(String type, String sdp); + virtual Error set_local_description(String type, String sdp); + virtual Error add_ice_candidate(String sdpMidName, int sdpMlineIndexName, String sdpName); + virtual Error poll(); + + /** Inherited from PacketPeer: **/ + virtual int get_available_packet_count() const; + virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size); ///< buffer is GONE after next get_packet + virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size); + + virtual int get_max_packet_size() const; + + WebRTCPeerGDNative(); + ~WebRTCPeerGDNative(); +}; + +#endif // WEBRTC_PEER_GDNATIVE_H + +#endif // WEBRTC_GDNATIVE_ENABLED diff --git a/modules/webrtc/webrtc_peer_js.cpp b/modules/webrtc/webrtc_peer_js.cpp new file mode 100644 index 0000000000..1282e075ab --- /dev/null +++ b/modules/webrtc/webrtc_peer_js.cpp @@ -0,0 +1,455 @@ +/*************************************************************************/ +/* webrtc_peer_js.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 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. */ +/*************************************************************************/ + +#ifdef JAVASCRIPT_ENABLED + +#include "webrtc_peer_js.h" +#include "emscripten.h" + +extern "C" { +EMSCRIPTEN_KEEPALIVE void _emrtc_on_ice_candidate(void *obj, char *p_MidName, int p_MlineIndexName, char *p_sdpName) { + WebRTCPeerJS *peer = static_cast<WebRTCPeerJS *>(obj); + peer->emit_signal("new_ice_candidate", String(p_MidName), p_MlineIndexName, String(p_sdpName)); +} + +EMSCRIPTEN_KEEPALIVE void _emrtc_offer_created(void *obj, char *p_type, char *p_offer) { + WebRTCPeerJS *peer = static_cast<WebRTCPeerJS *>(obj); + peer->emit_signal("offer_created", String(p_type), String(p_offer)); +} + +EMSCRIPTEN_KEEPALIVE void _emrtc_on_error(void *obj) { + WebRTCPeerJS *peer = static_cast<WebRTCPeerJS *>(obj); + peer->_on_error(); +} + +EMSCRIPTEN_KEEPALIVE void _emrtc_on_open(void *obj) { + WebRTCPeerJS *peer = static_cast<WebRTCPeerJS *>(obj); + peer->_on_open(); +} + +EMSCRIPTEN_KEEPALIVE void _emrtc_on_close(void *obj) { + WebRTCPeerJS *peer = static_cast<WebRTCPeerJS *>(obj); + peer->_on_close(); +} + +EMSCRIPTEN_KEEPALIVE void _emrtc_on_message(void *obj, uint8_t *p_data, uint32_t p_size, bool p_is_string) { + WebRTCPeerJS *peer = static_cast<WebRTCPeerJS *>(obj); + peer->_on_message(p_data, p_size, p_is_string); +} + +EMSCRIPTEN_KEEPALIVE void _emrtc_bind_channel(int p_id) { + /* clang-format off */ + EM_ASM({ + if (!Module.IDHandler.has($0)) { + return; // Godot Object is gone! + } + var dict = Module.IDHandler.get($0); + var channel = dict["channel"]; + var c_ptr = dict["ptr"]; + + channel.onopen = function (evt) { + ccall("_emrtc_on_open", + "void", + ["number"], + [c_ptr] + ); + }; + channel.onclose = function (evt) { + ccall("_emrtc_on_close", + "void", + ["number"], + [c_ptr] + ); + }; + channel.onerror = function (evt) { + ccall("_emrtc_on_error", + "void", + ["number"], + [c_ptr] + ); + }; + + channel.binaryType = "arraybuffer"; + channel.onmessage = function(event) { + var buffer; + var is_string = 0; + if (event.data instanceof ArrayBuffer) { + + buffer = new Uint8Array(event.data); + + } else if (event.data instanceof Blob) { + + alert("Blob type not supported"); + return; + + } else if (typeof event.data === "string") { + + is_string = 1; + var enc = new TextEncoder("utf-8"); + buffer = new Uint8Array(enc.encode(event.data)); + + } else { + + alert("Unknown message type"); + return; + + } + var len = buffer.length*buffer.BYTES_PER_ELEMENT; + var out = Module._malloc(len); + Module.HEAPU8.set(buffer, out); + ccall("_emrtc_on_message", + "void", + ["number", "number", "number", "number"], + [c_ptr, out, len, is_string] + ); + Module._free(out); + } + }, p_id); + /* clang-format on */ +} +} + +void _emrtc_create_pc(int p_id) { + /* clang-format off */ + EM_ASM({ + var dict = Module.IDHandler.get($0); + var c_ptr = dict["ptr"]; + // Setup local connaction + var conn = new RTCPeerConnection(); + conn.onicecandidate = function(event) { + if (!Module.IDHandler.get($0)) return; + if (!event.candidate) return; + + var c = event.candidate; + // should emit on ice candidate + ccall("_emrtc_on_ice_candidate", + "void", + ["number", "string", "number", "string"], + [c_ptr, c.sdpMid, c.sdpMLineIndex, c.candidate] + ); + }; + conn.ondatachannel = function (evt) { + var dict = Module.IDHandler.get($0); + if (!dict || dict["channel"]) { + return; + } + var channel = evt.channel; + dict["channel"] = channel; + ccall("_emrtc_bind_channel", + "void", + ["number"], + [$0] + ); + }; + dict["conn"] = conn; + }, p_id); + /* clang-format on */ +} + +void WebRTCPeerJS::_on_open() { + in_buffer.resize(16); + _conn_state = STATE_CONNECTED; +} + +void WebRTCPeerJS::_on_close() { + close(); +} + +void WebRTCPeerJS::_on_error() { + close(); + _conn_state = STATE_FAILED; +} + +void WebRTCPeerJS::_on_message(uint8_t *p_data, uint32_t p_size, bool p_is_string) { + if (in_buffer.space_left() < p_size + 5) { + ERR_EXPLAIN("Buffer full! Dropping data"); + ERR_FAIL(); + } + + uint8_t is_string = p_is_string ? 1 : 0; + in_buffer.write((uint8_t *)&p_size, 4); + in_buffer.write((uint8_t *)&is_string, 1); + in_buffer.write(p_data, p_size); + queue_count++; +} + +void WebRTCPeerJS::close() { + in_buffer.resize(0); + queue_count = 0; + _was_string = false; + /* clang-format off */ + EM_ASM({ + var dict = Module.IDHandler.get($0); + if (!dict) return; + if (dict["channel"]) { + dict["channel"].close(); + dict["channel"] = null; + } + if (dict["conn"]) { + dict["conn"].close(); + } + }, _js_id); + /* clang-format on */ + _conn_state = STATE_CLOSED; +} + +Error WebRTCPeerJS::create_offer() { + ERR_FAIL_COND_V(_conn_state != STATE_NEW, FAILED); + + _conn_state = STATE_CONNECTING; + /* clang-format off */ + EM_ASM({ + var dict = Module.IDHandler.get($0); + var conn = dict["conn"]; + var c_ptr = dict["ptr"]; + var onError = function(error) { + console.log(error); + ccall("_emrtc_on_error", + "void", + ["number"], + [c_ptr] + ); + }; + var onCreated = function(offer) { + ccall("_emrtc_offer_created", + "void", + ["number", "string", "string"], + [c_ptr, offer.type, offer.sdp] + ); + }; + + var channel = conn.createDataChannel("default"); + dict["channel"] = channel; + ccall("_emrtc_bind_channel", + "void", + ["number"], + [$0] + ); + conn.createOffer().then(onCreated).catch(onError); + }, _js_id); + /* clang-format on */ + return OK; +} + +Error WebRTCPeerJS::set_local_description(String type, String sdp) { + /* clang-format off */ + EM_ASM({ + var dict = Module.IDHandler.get($0); + var conn = dict["conn"]; + var c_ptr = dict["ptr"]; + var type = UTF8ToString($1); + var sdp = UTF8ToString($2); + var onError = function(error) { + console.log(error); + ccall("_emrtc_on_error", + "void", + ["number"], + [c_ptr] + ); + }; + conn.setLocalDescription({ + "sdp": sdp, + "type": type + }).catch(onError); + }, _js_id, type.utf8().get_data(), sdp.utf8().get_data()); + /* clang-format on */ + return OK; +} + +Error WebRTCPeerJS::set_remote_description(String type, String sdp) { + if (type == "offer") { + ERR_FAIL_COND_V(_conn_state != STATE_NEW, FAILED); + _conn_state = STATE_CONNECTING; + } + /* clang-format off */ + EM_ASM({ + var dict = Module.IDHandler.get($0); + var conn = dict["conn"]; + var c_ptr = dict["ptr"]; + var type = UTF8ToString($1); + var sdp = UTF8ToString($2); + + var onError = function(error) { + console.log(error); + ccall("_emrtc_on_error", + "void", + ["number"], + [c_ptr] + ); + }; + var onCreated = function(offer) { + ccall("_emrtc_offer_created", + "void", + ["number", "string", "string"], + [c_ptr, offer.type, offer.sdp] + ); + }; + var onSet = function() { + if (type != "offer") { + return; + } + conn.createAnswer().then(onCreated); + }; + conn.setRemoteDescription({ + "sdp": sdp, + "type": type + }).then(onSet).catch(onError); + }, _js_id, type.utf8().get_data(), sdp.utf8().get_data()); + /* clang-format on */ + return OK; +} + +Error WebRTCPeerJS::add_ice_candidate(String sdpMidName, int sdpMlineIndexName, String sdpName) { + /* clang-format off */ + EM_ASM({ + var dict = Module.IDHandler.get($0); + var conn = dict["conn"]; + var c_ptr = dict["ptr"]; + var sdpMidName = UTF8ToString($1); + var sdpMlineIndexName = UTF8ToString($2); + var sdpName = UTF8ToString($3); + conn.addIceCandidate(new RTCIceCandidate({ + "candidate": sdpName, + "sdpMid": sdpMidName, + "sdpMlineIndex": sdpMlineIndexName + })); + }, _js_id, sdpMidName.utf8().get_data(), sdpMlineIndexName, sdpName.utf8().get_data()); + /* clang-format on */ + return OK; +} + +Error WebRTCPeerJS::poll() { + return OK; +} + +WebRTCPeer::ConnectionState WebRTCPeerJS::get_connection_state() const { + return _conn_state; +} + +int WebRTCPeerJS::get_available_packet_count() const { + return queue_count; +} + +Error WebRTCPeerJS::get_packet(const uint8_t **r_buffer, int &r_buffer_size) { + ERR_FAIL_COND_V(_conn_state != STATE_CONNECTED, ERR_UNCONFIGURED); + + if (queue_count == 0) + return ERR_UNAVAILABLE; + + uint32_t to_read = 0; + uint32_t left = 0; + uint8_t is_string = 0; + r_buffer_size = 0; + + in_buffer.read((uint8_t *)&to_read, 4); + --queue_count; + left = in_buffer.data_left(); + + if (left < to_read + 1) { + in_buffer.advance_read(left); + return FAILED; + } + + in_buffer.read(&is_string, 1); + _was_string = is_string == 1; + in_buffer.read(packet_buffer, to_read); + *r_buffer = packet_buffer; + r_buffer_size = to_read; + + return OK; +} + +Error WebRTCPeerJS::put_packet(const uint8_t *p_buffer, int p_buffer_size) { + ERR_FAIL_COND_V(_conn_state != STATE_CONNECTED, ERR_UNCONFIGURED); + + int is_bin = _write_mode == WebRTCPeer::WRITE_MODE_BINARY ? 1 : 0; + + /* clang-format off */ + EM_ASM({ + var dict = Module.IDHandler.get($0); + var channel = dict["channel"]; + var bytes_array = new Uint8Array($2); + var i = 0; + + for(i=0; i<$2; i++) { + bytes_array[i] = getValue($1+i, 'i8'); + } + + if ($3) { + channel.send(bytes_array.buffer); + } else { + var string = new TextDecoder("utf-8").decode(bytes_array); + channel.send(string); + } + }, _js_id, p_buffer, p_buffer_size, is_bin); + /* clang-format on */ + + return OK; +} + +int WebRTCPeerJS::get_max_packet_size() const { + return 1200; +} + +void WebRTCPeerJS::set_write_mode(WriteMode p_mode) { + _write_mode = p_mode; +} + +WebRTCPeer::WriteMode WebRTCPeerJS::get_write_mode() const { + return _write_mode; +} + +bool WebRTCPeerJS::was_string_packet() const { + return _was_string; +} + +WebRTCPeerJS::WebRTCPeerJS() { + queue_count = 0; + _was_string = false; + _write_mode = WRITE_MODE_BINARY; + _conn_state = STATE_NEW; + + /* clang-format off */ + _js_id = EM_ASM_INT({ + return Module.IDHandler.add({"conn": null, "ptr": $0, "channel": null}); + }, this); + /* clang-format on */ + _emrtc_create_pc(_js_id); +} + +WebRTCPeerJS::~WebRTCPeerJS() { + close(); + /* clang-format off */ + EM_ASM({ + Module.IDHandler.remove($0); + }, _js_id); + /* clang-format on */ +}; +#endif diff --git a/modules/webrtc/webrtc_peer_js.h b/modules/webrtc/webrtc_peer_js.h new file mode 100644 index 0000000000..02f0c9b55d --- /dev/null +++ b/modules/webrtc/webrtc_peer_js.h @@ -0,0 +1,88 @@ +/*************************************************************************/ +/* webrtc_peer_js.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 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. */ +/*************************************************************************/ + +#ifndef WEBRTC_PEER_JS_H +#define WEBRTC_PEER_JS_H + +#ifdef JAVASCRIPT_ENABLED + +#include "webrtc_peer.h" + +class WebRTCPeerJS : public WebRTCPeer { + +private: + enum { + PACKET_BUFFER_SIZE = 65536 - 5 // 4 bytes for the size, 1 for for type + }; + + bool _was_string; + WriteMode _write_mode; + + int _js_id; + RingBuffer<uint8_t> in_buffer; + int queue_count; + uint8_t packet_buffer[PACKET_BUFFER_SIZE]; + ConnectionState _conn_state; + +public: + static WebRTCPeer *_create() { return memnew(WebRTCPeerJS); } + static void make_default() { WebRTCPeer::_create = WebRTCPeerJS::_create; } + + virtual void set_write_mode(WriteMode mode); + virtual WriteMode get_write_mode() const; + virtual bool was_string_packet() const; + virtual ConnectionState get_connection_state() const; + + virtual Error create_offer(); + virtual Error set_remote_description(String type, String sdp); + virtual Error set_local_description(String type, String sdp); + virtual Error add_ice_candidate(String sdpMidName, int sdpMlineIndexName, String sdpName); + virtual Error poll(); + + /** Inherited from PacketPeer: **/ + virtual int get_available_packet_count() const; + virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size); ///< buffer is GONE after next get_packet + virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size); + + virtual int get_max_packet_size() const; + + void close(); + void _on_open(); + void _on_close(); + void _on_error(); + void _on_message(uint8_t *p_data, uint32_t p_size, bool p_is_string); + + WebRTCPeerJS(); + ~WebRTCPeerJS(); +}; + +#endif + +#endif // WEBRTC_PEER_JS_H |