diff options
author | Fabio Alessandrelli <fabio.alessandrelli@gmail.com> | 2019-04-21 04:57:53 +0200 |
---|---|---|
committer | Fabio Alessandrelli <fabio.alessandrelli@gmail.com> | 2019-05-16 10:32:51 +0200 |
commit | 3e64a42b1492e38bf033041c0eb1212542728cbd (patch) | |
tree | d187f873ecfdace0d127c6bc340ed295edcaa2f1 /src | |
parent | f2cf2e5340c1aa20516aea4863b8f7a46f317bb6 (diff) | |
download | fork-godot-webrtc-native-3e64a42b1492e38bf033041c0eb1212542728cbd.tar.gz fork-godot-webrtc-native-3e64a42b1492e38bf033041c0eb1212542728cbd.tar.bz2 fork-godot-webrtc-native-3e64a42b1492e38bf033041c0eb1212542728cbd.zip |
Update to new DataChannel API.
New WebRTCLibDataChannel class act as PacketPeer.
Old WebRTCPeer (now WebRTCPeerConnection) now allows you to set
configuration (STUN/TURN) and creating multiple data channels.
Fixed many bugs and implemented most of the missing API.
Diffstat (limited to 'src')
-rw-r--r-- | src/GodotCreateSessionDescriptionObserver.cpp | 10 | ||||
-rw-r--r-- | src/GodotDataChannelObserver.cpp | 19 | ||||
-rw-r--r-- | src/GodotPeerConnectionObserver.cpp | 24 | ||||
-rw-r--r-- | src/GodotSetSessionDescriptionObserver.cpp | 8 | ||||
-rw-r--r-- | src/WebRTCLibDataChannel.cpp | 177 | ||||
-rw-r--r-- | src/WebRTCLibDataChannel.hpp | 76 | ||||
-rw-r--r-- | src/WebRTCLibPeer.cpp | 202 | ||||
-rw-r--r-- | src/WebRTCLibPeerConnection.cpp | 245 | ||||
-rw-r--r-- | src/WebRTCLibPeerConnection.hpp (renamed from src/WebRTCLibPeer.hpp) | 57 | ||||
-rw-r--r-- | src/init.cpp | 10 | ||||
-rw-r--r-- | src/net/WebRTCDataChannelNative.cpp | 92 | ||||
-rw-r--r-- | src/net/WebRTCDataChannelNative.hpp | 91 | ||||
-rw-r--r-- | src/net/WebRTCPeerConnectionNative.cpp | 65 | ||||
-rw-r--r-- | src/net/WebRTCPeerConnectionNative.hpp | 66 | ||||
-rw-r--r-- | src/net/WebRTCPeerNative.cpp | 77 | ||||
-rw-r--r-- | src/net/WebRTCPeerNative.hpp | 80 |
16 files changed, 858 insertions, 441 deletions
diff --git a/src/GodotCreateSessionDescriptionObserver.cpp b/src/GodotCreateSessionDescriptionObserver.cpp index 77d1308..f9d110c 100644 --- a/src/GodotCreateSessionDescriptionObserver.cpp +++ b/src/GodotCreateSessionDescriptionObserver.cpp @@ -1,16 +1,16 @@ -#include "WebRTCLibPeer.hpp" +#include "WebRTCLibPeerConnection.hpp" using namespace godot_webrtc; -WebRTCLibPeer::GodotCSDO::GodotCSDO(WebRTCLibPeer *parent) { +WebRTCLibPeerConnection::GodotCSDO::GodotCSDO(WebRTCLibPeerConnection *parent) { this->parent = parent; } -void WebRTCLibPeer::GodotCSDO::OnSuccess(webrtc::SessionDescriptionInterface *desc) { +void WebRTCLibPeerConnection::GodotCSDO::OnSuccess(webrtc::SessionDescriptionInterface *desc) { // serialize this offer and send it to the remote peer: std::string sdp; // sdp = session description protocol desc->ToString(&sdp); - parent->queue_signal("offer_created", 2, desc->type().c_str(), sdp.c_str()); + parent->queue_signal("session_description_created", 2, desc->type().c_str(), sdp.c_str()); }; -void WebRTCLibPeer::GodotCSDO::OnFailure(const std::string &error){}; +void WebRTCLibPeerConnection::GodotCSDO::OnFailure(const std::string &error){}; diff --git a/src/GodotDataChannelObserver.cpp b/src/GodotDataChannelObserver.cpp deleted file mode 100644 index 7a6cf96..0000000 --- a/src/GodotDataChannelObserver.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "WebRTCLibPeer.hpp" - -using namespace godot_webrtc; - -WebRTCLibPeer::GodotDCO::GodotDCO(WebRTCLibPeer *parent) { - this->parent = parent; -} - -void WebRTCLibPeer::GodotDCO::OnMessage(const webrtc::DataBuffer &buffer) { - const uint8_t *data = buffer.data.data<uint8_t>(); - uint8_t *memory_controlled_buffer = new uint8_t[buffer.data.size()]; - - std::copy(data, data + buffer.data.size(), memory_controlled_buffer); - parent->queue_packet(memory_controlled_buffer, buffer.data.size()); -}; - -void WebRTCLibPeer::GodotDCO::OnStateChange(){}; - -void WebRTCLibPeer::GodotDCO::OnBufferedAmountChange(uint64_t previous_amount){}; diff --git a/src/GodotPeerConnectionObserver.cpp b/src/GodotPeerConnectionObserver.cpp index 298cfcf..c3f8f39 100644 --- a/src/GodotPeerConnectionObserver.cpp +++ b/src/GodotPeerConnectionObserver.cpp @@ -1,33 +1,35 @@ -#include "WebRTCLibPeer.hpp" +#include "WebRTCLibPeerConnection.hpp" +#include "WebRTCLibDataChannel.hpp" using namespace godot_webrtc; -WebRTCLibPeer::GodotPCO::GodotPCO(WebRTCLibPeer *parent) { +WebRTCLibPeerConnection::GodotPCO::GodotPCO(WebRTCLibPeerConnection *parent) { this->parent = parent; } -void WebRTCLibPeer::GodotPCO::OnSignalingChange(webrtc::PeerConnectionInterface::SignalingState new_state) { +void WebRTCLibPeerConnection::GodotPCO::OnSignalingChange(webrtc::PeerConnectionInterface::SignalingState new_state) { } -void WebRTCLibPeer::GodotPCO::OnAddStream(rtc::scoped_refptr<webrtc::MediaStreamInterface> stream) { +void WebRTCLibPeerConnection::GodotPCO::OnAddStream(rtc::scoped_refptr<webrtc::MediaStreamInterface> stream) { } -void WebRTCLibPeer::GodotPCO::OnRemoveStream(rtc::scoped_refptr<webrtc::MediaStreamInterface> stream) { +void WebRTCLibPeerConnection::GodotPCO::OnRemoveStream(rtc::scoped_refptr<webrtc::MediaStreamInterface> stream) { } -void WebRTCLibPeer::GodotPCO::OnDataChannel(rtc::scoped_refptr<webrtc::DataChannelInterface> data_channel) { +void WebRTCLibPeerConnection::GodotPCO::OnDataChannel(rtc::scoped_refptr<webrtc::DataChannelInterface> data_channel) { + parent->queue_signal("data_channel_received", 1, WebRTCLibDataChannel::new_data_channel(data_channel)); } -void WebRTCLibPeer::GodotPCO::OnRenegotiationNeeded() { +void WebRTCLibPeerConnection::GodotPCO::OnRenegotiationNeeded() { } -void WebRTCLibPeer::GodotPCO::OnIceConnectionChange(webrtc::PeerConnectionInterface::IceConnectionState new_state) { +void WebRTCLibPeerConnection::GodotPCO::OnIceConnectionChange(webrtc::PeerConnectionInterface::IceConnectionState new_state) { } -void WebRTCLibPeer::GodotPCO::OnIceGatheringChange(webrtc::PeerConnectionInterface::IceGatheringState new_state) { +void WebRTCLibPeerConnection::GodotPCO::OnIceGatheringChange(webrtc::PeerConnectionInterface::IceGatheringState new_state) { } -void WebRTCLibPeer::GodotPCO::OnIceCandidate(const webrtc::IceCandidateInterface *candidate) { +void WebRTCLibPeerConnection::GodotPCO::OnIceCandidate(const webrtc::IceCandidateInterface *candidate) { // Serialize the candidate and send it to the remote peer: godot::Dictionary candidateSDP; @@ -38,7 +40,7 @@ void WebRTCLibPeer::GodotPCO::OnIceCandidate(const webrtc::IceCandidateInterface candidate->ToString(&sdp); godot::String candidateSdpName = sdp.c_str(); - parent->queue_signal("new_ice_candidate", + parent->queue_signal("ice_candidate_created", 3, candidateSdpMidName, candidateSdpMlineIndexName, diff --git a/src/GodotSetSessionDescriptionObserver.cpp b/src/GodotSetSessionDescriptionObserver.cpp index 52be2af..96d466c 100644 --- a/src/GodotSetSessionDescriptionObserver.cpp +++ b/src/GodotSetSessionDescriptionObserver.cpp @@ -1,11 +1,11 @@ -#include "WebRTCLibPeer.hpp" +#include "WebRTCLibPeerConnection.hpp" using namespace godot_webrtc; -WebRTCLibPeer::GodotSSDO::GodotSSDO(WebRTCLibPeer *parent) { +WebRTCLibPeerConnection::GodotSSDO::GodotSSDO(WebRTCLibPeerConnection *parent) { this->parent = parent; } -void WebRTCLibPeer::GodotSSDO::OnSuccess(){}; +void WebRTCLibPeerConnection::GodotSSDO::OnSuccess(){}; -void WebRTCLibPeer::GodotSSDO::OnFailure(const std::string &error){}; +void WebRTCLibPeerConnection::GodotSSDO::OnFailure(const std::string &error){}; diff --git a/src/WebRTCLibDataChannel.cpp b/src/WebRTCLibDataChannel.cpp new file mode 100644 index 0000000..ede89a9 --- /dev/null +++ b/src/WebRTCLibDataChannel.cpp @@ -0,0 +1,177 @@ +#include "WebRTCLibDataChannel.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<uint8_t>(), buffer.data.size()); +} + +void WebRTCLibDataChannel::ChannelObserver::OnStateChange() { +} + +void WebRTCLibDataChannel::ChannelObserver::OnBufferedAmountChange(uint64_t previous_amount) { +} + +// DataChannel +WebRTCLibDataChannel *WebRTCLibDataChannel::new_data_channel(rtc::scoped_refptr<webrtc::DataChannelInterface> 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::get_wrapper<godot::GDNativeLibrary>((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 = godot::as<WebRTCLibDataChannel>(out); + tmp->bind_channel(p_channel); + + return tmp; +} + + +void WebRTCLibDataChannel::bind_channel(rtc::scoped_refptr<webrtc::DataChannelInterface> 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; +} diff --git a/src/WebRTCLibDataChannel.hpp b/src/WebRTCLibDataChannel.hpp new file mode 100644 index 0000000..557d1da --- /dev/null +++ b/src/WebRTCLibDataChannel.hpp @@ -0,0 +1,76 @@ +#ifndef WEBRTC_DATA_CHANNEL_H +#define WEBRTC_DATA_CHANNEL_H + +#include <Godot.hpp> // Godot.hpp must go first, or windows builds breaks + +#include "api/peerconnectioninterface.h" // interface for all things needed from WebRTC +#include "media/base/mediaengine.h" // needed for CreateModularPeerConnectionFactory + +#include "net/WebRTCDataChannelNative.hpp" +#include "PoolArrays.hpp" +#include <mutex> + +namespace godot_webrtc { + +class WebRTCLibDataChannel : public WebRTCDataChannelNative { + GODOT_CLASS(WebRTCLibDataChannel, WebRTCDataChannelNative); + +private: + class ChannelObserver : public webrtc::DataChannelObserver { + public: + WebRTCLibDataChannel *parent; + + ChannelObserver(WebRTCLibDataChannel *parent); + void OnMessage(const webrtc::DataBuffer &buffer) override; + void OnStateChange() override; // UNUSED + void OnBufferedAmountChange(uint64_t previous_amount) override; // UNUSED + }; + + ChannelObserver observer; + rtc::scoped_refptr<webrtc::DataChannelInterface> channel; + + std::mutex *mutex; + std::queue<godot::PoolByteArray> packet_queue; + godot::PoolByteArray current_packet; + std::string label; + std::string protocol; + +public: + static WebRTCLibDataChannel *new_data_channel(rtc::scoped_refptr<webrtc::DataChannelInterface> p_channel); + static void _register_methods(); + + void _init(); + + void bind_channel(rtc::scoped_refptr<webrtc::DataChannelInterface> p_channel); + void queue_packet(const uint8_t *data, uint32_t size); + + /* WebRTCDataChannel */ + void set_write_mode(godot_int mode); + godot_int get_write_mode() const; + bool was_string_packet() const; + + ChannelState get_ready_state() const; + const char *get_label() const; + bool is_ordered() const; + int get_id() const; + int get_max_packet_life_time() const; + int get_max_retransmits() const; + const char *get_protocol() const; + bool is_negotiated() const; + + godot_error poll(); + void close(); + + /* PacketPeer */ + virtual godot_error get_packet(const uint8_t **r_buffer, int *r_len); + virtual godot_error put_packet(const uint8_t *p_buffer, int p_len); + virtual godot_int get_available_packet_count() const; + virtual godot_int get_max_packet_size() const; + + WebRTCLibDataChannel(); + ~WebRTCLibDataChannel(); +}; + +} // namespace godot_webrtc + +#endif // WEBRTC_DATA_CHANNEL_H diff --git a/src/WebRTCLibPeer.cpp b/src/WebRTCLibPeer.cpp deleted file mode 100644 index c94cfcd..0000000 --- a/src/WebRTCLibPeer.cpp +++ /dev/null @@ -1,202 +0,0 @@ -#include "WebRTCLibPeer.hpp" - -using namespace godot_webrtc; - -void WebRTCLibPeer::set_write_mode(godot_int mode) { -} - -godot_int WebRTCLibPeer::get_write_mode() const { - return 0; -} - -bool WebRTCLibPeer::was_string_packet() const { - return false; -} - -godot_int WebRTCLibPeer::get_connection_state() const { - return 0; -} - -godot_error WebRTCLibPeer::create_offer() { - peer_connection->CreateOffer( - ptr_csdo, // CreateSessionDescriptionObserver* observer, - nullptr // webrtc::PeerConnectionInterface::RTCOfferAnswerOptions() // const MediaConstraintsInterface* constraints - ); - return GODOT_OK; -} - -godot_error WebRTCLibPeer::set_remote_description(const char *type, const char *sdp) { - godot_error err = set_description(type, sdp, false); //false meaning !isLocal because it is remote - peer_connection->CreateAnswer(ptr_csdo, webrtc::PeerConnectionInterface::RTCOfferAnswerOptions()); - return err; -} - -godot_error WebRTCLibPeer::set_local_description(const char *type, const char *sdp) { - return set_description(type, sdp, true); // isLocal == true -} - -godot_error WebRTCLibPeer::add_ice_candidate(const char *sdpMidName, int sdpMlineIndexName, const char *sdpName) { - webrtc::SdpParseError *error = nullptr; - webrtc::IceCandidateInterface *candidate = webrtc::CreateIceCandidate( - sdpMidName, - sdpMlineIndexName, - sdpName, - error); - - // @TODO do something if there's an error (if error, or if !candidate) - if (error || !candidate) - std::cout << "ERROR with creating ICE candidate (" << error << ")\n"; - - if (!peer_connection->AddIceCandidate(candidate)) - ERR_PRINT("Error with adding ICE candidate"); - return GODOT_OK; -} - -godot_error WebRTCLibPeer::poll() { - std::function<void()> signal; - while (!signal_queue.empty()) { - mutex_signal_queue->lock(); - signal = signal_queue.front(); - signal_queue.pop(); - mutex_signal_queue->unlock(); - - signal(); - } - return GODOT_OK; -} - -godot_error WebRTCLibPeer::get_packet(const uint8_t **r_buffer, int *r_len) { - if (packet_queue_size == 0) - return GODOT_ERR_UNAVAILABLE; - mutex_packet_queue->lock(); - uint8_t *current_packet = packet_queue.front(); - *r_buffer = current_packet; - *r_len = packet_sizes_queue.front(); - - packet_queue.pop(); - packet_sizes_queue.pop(); - mutex_packet_queue->unlock(); - - --packet_queue_size; - return GODOT_OK; -} - -godot_error WebRTCLibPeer::put_packet(const uint8_t *p_buffer, int p_len) { - webrtc::DataBuffer webrtc_buffer(rtc::CopyOnWriteBuffer(p_buffer, p_len), true); - data_channel->Send(webrtc_buffer); - return GODOT_OK; // @TODO properly return any Error we may get. -} - -godot_int WebRTCLibPeer::get_available_packet_count() const { - return packet_queue_size; -} - -godot_int WebRTCLibPeer::get_max_packet_size() const { - return 1200; -} - -void WebRTCLibPeer::_register_methods() { -} - -void WebRTCLibPeer::_init() { - register_interface(&interface); - - // initialize variables: - mutex_signal_queue = new std::mutex; - mutex_packet_queue = new std::mutex; - packet_queue_size = 0; - - // create a PeerConnectionFactoryInterface: - signaling_thread = new rtc::Thread; - signaling_thread->Start(); - pc_factory = webrtc::CreateModularPeerConnectionFactory( - nullptr, // rtc::Thread* network_thread, - nullptr, // rtc::Thread* worker_thread, - signaling_thread, - nullptr, // std::unique_ptr<cricket::MediaEngineInterface> media_engine, - nullptr, // std::unique_ptr<CallFactoryInterface> call_factory, - nullptr // std::unique_ptr<RtcEventLogFactoryInterface> event_log_factory - ); - if (pc_factory.get() == nullptr) { // PeerConnectionFactory couldn't be created. Fail the method call. - ERR_PRINT("PeerConnectionFactory could not be created"); - // return GODOT_FAILED; - } - - // create PeerConnection configuration and add the ice servers: - webrtc::PeerConnectionInterface::RTCConfiguration configuration; - //webrtc::PeerConnectionInterface::IceServer ice_server; - - //ice_server.uri = "stun:stun.l.google.com:19302"; // @FIXME allow user to input ice servers - //configuration.servers.push_back(ice_server); - - // create a PeerConnection object: - peer_connection = pc_factory->CreatePeerConnection(configuration, nullptr, nullptr, &pco); - if (peer_connection.get() == nullptr) { // PeerConnection couldn't be created. Fail the method call. - ERR_PRINT("PeerConnection could not be created"); - // return GODOT_FAILED; - } - - // create a DataChannel - webrtc::DataChannelInit data_channel_config; - data_channel_config.negotiated = true; // True if the channel has been externally negotiated - data_channel_config.id = 0; - - data_channel = peer_connection->CreateDataChannel("channel", &data_channel_config); - // @TODO (NONESSENTIAL) create data_channel check. fail function call if data_channel isn't created - data_channel->RegisterObserver(&dco); -} - -WebRTCLibPeer::WebRTCLibPeer() : - dco(this), - pco(this), - ptr_csdo(new rtc::RefCountedObject<GodotCSDO>(this)), - ptr_ssdo(new rtc::RefCountedObject<GodotSSDO>(this)) { -} - -WebRTCLibPeer::~WebRTCLibPeer() { - if (_owner) { - register_interface(NULL); - } - delete mutex_signal_queue; - delete mutex_packet_queue; -} - -void WebRTCLibPeer::queue_signal(godot::String p_name, int p_argc, const godot::Variant &p_arg1, const godot::Variant &p_arg2, const godot::Variant &p_arg3) { - mutex_signal_queue->lock(); - signal_queue.push( - [this, p_name, p_argc, p_arg1, p_arg2, p_arg3] { - if (p_argc == 2) - emit_signal(p_name, p_arg1, p_arg2); - else - emit_signal(p_name, p_arg1, p_arg2, p_arg3); - }); - mutex_signal_queue->unlock(); -} - -void WebRTCLibPeer::queue_packet(uint8_t *buffer, int buffer_size) { - mutex_packet_queue->lock(); - packet_queue.push(buffer); - packet_sizes_queue.push(buffer_size); - ++packet_queue_size; - mutex_packet_queue->unlock(); -} - -godot_error WebRTCLibPeer::set_description(const char *type, const char *sdp, bool isLocal) { - // webrtc::SdpType type = (isOffer) ? webrtc::SdpType::kOffer : webrtc::SdpType::kAnswer; - godot::String string_sdp = sdp; - - webrtc::SdpType sdptype = (godot::String(type) == godot::String("offer")) ? webrtc::SdpType::kOffer : webrtc::SdpType::kAnswer; - std::unique_ptr<webrtc::SessionDescriptionInterface> desc = - webrtc::CreateSessionDescription(sdptype, sdp); - - if (isLocal) { - peer_connection->SetLocalDescription( - ptr_ssdo, // @TODO (NONESSENTIAL, OPTIONAL) replace this with DummySetSessionDescriptionObserver::Create() - desc.release()); - } else { - peer_connection->SetRemoteDescription( - ptr_ssdo, // @TODO (NONESSENTIAL, OPTIONAL) replace this with DummySetSessionDescriptionObserver::Create() - desc.release()); - } - return GODOT_OK; -} diff --git a/src/WebRTCLibPeerConnection.cpp b/src/WebRTCLibPeerConnection.cpp new file mode 100644 index 0000000..a922f1b --- /dev/null +++ b/src/WebRTCLibPeerConnection.cpp @@ -0,0 +1,245 @@ +#include "WebRTCDataChannel.hpp" +#include "WebRTCDataChannelGDNative.hpp" +#include "WebRTCLibPeerConnection.hpp" +#include "WebRTCLibDataChannel.hpp" + +using namespace godot_webrtc; + +godot_error _parse_ice_server(webrtc::PeerConnectionInterface::RTCConfiguration &r_config, godot::Dictionary p_server) { + godot::Variant v; + webrtc::PeerConnectionInterface::IceServer ice_server; + godot::String url; + + ERR_FAIL_COND_V(!p_server.has("urls"), GODOT_ERR_INVALID_PARAMETER); + + // Parse mandatory URL + v = p_server["urls"]; + if (v.get_type() == godot::Variant::STRING) { + url = v; + ice_server.urls.push_back(url.utf8().get_data()); + } else if (v.get_type() == godot::Variant::ARRAY) { + godot::Array names = v; + for (int j = 0; j < names.size(); j++) { + v = names[j]; + ERR_FAIL_COND_V(v.get_type() != godot::Variant::STRING, GODOT_ERR_INVALID_PARAMETER); + url = v; + ice_server.urls.push_back(url.utf8().get_data()); + } + } else { + ERR_FAIL_V(GODOT_ERR_INVALID_PARAMETER); + } + // Parse credentials (only meaningful for TURN, only support password) + if (p_server.has("username") && (v = p_server["username"]) && v.get_type() == godot::Variant::STRING) { + ice_server.username = (v.operator godot::String()).utf8().get_data(); + } + if (p_server.has("credential") && (v = p_server["credential"]) && v.get_type() == godot::Variant::STRING) { + ice_server.password = (v.operator godot::String()).utf8().get_data(); + } + + r_config.servers.push_back(ice_server); + return GODOT_OK; +} + +godot_error _parse_channel_config(webrtc::DataChannelInit &r_config, godot::Dictionary p_dict) { + godot::Variant v; +#define _SET_N(PROP, PNAME, TYPE) if (p_dict.has(#PROP)) { v = p_dict[#PROP]; if(v.get_type() == godot::Variant::TYPE) r_config.PNAME = v; } +#define _SET(PROP, TYPE) _SET_N(PROP, PROP, TYPE) + _SET(negotiated, BOOL); + _SET(id, INT); + _SET_N(maxPacketLifeTime, maxRetransmitTime, INT); + _SET(maxRetransmits, INT); + _SET(ordered, BOOL); +#undef _SET + if (p_dict.has("protocol") && (v = p_dict["protocol"]) && v.get_type() == godot::Variant::STRING) { + r_config.protocol = v.operator godot::String().utf8().get_data(); + } + + // ID makes sense only when negotiated is true (and must be set in that case) + ERR_FAIL_COND_V(r_config.negotiated ? r_config.id == -1 : r_config.id != -1, GODOT_ERR_INVALID_PARAMETER); + // Only one of maxRetransmits and maxRetransmitTime can be set on a channel. + ERR_FAIL_COND_V(r_config.maxRetransmits != -1 && r_config.maxRetransmitTime != -1, GODOT_ERR_INVALID_PARAMETER); + return GODOT_OK; +} + +WebRTCLibPeerConnection::ConnectionState WebRTCLibPeerConnection::get_connection_state() const { + ERR_FAIL_COND_V(peer_connection.get() == nullptr, STATE_CLOSED); + + webrtc::PeerConnectionInterface::IceConnectionState state = peer_connection->ice_connection_state(); + switch(state) { + case webrtc::PeerConnectionInterface::kIceConnectionNew: + return STATE_NEW; + case webrtc::PeerConnectionInterface::kIceConnectionChecking: + return STATE_CONNECTING; + case webrtc::PeerConnectionInterface::kIceConnectionConnected: + return STATE_CONNECTED; + case webrtc::PeerConnectionInterface::kIceConnectionCompleted: + return STATE_CONNECTED; + case webrtc::PeerConnectionInterface::kIceConnectionFailed: + return STATE_FAILED; + case webrtc::PeerConnectionInterface::kIceConnectionDisconnected: + return STATE_DISCONNECTED; + case webrtc::PeerConnectionInterface::kIceConnectionClosed: + return STATE_CLOSED; + default: + return STATE_CLOSED; + } +} + +godot_error WebRTCLibPeerConnection::initialize(const godot_dictionary *p_config) { + webrtc::PeerConnectionInterface::RTCConfiguration config; + godot::Dictionary d = *(godot::Dictionary *)p_config; + godot::Variant v; + if (d.has("iceServers") && (v = d["iceServers"]) && v.get_type() == godot::Variant::ARRAY) { + godot::Array servers = v; + for (int i = 0; i < servers.size(); i++) { + v = servers[i]; + ERR_FAIL_COND_V(v.get_type() != godot::Variant::DICTIONARY, GODOT_ERR_INVALID_PARAMETER); + godot_error err; + godot::Dictionary server = v; + err = _parse_ice_server(config, server); + ERR_FAIL_COND_V(err != GODOT_OK, err); + } + } + return _create_pc(config); +} + +godot_object *WebRTCLibPeerConnection::create_data_channel(const char *p_channel, const godot_dictionary *p_channel_config) { + ERR_FAIL_COND_V(peer_connection.get() == nullptr, NULL); + + // Read config from dictionary + webrtc::DataChannelInit config; + godot::Dictionary d = *(godot::Dictionary *)p_channel_config; + godot_error err = _parse_channel_config(config, d); + ERR_FAIL_COND_V(err != GODOT_OK, NULL); + + WebRTCLibDataChannel *wrapper = WebRTCLibDataChannel::new_data_channel(peer_connection->CreateDataChannel(p_channel, &config)); + ERR_FAIL_COND_V(wrapper == NULL, NULL); + return wrapper->_owner; +} + +godot_error WebRTCLibPeerConnection::create_offer() { + ERR_FAIL_COND_V(peer_connection.get() == nullptr, GODOT_ERR_UNCONFIGURED); + peer_connection->CreateOffer(ptr_csdo, nullptr); + return GODOT_OK; +} + +#define _MAKE_DESC(TYPE, SDP) webrtc::CreateSessionDescription((godot::String(TYPE) == godot::String("offer") ? webrtc::SdpType::kOffer : webrtc::SdpType::kAnswer), SDP) +godot_error WebRTCLibPeerConnection::set_remote_description(const char *type, const char *sdp) { + ERR_FAIL_COND_V(peer_connection.get() == nullptr, GODOT_ERR_UNCONFIGURED); + std::unique_ptr<webrtc::SessionDescriptionInterface> desc = _MAKE_DESC(type, sdp); + peer_connection->SetRemoteDescription(ptr_ssdo, desc.release()); + peer_connection->CreateAnswer(ptr_csdo, webrtc::PeerConnectionInterface::RTCOfferAnswerOptions()); + return GODOT_OK; +} + +godot_error WebRTCLibPeerConnection::set_local_description(const char *type, const char *sdp) { + ERR_FAIL_COND_V(peer_connection.get() == nullptr, GODOT_ERR_UNCONFIGURED); + std::unique_ptr<webrtc::SessionDescriptionInterface> desc = _MAKE_DESC(type, sdp); + peer_connection->SetLocalDescription(ptr_ssdo, desc.release()); + return GODOT_OK; +} +#undef _MAKE_DESC + +godot_error WebRTCLibPeerConnection::add_ice_candidate(const char *sdpMidName, int sdpMlineIndexName, const char *sdpName) { + ERR_FAIL_COND_V(peer_connection.get() == nullptr, GODOT_ERR_UNCONFIGURED); + + webrtc::SdpParseError *error = nullptr; + webrtc::IceCandidateInterface *candidate = webrtc::CreateIceCandidate( + sdpMidName, + sdpMlineIndexName, + sdpName, + error); + + ERR_FAIL_COND_V(error || !candidate, GODOT_ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(!peer_connection->AddIceCandidate(candidate), GODOT_FAILED); + + return GODOT_OK; +} + +godot_error WebRTCLibPeerConnection::poll() { + ERR_FAIL_COND_V(peer_connection.get() == nullptr, GODOT_ERR_UNCONFIGURED); + + std::function<void()> signal; + while (!signal_queue.empty()) { + mutex_signal_queue->lock(); + signal = signal_queue.front(); + signal_queue.pop(); + mutex_signal_queue->unlock(); + + signal(); + } + return GODOT_OK; +} + +void WebRTCLibPeerConnection::close() { + peer_connection->Close(); + while(!signal_queue.empty()) { + signal_queue.pop(); + } +} + +void WebRTCLibPeerConnection::_register_methods() { +} + +void WebRTCLibPeerConnection::_init() { + register_interface(&interface); + + // initialize variables: + mutex_signal_queue = new std::mutex; + + // create a PeerConnectionFactoryInterface: + signaling_thread = new rtc::Thread; + signaling_thread->Start(); + pc_factory = webrtc::CreateModularPeerConnectionFactory( + nullptr, // rtc::Thread* network_thread, + nullptr, // rtc::Thread* worker_thread, + signaling_thread, + nullptr, // std::unique_ptr<cricket::MediaEngineInterface> media_engine, + nullptr, // std::unique_ptr<CallFactoryInterface> call_factory, + nullptr // std::unique_ptr<RtcEventLogFactoryInterface> event_log_factory + ); + + // Create peer connection with default configuration. + webrtc::PeerConnectionInterface::RTCConfiguration config; + _create_pc(config); +} + +godot_error WebRTCLibPeerConnection::_create_pc(webrtc::PeerConnectionInterface::RTCConfiguration &config) { + ERR_FAIL_COND_V(pc_factory.get() == nullptr, GODOT_ERR_BUG); + peer_connection = nullptr; + peer_connection = pc_factory->CreatePeerConnection(config, nullptr, nullptr, &pco); + if (peer_connection.get() == nullptr) { // PeerConnection couldn't be created. Fail the method call. + ERR_PRINT("PeerConnection could not be created"); + return GODOT_FAILED; + } + return GODOT_OK; +} + +WebRTCLibPeerConnection::WebRTCLibPeerConnection() : + pco(this), + ptr_csdo(new rtc::RefCountedObject<GodotCSDO>(this)), + ptr_ssdo(new rtc::RefCountedObject<GodotSSDO>(this)) { +} + +WebRTCLibPeerConnection::~WebRTCLibPeerConnection() { + if (_owner) { + register_interface(NULL); + } + close(); + delete mutex_signal_queue; +} + +void WebRTCLibPeerConnection::queue_signal(godot::String p_name, int p_argc, const godot::Variant &p_arg1, const godot::Variant &p_arg2, const godot::Variant &p_arg3) { + mutex_signal_queue->lock(); + signal_queue.push( + [this, p_name, p_argc, p_arg1, p_arg2, p_arg3] { + if (p_argc == 1) { + emit_signal(p_name, p_arg1); + } else if (p_argc == 2) { + emit_signal(p_name, p_arg1, p_arg2); + } else { + emit_signal(p_name, p_arg1, p_arg2, p_arg3); + } + }); + mutex_signal_queue->unlock(); +} diff --git a/src/WebRTCLibPeer.hpp b/src/WebRTCLibPeerConnection.hpp index 9707f4f..b46d606 100644 --- a/src/WebRTCLibPeer.hpp +++ b/src/WebRTCLibPeerConnection.hpp @@ -8,62 +8,47 @@ #include <functional> // std::function #include <mutex> // mutex @TODO replace std::mutex with Godot mutex -#include "net/WebRTCPeerNative.hpp" +#include "net/WebRTCPeerConnectionNative.hpp" namespace godot_webrtc { -class WebRTCLibPeer : public WebRTCPeerNative { - GODOT_CLASS(WebRTCLibPeer, WebRTCPeerNative); +class WebRTCLibPeerConnection : public WebRTCPeerConnectionNative { + GODOT_CLASS(WebRTCLibPeerConnection, WebRTCPeerConnectionNative); + +private: + godot_error _create_pc(webrtc::PeerConnectionInterface::RTCConfiguration &config); public: static void _register_methods(); void _init(); - void set_write_mode(godot_int mode); - godot_int get_write_mode() const; - bool was_string_packet() const; - godot_int get_connection_state() const; + ConnectionState get_connection_state() const; + godot_error initialize(const godot_dictionary *p_config); + godot_object *create_data_channel(const char *p_channel, const godot_dictionary *p_channel_config); godot_error create_offer(); godot_error set_remote_description(const char *type, const char *sdp); godot_error set_local_description(const char *type, const char *sdp); godot_error add_ice_candidate(const char *sdpMidName, int sdpMlineIndexName, const char *sdpName); godot_error poll(); + void close(); - /* WebRTCPeer */ - virtual godot_error get_packet(const uint8_t **r_buffer, int *r_len); - virtual godot_error put_packet(const uint8_t *p_buffer, int p_len); - virtual godot_int get_available_packet_count() const; - virtual godot_int get_max_packet_size() const; - - WebRTCLibPeer(); - ~WebRTCLibPeer(); + WebRTCLibPeerConnection(); + ~WebRTCLibPeerConnection(); /* helper functions */ void queue_signal(godot::String p_name, int p_argc, const godot::Variant &p_arg1 = godot::Variant(), const godot::Variant &p_arg2 = godot::Variant(), const godot::Variant &p_arg3 = godot::Variant()); // void queue_signal(godot::StringName p_name, Variant_ARG_LIST); void queue_packet(uint8_t *, int); - godot_error set_description(const char *type, const char *sdp, bool isLocal); - - /** DataChannelObserver callback functions **/ - class GodotDCO : public webrtc::DataChannelObserver { - public: - WebRTCLibPeer *parent; - - GodotDCO(WebRTCLibPeer *parent); - void OnMessage(const webrtc::DataBuffer &buffer) override; - void OnStateChange() override; // UNUSED - void OnBufferedAmountChange(uint64_t previous_amount) override; // UNUSED - }; /** PeerConnectionObserver callback functions **/ class GodotPCO : public webrtc::PeerConnectionObserver { public: - WebRTCLibPeer *parent; + WebRTCLibPeerConnection *parent; - GodotPCO(WebRTCLibPeer *parent); + GodotPCO(WebRTCLibPeerConnection *parent); void OnSignalingChange(webrtc::PeerConnectionInterface::SignalingState new_state) override; void OnAddStream(rtc::scoped_refptr<webrtc::MediaStreamInterface> stream) override; void OnRemoveStream(rtc::scoped_refptr<webrtc::MediaStreamInterface> stream) override; @@ -77,9 +62,9 @@ public: /** CreateSessionDescriptionObserver callback functions **/ class GodotCSDO : public webrtc::CreateSessionDescriptionObserver { public: - WebRTCLibPeer *parent; + WebRTCLibPeerConnection *parent; - GodotCSDO(WebRTCLibPeer *parent); + GodotCSDO(WebRTCLibPeerConnection *parent); void OnSuccess(webrtc::SessionDescriptionInterface *desc) override; void OnFailure(const std::string &error) override; }; @@ -87,29 +72,23 @@ public: /** SetSessionDescriptionObserver callback functions **/ class GodotSSDO : public webrtc::SetSessionDescriptionObserver { public: - WebRTCLibPeer *parent; + WebRTCLibPeerConnection *parent; - GodotSSDO(WebRTCLibPeer *parent); + GodotSSDO(WebRTCLibPeerConnection *parent); void OnSuccess() override; void OnFailure(const std::string &error) override; }; - GodotDCO dco; GodotPCO pco; rtc::scoped_refptr<GodotSSDO> ptr_ssdo; rtc::scoped_refptr<GodotCSDO> ptr_csdo; std::mutex *mutex_signal_queue; - std::mutex *mutex_packet_queue; - int packet_queue_size; - std::queue<uint8_t *> packet_queue; - std::queue<int> packet_sizes_queue; std::queue<std::function<void()> > signal_queue; rtc::Thread *signaling_thread; rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> pc_factory; rtc::scoped_refptr<webrtc::PeerConnectionInterface> peer_connection; - rtc::scoped_refptr<webrtc::DataChannelInterface> data_channel; }; } // namespace godot_webrtc diff --git a/src/init.cpp b/src/init.cpp index 9b02bd9..75a89e9 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1,5 +1,6 @@ -#include "WebRTCLibPeer.hpp" -#include "net/WebRTCPeerNative.hpp" +#include "WebRTCLibDataChannel.hpp" +#include "WebRTCLibPeerConnection.hpp" +#include "net/WebRTCPeerConnectionNative.hpp" #include <gdnative_api_struct.gen.h> /* Godot export stuff */ @@ -16,7 +17,7 @@ extern "C" void GDN_EXPORT godot_gdnative_init(godot_gdnative_init_options *o) { break; if (net_api->next->version.major == 3 && net_api->next->version.minor == 2) { - WebRTCPeerNative::_net_api = (const godot_gdnative_ext_net_3_2_api_struct *)net_api->next; + WebRTCPeerConnectionNative::_net_api = (const godot_gdnative_ext_net_3_2_api_struct *)net_api->next; } } @@ -30,5 +31,6 @@ extern "C" void GDN_EXPORT godot_gdnative_terminate(godot_gdnative_terminate_opt extern "C" void GDN_EXPORT godot_nativescript_init(void *handle) { godot::Godot::nativescript_init(handle); - godot::register_class<godot_webrtc::WebRTCLibPeer>(); + godot::register_class<godot_webrtc::WebRTCLibPeerConnection>(); + godot::register_class<godot_webrtc::WebRTCLibDataChannel>(); } diff --git a/src/net/WebRTCDataChannelNative.cpp b/src/net/WebRTCDataChannelNative.cpp new file mode 100644 index 0000000..8e1d3b1 --- /dev/null +++ b/src/net/WebRTCDataChannelNative.cpp @@ -0,0 +1,92 @@ +#include "WebRTCDataChannelNative.hpp" +#include "net/WebRTCPeerConnectionNative.hpp" + +void WebRTCDataChannelNative::register_interface(const godot_net_webrtc_data_channel *p_interface) { + ERR_FAIL_COND(!WebRTCPeerConnectionNative::_net_api); + WebRTCPeerConnectionNative::_net_api->godot_net_bind_webrtc_data_channel(_owner, p_interface); +} + +void WebRTCDataChannelNative::_register_methods() {} + +void WebRTCDataChannelNative::_init() { + register_interface(&interface); +} + +WebRTCDataChannelNative::~WebRTCDataChannelNative() { + if (_owner) { + register_interface(NULL); + } +} + +/* + * The C interface that implements WebRTCDataChannel. + * In this case it forwards calls to our C++ class, but could be plain C, + * and you could use void *user for any kind of state struct pointer you have. + */ +godot_error get_packet_wdc(void *user, const uint8_t **r_buffer, int *r_len) { + return ((WebRTCDataChannelNative *)user)->get_packet(r_buffer, r_len); +} + +godot_error put_packet_wdc(void *user, const uint8_t *p_buffer, int p_len) { + return ((WebRTCDataChannelNative *)user)->put_packet(p_buffer, p_len); +} + +godot_int get_available_packet_count_wdc(const void *user) { + return ((WebRTCDataChannelNative *)user)->get_available_packet_count(); +} + +godot_int get_max_packet_size_wdc(const void *user) { + return ((WebRTCDataChannelNative *)user)->get_max_packet_size(); +} + +void set_write_mode_wdc(void *user, godot_int write_mode) { + ((WebRTCDataChannelNative *)user)->set_write_mode(write_mode); +} + +godot_int get_write_mode_wdc(const void *user) { + return ((WebRTCDataChannelNative *)user)->get_write_mode(); +} + +bool was_string_packet_wdc(const void *user) { + return ((WebRTCDataChannelNative *)user)->was_string_packet(); +} + +godot_int get_ready_state_wdc(const void *user) { + return (godot_int)(((WebRTCDataChannelNative *)user)->get_ready_state()); +} + +const char *get_label_wdc(const void *user) { + return ((WebRTCDataChannelNative *)user)->get_label(); +} + +bool is_ordered_wdc(const void *user) { + return ((WebRTCDataChannelNative *)user)->is_ordered(); +} + +int get_id_wdc(const void *user) { + return ((WebRTCDataChannelNative *)user)->get_id(); +} + +int get_max_packet_life_time_wdc(const void *user) { + return ((WebRTCDataChannelNative *)user)->get_max_packet_life_time(); +} + +int get_max_retransmits_wdc(const void *user) { + return ((WebRTCDataChannelNative *)user)->get_max_retransmits(); +} + +const char *get_protocol_wdc(const void *user) { + return ((WebRTCDataChannelNative *)user)->get_protocol(); +} + +bool is_negotiated_wdc(const void *user) { + return ((WebRTCDataChannelNative *)user)->is_negotiated(); +} + +godot_error poll_wdc(void *user) { + return ((WebRTCDataChannelNative *)user)->poll(); +} + +void close_wdc(void *user) { + ((WebRTCDataChannelNative *)user)->close(); +} diff --git a/src/net/WebRTCDataChannelNative.hpp b/src/net/WebRTCDataChannelNative.hpp new file mode 100644 index 0000000..eaeb95d --- /dev/null +++ b/src/net/WebRTCDataChannelNative.hpp @@ -0,0 +1,91 @@ +#ifndef WEBRTC_DATA_CHANNEL_NATIVE +#define WEBRTC_DATA_CHANNEL_NATIVE + +#include <Godot.hpp> +#include <Reference.hpp> +#include <WebRTCDataChannelGDNative.hpp> + +#include <net/godot_net.h> + +/* Forward declare interface functions */ +godot_error get_packet_wdc(void *, const uint8_t **, int *); +godot_error put_packet_wdc(void *, const uint8_t *, int); +godot_int get_available_packet_count_wdc(const void *); +godot_int get_max_packet_size_wdc(const void *); + +void set_write_mode_wdc(void *, godot_int); +godot_int get_write_mode_wdc(const void *); +bool was_string_packet_wdc(const void *); +godot_int get_ready_state_wdc(const void *); +const char *get_label_wdc(const void *); +bool is_ordered_wdc(const void *); +int get_id_wdc(const void *); +int get_max_packet_life_time_wdc(const void *); +int get_max_retransmits_wdc(const void *); +const char *get_protocol_wdc(const void *); +bool is_negotiated_wdc(const void *); +godot_error poll_wdc(void *); +void close_wdc(void *); + +class WebRTCDataChannelNative : public godot::WebRTCDataChannelGDNative { + GODOT_CLASS(WebRTCDataChannelNative, godot::WebRTCDataChannelGDNative); + +protected: + godot_net_webrtc_data_channel interface = { + { 3, 1 }, + this, + + &get_packet_wdc, + &put_packet_wdc, + &get_available_packet_count_wdc, + &get_max_packet_size_wdc, + + &set_write_mode_wdc, + &get_write_mode_wdc, + &was_string_packet_wdc, + &get_ready_state_wdc, + &get_label_wdc, + &is_ordered_wdc, + &get_id_wdc, + &get_max_packet_life_time_wdc, + &get_max_retransmits_wdc, + &get_protocol_wdc, + &is_negotiated_wdc, + + &poll_wdc, + &close_wdc, + NULL, + }; + +public: + static void _register_methods(); + + void _init(); + void register_interface(const godot_net_webrtc_data_channel *interface); + + virtual void set_write_mode(godot_int mode) = 0; + virtual godot_int get_write_mode() const = 0; + virtual bool was_string_packet() const = 0; + + virtual ChannelState get_ready_state() const = 0; + virtual const char *get_label() const = 0; + virtual bool is_ordered() const = 0; + virtual int get_id() const = 0; + virtual int get_max_packet_life_time() const = 0; + virtual int get_max_retransmits() const = 0; + virtual const char *get_protocol() const = 0; + virtual bool is_negotiated() const = 0; + + virtual godot_error poll() = 0; + virtual void close() = 0; + + /* PacketPeer */ + virtual godot_error get_packet(const uint8_t **r_buffer, int *r_len) = 0; + virtual godot_error put_packet(const uint8_t *p_buffer, int p_len) = 0; + virtual godot_int get_available_packet_count() const = 0; + virtual godot_int get_max_packet_size() const = 0; + + ~WebRTCDataChannelNative(); +}; + +#endif // WEBRTC_DATA_CHANNEL_NATIVE diff --git a/src/net/WebRTCPeerConnectionNative.cpp b/src/net/WebRTCPeerConnectionNative.cpp new file mode 100644 index 0000000..5f7d83e --- /dev/null +++ b/src/net/WebRTCPeerConnectionNative.cpp @@ -0,0 +1,65 @@ +#include "WebRTCPeerConnectionNative.hpp" + +const godot_gdnative_ext_net_3_2_api_struct *WebRTCPeerConnectionNative::_net_api = NULL; + +void WebRTCPeerConnectionNative::register_interface(const godot_net_webrtc_peer_connection *p_interface) { + ERR_FAIL_COND(!_net_api); + _net_api->godot_net_bind_webrtc_peer_connection(_owner, p_interface); +} + +void WebRTCPeerConnectionNative::_register_methods() {} + +void WebRTCPeerConnectionNative::_init() { + register_interface(&interface); +} + +WebRTCPeerConnectionNative::~WebRTCPeerConnectionNative() { + if (_owner) { + register_interface(NULL); + } +} + +/* + * The C interface that implements WebRTCPeerConnection. + * In this case it forwards calls to our C++ class, but could be plain C, + * and you could use void *user for any kind of state struct pointer you have. + */ +godot_int get_connection_state_wp(const void *user) { + return (godot_int)((WebRTCPeerConnectionNative *)user)->get_connection_state(); +} + +godot_error initialize_wp(void *user, const godot_dictionary *p_config) { + return ((WebRTCPeerConnectionNative *)user)->initialize(p_config); +} + +godot_object *create_data_channel_wp(void *user, const char *p_channel, const godot_dictionary *p_channel_config) { + return ((WebRTCPeerConnectionNative *)user)->create_data_channel(p_channel, p_channel_config); +} + +godot_error create_offer_wp(void *user) { + return ((WebRTCPeerConnectionNative *)user)->create_offer(); +} + +godot_error create_answer_wp(void *user) { + return GODOT_ERR_UNAVAILABLE; // Not implemented, not used yet. +} + +godot_error set_remote_description_wp(void *user, const char *type, const char *sdp) { + return ((WebRTCPeerConnectionNative *)user)->set_remote_description(type, sdp); +} + +godot_error set_local_description_wp(void *user, const char *type, const char *sdp) { + return ((WebRTCPeerConnectionNative *)user)->set_local_description(type, sdp); +} + +godot_error add_ice_candidate_wp(void *user, const char *sdpMidName, int sdpMlineIndexName, const char *sdpName) { + return ((WebRTCPeerConnectionNative *)user)->add_ice_candidate(sdpMidName, sdpMlineIndexName, sdpName); +} + +godot_error poll_wp(void *user) { + return ((WebRTCPeerConnectionNative *)user)->poll(); +} + +void close_wp(void *user) { + ((WebRTCPeerConnectionNative *)user)->close(); +} diff --git a/src/net/WebRTCPeerConnectionNative.hpp b/src/net/WebRTCPeerConnectionNative.hpp new file mode 100644 index 0000000..3b0ac79 --- /dev/null +++ b/src/net/WebRTCPeerConnectionNative.hpp @@ -0,0 +1,66 @@ +#ifndef WEBRTC_PEER_NATIVE +#define WEBRTC_PEER_NATIVE + +#include <Godot.hpp> +#include <Reference.hpp> +#include <WebRTCPeerConnectionGDNative.hpp> + +#include <net/godot_net.h> + +/* Forward declare interface functions */ +godot_int get_connection_state_wp(const void *); + +godot_error initialize_wp(void *, const godot_dictionary *); +godot_object *create_data_channel_wp(void *, const char *, const godot_dictionary *); +godot_error create_offer_wp(void *); +godot_error create_answer_wp(void *); +godot_error set_remote_description_wp(void *, const char *, const char *); +godot_error set_local_description_wp(void *, const char *, const char *); +godot_error add_ice_candidate_wp(void *, const char *, int, const char *); +godot_error poll_wp(void *); +void close_wp(void *); + +class WebRTCPeerConnectionNative : public godot::WebRTCPeerConnectionGDNative { + GODOT_CLASS(WebRTCPeerConnectionNative, godot::WebRTCPeerConnectionGDNative); + +protected: + godot_net_webrtc_peer_connection interface = { + { 3, 1 }, + this, + + &get_connection_state_wp, + + &initialize_wp, + &create_data_channel_wp, + &create_offer_wp, + &create_answer_wp, + &set_remote_description_wp, + &set_local_description_wp, + &add_ice_candidate_wp, + &poll_wp, + &close_wp, + NULL, + }; + +public: + static void _register_methods(); + static const godot_gdnative_ext_net_3_2_api_struct *_net_api; + + void _init(); + void register_interface(const godot_net_webrtc_peer_connection *interface); + + virtual ConnectionState get_connection_state() const = 0; + + virtual godot_error initialize(const godot_dictionary *p_config) = 0; + virtual godot_object *create_data_channel(const char *p_channel, const godot_dictionary *p_channel_config) = 0; + virtual godot_error create_offer() = 0; + virtual godot_error set_remote_description(const char *type, const char *sdp) = 0; + virtual godot_error set_local_description(const char *type, const char *sdp) = 0; + virtual godot_error add_ice_candidate(const char *sdpMidName, int sdpMlineIndexName, const char *sdpName) = 0; + virtual godot_error poll() = 0; + virtual void close() = 0; + + ~WebRTCPeerConnectionNative(); +}; + +#endif // WEBRTC_PEER_NATIVE diff --git a/src/net/WebRTCPeerNative.cpp b/src/net/WebRTCPeerNative.cpp deleted file mode 100644 index a0872bc..0000000 --- a/src/net/WebRTCPeerNative.cpp +++ /dev/null @@ -1,77 +0,0 @@ -#include "WebRTCPeerNative.hpp" - -const godot_gdnative_ext_net_3_2_api_struct *WebRTCPeerNative::_net_api = NULL; - -void WebRTCPeerNative::register_interface(const godot_net_webrtc_peer *p_interface) { - ERR_FAIL_COND(!_net_api); - _net_api->godot_net_bind_webrtc_peer(_owner, p_interface); -} - -void WebRTCPeerNative::_register_methods() {} - -void WebRTCPeerNative::_init() { - register_interface(&interface); -} - -WebRTCPeerNative::~WebRTCPeerNative() { - if (_owner) { - register_interface(NULL); - } -} - -/* - * The C interface that implements WebRTCPeer. - * In this case it forwards calls to our C++ class, but could be plain C, - * and you could use void *user for any kind of state struct pointer you have. - */ -godot_error get_packet_wp(void *user, const uint8_t **r_buffer, int *r_len) { - return ((WebRTCPeerNative *)user)->get_packet(r_buffer, r_len); -} - -godot_error put_packet_wp(void *user, const uint8_t *p_buffer, int p_len) { - return ((WebRTCPeerNative *)user)->put_packet(p_buffer, p_len); -} - -godot_int get_available_packet_count_wp(const void *user) { - return ((WebRTCPeerNative *)user)->get_available_packet_count(); -} - -godot_int get_max_packet_size_wp(const void *user) { - return ((WebRTCPeerNative *)user)->get_max_packet_size(); -} - -void set_write_mode_wp(void *user, godot_int write_mode) { - ((WebRTCPeerNative *)user)->set_write_mode(write_mode); -} - -godot_int get_write_mode_wp(const void *user) { - return ((WebRTCPeerNative *)user)->get_write_mode(); -} - -bool was_string_packet_wp(const void *user) { - return ((WebRTCPeerNative *)user)->was_string_packet(); -} - -godot_int get_connection_state_wp(const void *user) { - return ((WebRTCPeerNative *)user)->get_connection_state(); -} - -godot_error create_offer_wp(void *user) { - return ((WebRTCPeerNative *)user)->create_offer(); -} - -godot_error set_remote_description_wp(void *user, const char *type, const char *sdp) { - return ((WebRTCPeerNative *)user)->set_remote_description(type, sdp); -} - -godot_error set_local_description_wp(void *user, const char *type, const char *sdp) { - return ((WebRTCPeerNative *)user)->set_local_description(type, sdp); -} - -godot_error add_ice_candidate_wp(void *user, const char *sdpMidName, int sdpMlineIndexName, const char *sdpName) { - return ((WebRTCPeerNative *)user)->add_ice_candidate(sdpMidName, sdpMlineIndexName, sdpName); -} - -godot_error poll_wp(void *user) { - return ((WebRTCPeerNative *)user)->poll(); -} diff --git a/src/net/WebRTCPeerNative.hpp b/src/net/WebRTCPeerNative.hpp deleted file mode 100644 index d5f2c6f..0000000 --- a/src/net/WebRTCPeerNative.hpp +++ /dev/null @@ -1,80 +0,0 @@ -#ifndef WEBRTC_PEER_NATIVE -#define WEBRTC_PEER_NATIVE - -#include <Godot.hpp> -#include <Reference.hpp> -#include <WebRTCPeerGDNative.hpp> - -#include <net/godot_net.h> - -/* Forward declare interface functions */ -godot_error get_packet_wp(void *, const uint8_t **, int *); -godot_error put_packet_wp(void *, const uint8_t *, int); -godot_int get_available_packet_count_wp(const void *); -godot_int get_max_packet_size_wp(const void *); - -void set_write_mode_wp(void *, godot_int); -godot_int get_write_mode_wp(const void *); -bool was_string_packet_wp(const void *); -godot_int get_connection_state_wp(const void *); - -godot_error create_offer_wp(void *); -godot_error set_remote_description_wp(void *, const char *, const char *); -godot_error set_local_description_wp(void *, const char *, const char *); -godot_error add_ice_candidate_wp(void *, const char *, int, const char *); -godot_error poll_wp(void *); - -class WebRTCPeerNative : public godot::WebRTCPeerGDNative { - GODOT_CLASS(WebRTCPeerNative, godot::WebRTCPeerGDNative); - -protected: - godot_net_webrtc_peer interface = { - { 3, 1 }, - this, - - &get_packet_wp, - &put_packet_wp, - &get_available_packet_count_wp, - &get_max_packet_size_wp, - - &set_write_mode_wp, - &get_write_mode_wp, - &was_string_packet_wp, - &get_connection_state_wp, - - &create_offer_wp, - &set_remote_description_wp, - &set_local_description_wp, - &add_ice_candidate_wp, - &poll_wp, - NULL, - }; - -public: - static void _register_methods(); - static const godot_gdnative_ext_net_3_2_api_struct *_net_api; - - void _init(); - void register_interface(const godot_net_webrtc_peer *interface); - - virtual void set_write_mode(godot_int mode) = 0; - virtual godot_int get_write_mode() const = 0; - virtual bool was_string_packet() const = 0; - virtual godot_int get_connection_state() const = 0; - - virtual godot_error create_offer() = 0; - virtual godot_error set_remote_description(const char *type, const char *sdp) = 0; - virtual godot_error set_local_description(const char *type, const char *sdp) = 0; - virtual godot_error add_ice_candidate(const char *sdpMidName, int sdpMlineIndexName, const char *sdpName) = 0; - virtual godot_error poll() = 0; - - /* PacketPeer */ - virtual godot_error get_packet(const uint8_t **r_buffer, int *r_len) = 0; - virtual godot_error put_packet(const uint8_t *p_buffer, int p_len) = 0; - virtual godot_int get_available_packet_count() const = 0; - virtual godot_int get_max_packet_size() const = 0; - - ~WebRTCPeerNative(); -}; - -#endif // WEBRTC_PEER_NATIVE |