diff options
Diffstat (limited to 'modules/webrtc')
25 files changed, 851 insertions, 600 deletions
diff --git a/modules/webrtc/SCsub b/modules/webrtc/SCsub index 31b8a73bf2..e6b9959840 100644 --- a/modules/webrtc/SCsub +++ b/modules/webrtc/SCsub @@ -4,11 +4,6 @@ Import("env") Import("env_modules") 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"]) - env_webrtc.Prepend(CPPPATH=["#modules/gdnative/include/"]) if env["platform"] == "javascript": # Our JavaScript/C++ interface. diff --git a/modules/webrtc/config.py b/modules/webrtc/config.py index 0a075ccef1..4ad918833a 100644 --- a/modules/webrtc/config.py +++ b/modules/webrtc/config.py @@ -10,7 +10,9 @@ def get_doc_classes(): return [ "WebRTCPeerConnection", "WebRTCDataChannel", - "WebRTCMultiplayer", + "WebRTCMultiplayerPeer", + "WebRTCPeerConnectionExtension", + "WebRTCDataChannelExtension", ] diff --git a/modules/webrtc/doc_classes/WebRTCDataChannel.xml b/modules/webrtc/doc_classes/WebRTCDataChannel.xml index 5c90038b9a..cf5735bab5 100644 --- a/modules/webrtc/doc_classes/WebRTCDataChannel.xml +++ b/modules/webrtc/doc_classes/WebRTCDataChannel.xml @@ -8,81 +8,76 @@ </tutorials> <methods> <method name="close"> - <return type="void"> - </return> + <return type="void" /> <description> Closes this data channel, notifying the other peer. </description> </method> + <method name="get_buffered_amount" qualifiers="const"> + <return type="int" /> + <description> + Returns the number of bytes currently queued to be sent over this channel. + </description> + </method> <method name="get_id" qualifiers="const"> - <return type="int"> - </return> + <return type="int" /> <description> Returns the id assigned to this channel during creation (or auto-assigned during negotiation). If the channel is not negotiated out-of-band the id will only be available after the connection is established (will return [code]65535[/code] until then). </description> </method> <method name="get_label" qualifiers="const"> - <return type="String"> - </return> + <return type="String" /> <description> Returns the label assigned to this channel during creation. </description> </method> <method name="get_max_packet_life_time" qualifiers="const"> - <return type="int"> - </return> + <return type="int" /> <description> Returns the [code]maxPacketLifeTime[/code] value assigned to this channel during creation. Will be [code]65535[/code] if not specified. </description> </method> <method name="get_max_retransmits" qualifiers="const"> - <return type="int"> - </return> + <return type="int" /> <description> Returns the [code]maxRetransmits[/code] value assigned to this channel during creation. Will be [code]65535[/code] if not specified. </description> </method> <method name="get_protocol" qualifiers="const"> - <return type="String"> - </return> + <return type="String" /> <description> Returns the sub-protocol assigned to this channel during creation. An empty string if not specified. </description> </method> <method name="get_ready_state" qualifiers="const"> - <return type="int" enum="WebRTCDataChannel.ChannelState"> - </return> + <return type="int" enum="WebRTCDataChannel.ChannelState" /> <description> Returns the current state of this channel, see [enum ChannelState]. </description> </method> <method name="is_negotiated" qualifiers="const"> - <return type="bool"> - </return> + <return type="bool" /> <description> Returns [code]true[/code] if this channel was created with out-of-band configuration. </description> </method> <method name="is_ordered" qualifiers="const"> - <return type="bool"> - </return> + <return type="bool" /> <description> Returns [code]true[/code] if this channel was created with ordering enabled (default). </description> </method> <method name="poll"> - <return type="int" enum="Error"> - </return> + <return type="int" enum="Error" /> <description> Reserved, but not used for now. </description> </method> <method name="was_string_packet" qualifiers="const"> - <return type="bool"> - </return> + <return type="bool" /> <description> Returns [code]true[/code] if the last received packet was transferred as text. See [member write_mode]. </description> diff --git a/modules/webrtc/doc_classes/WebRTCDataChannelExtension.xml b/modules/webrtc/doc_classes/WebRTCDataChannelExtension.xml new file mode 100644 index 0000000000..746fabd6e5 --- /dev/null +++ b/modules/webrtc/doc_classes/WebRTCDataChannelExtension.xml @@ -0,0 +1,106 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="WebRTCDataChannelExtension" inherits="WebRTCDataChannel" version="4.0"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <methods> + <method name="_close" qualifiers="virtual"> + <return type="void" /> + <description> + </description> + </method> + <method name="_get_available_packet_count" qualifiers="virtual const"> + <return type="int" /> + <description> + </description> + </method> + <method name="_get_buffered_amount" qualifiers="virtual const"> + <return type="int" /> + <description> + </description> + </method> + <method name="_get_id" qualifiers="virtual const"> + <return type="int" /> + <description> + </description> + </method> + <method name="_get_label" qualifiers="virtual const"> + <return type="String" /> + <description> + </description> + </method> + <method name="_get_max_packet_life_time" qualifiers="virtual const"> + <return type="int" /> + <description> + </description> + </method> + <method name="_get_max_packet_size" qualifiers="virtual const"> + <return type="int" /> + <description> + </description> + </method> + <method name="_get_max_retransmits" qualifiers="virtual const"> + <return type="int" /> + <description> + </description> + </method> + <method name="_get_packet" qualifiers="virtual"> + <return type="int" /> + <argument index="0" name="r_buffer" type="const uint8_t **" /> + <argument index="1" name="r_buffer_size" type="int32_t*" /> + <description> + </description> + </method> + <method name="_get_protocol" qualifiers="virtual const"> + <return type="String" /> + <description> + </description> + </method> + <method name="_get_ready_state" qualifiers="virtual const"> + <return type="int" /> + <description> + </description> + </method> + <method name="_get_write_mode" qualifiers="virtual const"> + <return type="int" /> + <description> + </description> + </method> + <method name="_is_negotiated" qualifiers="virtual const"> + <return type="bool" /> + <description> + </description> + </method> + <method name="_is_ordered" qualifiers="virtual const"> + <return type="bool" /> + <description> + </description> + </method> + <method name="_poll" qualifiers="virtual"> + <return type="int" /> + <description> + </description> + </method> + <method name="_put_packet" qualifiers="virtual"> + <return type="int" /> + <argument index="0" name="p_buffer" type="const uint8_t*" /> + <argument index="1" name="p_buffer_size" type="int" /> + <description> + </description> + </method> + <method name="_set_write_mode" qualifiers="virtual"> + <return type="void" /> + <argument index="0" name="p_write_mode" type="int" /> + <description> + </description> + </method> + <method name="_was_string_packet" qualifiers="virtual const"> + <return type="bool" /> + <description> + </description> + </method> + </methods> +</class> diff --git a/modules/webrtc/doc_classes/WebRTCMultiplayer.xml b/modules/webrtc/doc_classes/WebRTCMultiplayerPeer.xml index 5b9459bc27..a8360a4d45 100644 --- a/modules/webrtc/doc_classes/WebRTCMultiplayer.xml +++ b/modules/webrtc/doc_classes/WebRTCMultiplayerPeer.xml @@ -1,89 +1,71 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="WebRTCMultiplayer" inherits="NetworkedMultiplayerPeer" version="4.0"> +<class name="WebRTCMultiplayerPeer" inherits="MultiplayerPeer" version="4.0"> <brief_description> A simple interface to create a peer-to-peer mesh network composed of [WebRTCPeerConnection] that is compatible with the [MultiplayerAPI]. </brief_description> <description> - This class constructs a full mesh of [WebRTCPeerConnection] (one connection for each peer) that can be used as a [member MultiplayerAPI.network_peer]. + This class constructs a full mesh of [WebRTCPeerConnection] (one connection for each peer) that can be used as a [member MultiplayerAPI.multiplayer_peer]. You can add each [WebRTCPeerConnection] via [method add_peer] or remove them via [method remove_peer]. Peers must be added in [constant WebRTCPeerConnection.STATE_NEW] state to allow it to create the appropriate channels. This class will not create offers nor set descriptions, it will only poll them, and notify connections and disconnections. - [signal NetworkedMultiplayerPeer.connection_succeeded] and [signal NetworkedMultiplayerPeer.server_disconnected] will not be emitted unless [code]server_compatibility[/code] is [code]true[/code] in [method initialize]. Beside that data transfer works like in a [NetworkedMultiplayerPeer]. + [signal MultiplayerPeer.connection_succeeded] and [signal MultiplayerPeer.server_disconnected] will not be emitted unless [code]server_compatibility[/code] is [code]true[/code] in [method initialize]. Beside that data transfer works like in a [MultiplayerPeer]. + [b]Note:[/b] When exporting to Android, make sure to enable the [code]INTERNET[/code] permission in the Android export preset before exporting the project or using one-click deploy. Otherwise, network communication of any kind will be blocked by Android. </description> <tutorials> </tutorials> <methods> <method name="add_peer"> - <return type="int" enum="Error"> - </return> - <argument index="0" name="peer" type="WebRTCPeerConnection"> - </argument> - <argument index="1" name="peer_id" type="int"> - </argument> - <argument index="2" name="unreliable_lifetime" type="int" default="1"> - </argument> + <return type="int" enum="Error" /> + <argument index="0" name="peer" type="WebRTCPeerConnection" /> + <argument index="1" name="peer_id" type="int" /> + <argument index="2" name="unreliable_lifetime" type="int" default="1" /> <description> Add a new peer to the mesh with the given [code]peer_id[/code]. The [WebRTCPeerConnection] must be in state [constant WebRTCPeerConnection.STATE_NEW]. Three channels will be created for reliable, unreliable, and ordered transport. The value of [code]unreliable_lifetime[/code] will be passed to the [code]maxPacketLifetime[/code] option when creating unreliable and ordered channels (see [method WebRTCPeerConnection.create_data_channel]). </description> </method> <method name="close"> - <return type="void"> - </return> + <return type="void" /> <description> Close all the add peer connections and channels, freeing all resources. </description> </method> <method name="get_peer"> - <return type="Dictionary"> - </return> - <argument index="0" name="peer_id" type="int"> - </argument> + <return type="Dictionary" /> + <argument index="0" name="peer_id" type="int" /> <description> Return a dictionary representation of the peer with given [code]peer_id[/code] with three keys. [code]connection[/code] containing the [WebRTCPeerConnection] to this peer, [code]channels[/code] an array of three [WebRTCDataChannel], and [code]connected[/code] a boolean representing if the peer connection is currently connected (all three channels are open). </description> </method> <method name="get_peers"> - <return type="Dictionary"> - </return> + <return type="Dictionary" /> <description> Returns a dictionary which keys are the peer ids and values the peer representation as in [method get_peer]. </description> </method> <method name="has_peer"> - <return type="bool"> - </return> - <argument index="0" name="peer_id" type="int"> - </argument> + <return type="bool" /> + <argument index="0" name="peer_id" type="int" /> <description> Returns [code]true[/code] if the given [code]peer_id[/code] is in the peers map (it might not be connected though). </description> </method> <method name="initialize"> - <return type="int" enum="Error"> - </return> - <argument index="0" name="peer_id" type="int"> - </argument> - <argument index="1" name="server_compatibility" type="bool" default="false"> - </argument> + <return type="int" enum="Error" /> + <argument index="0" name="peer_id" type="int" /> + <argument index="1" name="server_compatibility" type="bool" default="false" /> + <argument index="2" name="channels_config" type="Array" default="[]" /> <description> Initialize the multiplayer peer with the given [code]peer_id[/code] (must be between 1 and 2147483647). - If [code]server_compatibilty[/code] is [code]false[/code] (default), the multiplayer peer will be immediately in state [constant NetworkedMultiplayerPeer.CONNECTION_CONNECTED] and [signal NetworkedMultiplayerPeer.connection_succeeded] will not be emitted. - If [code]server_compatibilty[/code] is [code]true[/code] the peer will suppress all [signal NetworkedMultiplayerPeer.peer_connected] signals until a peer with id [constant NetworkedMultiplayerPeer.TARGET_PEER_SERVER] connects and then emit [signal NetworkedMultiplayerPeer.connection_succeeded]. After that the signal [signal NetworkedMultiplayerPeer.peer_connected] will be emitted for every already connected peer, and any new peer that might connect. If the server peer disconnects after that, signal [signal NetworkedMultiplayerPeer.server_disconnected] will be emitted and state will become [constant NetworkedMultiplayerPeer.CONNECTION_CONNECTED]. + If [code]server_compatibilty[/code] is [code]false[/code] (default), the multiplayer peer will be immediately in state [constant MultiplayerPeer.CONNECTION_CONNECTED] and [signal MultiplayerPeer.connection_succeeded] will not be emitted. + If [code]server_compatibilty[/code] is [code]true[/code] the peer will suppress all [signal MultiplayerPeer.peer_connected] signals until a peer with id [constant MultiplayerPeer.TARGET_PEER_SERVER] connects and then emit [signal MultiplayerPeer.connection_succeeded]. After that the signal [signal MultiplayerPeer.peer_connected] will be emitted for every already connected peer, and any new peer that might connect. If the server peer disconnects after that, signal [signal MultiplayerPeer.server_disconnected] will be emitted and state will become [constant MultiplayerPeer.CONNECTION_CONNECTED]. + You can optionally specify a [code]channels_config[/code] array of [enum TransferMode] which will be used to create extra channels (WebRTC only supports one transfer mode per channel). </description> </method> <method name="remove_peer"> - <return type="void"> - </return> - <argument index="0" name="peer_id" type="int"> - </argument> + <return type="void" /> + <argument index="0" name="peer_id" type="int" /> <description> - Remove the peer with given [code]peer_id[/code] from the mesh. If the peer was connected, and [signal NetworkedMultiplayerPeer.peer_connected] was emitted for it, then [signal NetworkedMultiplayerPeer.peer_disconnected] will be emitted. + Remove the peer with given [code]peer_id[/code] from the mesh. If the peer was connected, and [signal MultiplayerPeer.peer_connected] was emitted for it, then [signal MultiplayerPeer.peer_disconnected] will be emitted. </description> </method> </methods> - <members> - <member name="refuse_new_connections" type="bool" setter="set_refuse_new_connections" getter="is_refusing_new_connections" override="true" default="false" /> - <member name="transfer_mode" type="int" setter="set_transfer_mode" getter="get_transfer_mode" override="true" enum="NetworkedMultiplayerPeer.TransferMode" default="2" /> - </members> - <constants> - </constants> </class> diff --git a/modules/webrtc/doc_classes/WebRTCPeerConnection.xml b/modules/webrtc/doc_classes/WebRTCPeerConnection.xml index e21dee8eff..f6f360503f 100644 --- a/modules/webrtc/doc_classes/WebRTCPeerConnection.xml +++ b/modules/webrtc/doc_classes/WebRTCPeerConnection.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="WebRTCPeerConnection" inherits="Reference" version="4.0"> +<class name="WebRTCPeerConnection" inherits="RefCounted" version="4.0"> <brief_description> Interface to a WebRTC peer connection. </brief_description> @@ -15,40 +15,32 @@ </tutorials> <methods> <method name="add_ice_candidate"> - <return type="int" enum="Error"> - </return> - <argument index="0" name="media" type="String"> - </argument> - <argument index="1" name="index" type="int"> - </argument> - <argument index="2" name="name" type="String"> - </argument> + <return type="int" enum="Error" /> + <argument index="0" name="media" type="String" /> + <argument index="1" name="index" type="int" /> + <argument index="2" name="name" type="String" /> <description> Add an ice candidate generated by a remote peer (and received over the signaling server). See [signal ice_candidate_created]. </description> </method> <method name="close"> - <return type="void"> - </return> + <return type="void" /> <description> Close the peer connection and all data channels associated with it. Note, you cannot reuse this object for a new connection unless you call [method initialize]. </description> </method> <method name="create_data_channel"> - <return type="WebRTCDataChannel"> - </return> - <argument index="0" name="label" type="String"> - </argument> + <return type="WebRTCDataChannel" /> + <argument index="0" name="label" type="String" /> <argument index="1" name="options" type="Dictionary" default="{ -}"> - </argument> +}" /> <description> Returns a new [WebRTCDataChannel] (or [code]null[/code] on failure) with given [code]label[/code] and optionally configured via the [code]options[/code] dictionary. This method can only be called when the connection is in state [constant STATE_NEW]. There are two ways to create a working data channel: either call [method create_data_channel] on only one of the peer and listen to [signal data_channel_received] on the other, or call [method create_data_channel] on both peers, with the same values, and the [code]negotiated[/code] option set to [code]true[/code]. Valid [code]options[/code] are: [codeblock] { - "negotiated": true, # When set to true (default off), means the channel is negotiated out of band. "id" must be set too. data_channel_received will not be called. + "negotiated": true, # When set to true (default off), means the channel is negotiated out of band. "id" must be set too. "data_channel_received" will not be called. "id": 1, # When "negotiated" is true this value must also be set to the same value on both peer. # Only one of maxRetransmits and maxPacketLifeTime can be specified, not both. They make the channel unreliable (but also better at real time). @@ -63,26 +55,22 @@ </description> </method> <method name="create_offer"> - <return type="int" enum="Error"> - </return> + <return type="int" enum="Error" /> <description> Creates a new SDP offer to start a WebRTC connection with a remote peer. At least one [WebRTCDataChannel] must have been created before calling this method. If this functions returns [constant OK], [signal session_description_created] will be called when the session is ready to be sent. </description> </method> <method name="get_connection_state" qualifiers="const"> - <return type="int" enum="WebRTCPeerConnection.ConnectionState"> - </return> + <return type="int" enum="WebRTCPeerConnection.ConnectionState" /> <description> Returns the connection state. See [enum ConnectionState]. </description> </method> <method name="initialize"> - <return type="int" enum="Error"> - </return> + <return type="int" enum="Error" /> <argument index="0" name="configuration" type="Dictionary" default="{ -}"> - </argument> +}" /> <description> Re-initialize this peer connection, closing any previously active connection, and going back to state [constant STATE_NEW]. A dictionary of [code]options[/code] can be passed to configure the peer connection. Valid [code]options[/code] are: @@ -103,31 +91,24 @@ </description> </method> <method name="poll"> - <return type="int" enum="Error"> - </return> + <return type="int" enum="Error" /> <description> Call this method frequently (e.g. in [method Node._process] or [method Node._physics_process]) to properly receive signals. </description> </method> <method name="set_local_description"> - <return type="int" enum="Error"> - </return> - <argument index="0" name="type" type="String"> - </argument> - <argument index="1" name="sdp" type="String"> - </argument> + <return type="int" enum="Error" /> + <argument index="0" name="type" type="String" /> + <argument index="1" name="sdp" type="String" /> <description> Sets the SDP description of the local peer. This should be called in response to [signal session_description_created]. After calling this function the peer will start emitting [signal ice_candidate_created] (unless an [enum Error] different from [constant OK] is returned). </description> </method> <method name="set_remote_description"> - <return type="int" enum="Error"> - </return> - <argument index="0" name="type" type="String"> - </argument> - <argument index="1" name="sdp" type="String"> - </argument> + <return type="int" enum="Error" /> + <argument index="0" name="type" type="String" /> + <argument index="1" name="sdp" type="String" /> <description> Sets the SDP description of the remote peer. This should be called with the values generated by a remote peer and received over the signaling server. If [code]type[/code] is [code]offer[/code] the peer will emit [signal session_description_created] with the appropriate answer. @@ -137,29 +118,23 @@ </methods> <signals> <signal name="data_channel_received"> - <argument index="0" name="channel" type="Object"> - </argument> + <argument index="0" name="channel" type="Object" /> <description> Emitted when a new in-band channel is received, i.e. when the channel was created with [code]negotiated: false[/code] (default). The object will be an instance of [WebRTCDataChannel]. You must keep a reference of it or it will be closed automatically. See [method create_data_channel]. </description> </signal> <signal name="ice_candidate_created"> - <argument index="0" name="media" type="String"> - </argument> - <argument index="1" name="index" type="int"> - </argument> - <argument index="2" name="name" type="String"> - </argument> + <argument index="0" name="media" type="String" /> + <argument index="1" name="index" type="int" /> + <argument index="2" name="name" type="String" /> <description> Emitted when a new ICE candidate has been created. The three parameters are meant to be passed to the remote peer over the signaling server. </description> </signal> <signal name="session_description_created"> - <argument index="0" name="type" type="String"> - </argument> - <argument index="1" name="sdp" type="String"> - </argument> + <argument index="0" name="type" type="String" /> + <argument index="1" name="sdp" type="String" /> <description> Emitted after a successful call to [method create_offer] or [method set_remote_description] (when it generates an answer). The parameters are meant to be passed to [method set_local_description] on this object, and sent to the remote peer over the signaling server. </description> diff --git a/modules/webrtc/doc_classes/WebRTCPeerConnectionExtension.xml b/modules/webrtc/doc_classes/WebRTCPeerConnectionExtension.xml new file mode 100644 index 0000000000..d296fcd6e7 --- /dev/null +++ b/modules/webrtc/doc_classes/WebRTCPeerConnectionExtension.xml @@ -0,0 +1,71 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="WebRTCPeerConnectionExtension" inherits="WebRTCPeerConnection" version="4.0"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <methods> + <method name="_add_ice_candidate" qualifiers="virtual"> + <return type="int" /> + <argument index="0" name="p_sdp_mid_name" type="String" /> + <argument index="1" name="p_sdp_mline_index" type="int" /> + <argument index="2" name="p_sdp_name" type="String" /> + <description> + </description> + </method> + <method name="_close" qualifiers="virtual"> + <return type="void" /> + <description> + </description> + </method> + <method name="_create_data_channel" qualifiers="virtual"> + <return type="Object" /> + <argument index="0" name="p_label" type="String" /> + <argument index="1" name="p_config" type="Dictionary" /> + <description> + </description> + </method> + <method name="_create_offer" qualifiers="virtual"> + <return type="int" /> + <description> + </description> + </method> + <method name="_get_connection_state" qualifiers="virtual const"> + <return type="int" /> + <description> + </description> + </method> + <method name="_initialize" qualifiers="virtual"> + <return type="int" /> + <argument index="0" name="p_config" type="Dictionary" /> + <description> + </description> + </method> + <method name="_poll" qualifiers="virtual"> + <return type="int" /> + <description> + </description> + </method> + <method name="_set_local_description" qualifiers="virtual"> + <return type="int" /> + <argument index="0" name="p_type" type="String" /> + <argument index="1" name="p_sdp" type="String" /> + <description> + </description> + </method> + <method name="_set_remote_description" qualifiers="virtual"> + <return type="int" /> + <argument index="0" name="p_type" type="String" /> + <argument index="1" name="p_sdp" type="String" /> + <description> + </description> + </method> + <method name="make_default"> + <return type="void" /> + <description> + </description> + </method> + </methods> +</class> diff --git a/modules/webrtc/library_godot_webrtc.js b/modules/webrtc/library_godot_webrtc.js index 404a116716..a0a6c21be3 100644 --- a/modules/webrtc/library_godot_webrtc.js +++ b/modules/webrtc/library_godot_webrtc.js @@ -133,12 +133,12 @@ const GodotRTCDataChannel = { godot_js_rtc_datachannel_is_ordered__sig: 'ii', godot_js_rtc_datachannel_is_ordered: function (p_id) { - return IDHandler.get_prop(p_id, 'ordered', true); + return GodotRTCDataChannel.get_prop(p_id, 'ordered', true); }, godot_js_rtc_datachannel_id_get__sig: 'ii', godot_js_rtc_datachannel_id_get: function (p_id) { - return IDHandler.get_prop(p_id, 'id', 65535); + return GodotRTCDataChannel.get_prop(p_id, 'id', 65535); }, godot_js_rtc_datachannel_max_packet_lifetime_get__sig: 'ii', @@ -158,12 +158,17 @@ const GodotRTCDataChannel = { godot_js_rtc_datachannel_max_retransmits_get__sig: 'ii', godot_js_rtc_datachannel_max_retransmits_get: function (p_id) { - return IDHandler.get_prop(p_id, 'maxRetransmits', 65535); + return GodotRTCDataChannel.get_prop(p_id, 'maxRetransmits', 65535); }, godot_js_rtc_datachannel_is_negotiated__sig: 'ii', godot_js_rtc_datachannel_is_negotiated: function (p_id) { - return IDHandler.get_prop(p_id, 'negotiated', 65535); + return GodotRTCDataChannel.get_prop(p_id, 'negotiated', 65535); + }, + + godot_js_rtc_datachannel_get_buffered_amount__sig: 'ii', + godot_js_rtc_datachannel_get_buffered_amount: function (p_id) { + return GodotRTCDataChannel.get_prop(p_id, 'bufferedAmount', 0); }, godot_js_rtc_datachannel_label_get__sig: 'ii', diff --git a/modules/webrtc/register_types.cpp b/modules/webrtc/register_types.cpp index ecfaed9089..8110e4a048 100644 --- a/modules/webrtc/register_types.cpp +++ b/modules/webrtc/register_types.cpp @@ -31,17 +31,11 @@ #include "register_types.h" #include "core/config/project_settings.h" #include "webrtc_data_channel.h" +#include "webrtc_multiplayer_peer.h" #include "webrtc_peer_connection.h" -#ifdef JAVASCRIPT_ENABLED -#include "emscripten.h" -#include "webrtc_peer_connection_js.h" -#endif -#ifdef WEBRTC_GDNATIVE_ENABLED -#include "webrtc_data_channel_gdnative.h" -#include "webrtc_peer_connection_gdnative.h" -#endif -#include "webrtc_multiplayer.h" +#include "webrtc_data_channel_extension.h" +#include "webrtc_peer_connection_extension.h" void register_webrtc_types() { #define _SET_HINT(NAME, _VAL_, _MAX_) \ @@ -50,19 +44,13 @@ void register_webrtc_types() { _SET_HINT(WRTC_IN_BUF, 64, 4096); -#ifdef JAVASCRIPT_ENABLED - WebRTCPeerConnectionJS::make_default(); -#elif defined(WEBRTC_GDNATIVE_ENABLED) - WebRTCPeerConnectionGDNative::make_default(); -#endif - ClassDB::register_custom_instance_class<WebRTCPeerConnection>(); -#ifdef WEBRTC_GDNATIVE_ENABLED - ClassDB::register_class<WebRTCPeerConnectionGDNative>(); - ClassDB::register_class<WebRTCDataChannelGDNative>(); -#endif - ClassDB::register_virtual_class<WebRTCDataChannel>(); - ClassDB::register_class<WebRTCMultiplayer>(); + GDREGISTER_CLASS(WebRTCPeerConnectionExtension); + + GDREGISTER_VIRTUAL_CLASS(WebRTCDataChannel); + GDREGISTER_CLASS(WebRTCDataChannelExtension); + + GDREGISTER_CLASS(WebRTCMultiplayerPeer); } void unregister_webrtc_types() {} diff --git a/modules/webrtc/webrtc_data_channel.cpp b/modules/webrtc/webrtc_data_channel.cpp index 004112f992..ca520a733d 100644 --- a/modules/webrtc/webrtc_data_channel.cpp +++ b/modules/webrtc/webrtc_data_channel.cpp @@ -46,6 +46,7 @@ void WebRTCDataChannel::_bind_methods() { ClassDB::bind_method(D_METHOD("get_max_retransmits"), &WebRTCDataChannel::get_max_retransmits); ClassDB::bind_method(D_METHOD("get_protocol"), &WebRTCDataChannel::get_protocol); ClassDB::bind_method(D_METHOD("is_negotiated"), &WebRTCDataChannel::is_negotiated); + ClassDB::bind_method(D_METHOD("get_buffered_amount"), &WebRTCDataChannel::get_buffered_amount); ADD_PROPERTY(PropertyInfo(Variant::INT, "write_mode", PROPERTY_HINT_ENUM), "set_write_mode", "get_write_mode"); diff --git a/modules/webrtc/webrtc_data_channel.h b/modules/webrtc/webrtc_data_channel.h index 20affc513f..809d35c6e3 100644 --- a/modules/webrtc/webrtc_data_channel.h +++ b/modules/webrtc/webrtc_data_channel.h @@ -70,6 +70,8 @@ public: virtual String get_protocol() const = 0; virtual bool is_negotiated() const = 0; + virtual int get_buffered_amount() const = 0; + virtual Error poll() = 0; virtual void close() = 0; diff --git a/modules/webrtc/webrtc_data_channel_extension.cpp b/modules/webrtc/webrtc_data_channel_extension.cpp new file mode 100644 index 0000000000..ae346f6d8e --- /dev/null +++ b/modules/webrtc/webrtc_data_channel_extension.cpp @@ -0,0 +1,215 @@ +/*************************************************************************/ +/* webrtc_data_channel_extension.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 "webrtc_data_channel_extension.h" + +void WebRTCDataChannelExtension::_bind_methods() { + ADD_PROPERTY_DEFAULT("write_mode", WRITE_MODE_BINARY); + + GDVIRTUAL_BIND(_get_packet, "r_buffer", "r_buffer_size"); + GDVIRTUAL_BIND(_put_packet, "p_buffer", "p_buffer_size"); + GDVIRTUAL_BIND(_get_available_packet_count); + GDVIRTUAL_BIND(_get_max_packet_size); + + GDVIRTUAL_BIND(_poll); + GDVIRTUAL_BIND(_close); + + GDVIRTUAL_BIND(_set_write_mode, "p_write_mode"); + GDVIRTUAL_BIND(_get_write_mode); + + GDVIRTUAL_BIND(_was_string_packet); + GDVIRTUAL_BIND(_get_ready_state); + GDVIRTUAL_BIND(_get_label); + GDVIRTUAL_BIND(_is_ordered); + GDVIRTUAL_BIND(_get_id); + GDVIRTUAL_BIND(_get_max_packet_life_time); + GDVIRTUAL_BIND(_get_max_retransmits); + GDVIRTUAL_BIND(_get_protocol); + GDVIRTUAL_BIND(_is_negotiated); + GDVIRTUAL_BIND(_get_buffered_amount); +} + +int WebRTCDataChannelExtension::get_available_packet_count() const { + int count; + if (GDVIRTUAL_CALL(_get_available_packet_count, count)) { + return count; + } + WARN_PRINT_ONCE("WebRTCDataChannelExtension::_get_available_packet_count is unimplemented!"); + return -1; +} + +Error WebRTCDataChannelExtension::get_packet(const uint8_t **r_buffer, int &r_buffer_size) { + int err; + if (GDVIRTUAL_CALL(_get_packet, r_buffer, &r_buffer_size, err)) { + return (Error)err; + } + WARN_PRINT_ONCE("WebRTCDataChannelExtension::_get_packet_native is unimplemented!"); + return FAILED; +} + +Error WebRTCDataChannelExtension::put_packet(const uint8_t *p_buffer, int p_buffer_size) { + int err; + if (GDVIRTUAL_CALL(_put_packet, p_buffer, p_buffer_size, err)) { + return (Error)err; + } + WARN_PRINT_ONCE("WebRTCDataChannelExtension::_put_packet_native is unimplemented!"); + return FAILED; +} + +int WebRTCDataChannelExtension::get_max_packet_size() const { + int size; + if (GDVIRTUAL_CALL(_get_max_packet_size, size)) { + return size; + } + WARN_PRINT_ONCE("WebRTCDataChannelExtension::_get_max_packet_size is unimplemented!"); + return 0; +} + +Error WebRTCDataChannelExtension::poll() { + int err; + if (GDVIRTUAL_CALL(_poll, err)) { + return (Error)err; + } + WARN_PRINT_ONCE("WebRTCDataChannelExtension::_poll is unimplemented!"); + return ERR_UNCONFIGURED; +} + +void WebRTCDataChannelExtension::close() { + if (GDVIRTUAL_CALL(_close)) { + return; + } + WARN_PRINT_ONCE("WebRTCDataChannelExtension::_close is unimplemented!"); +} + +void WebRTCDataChannelExtension::set_write_mode(WriteMode p_mode) { + if (GDVIRTUAL_CALL(_set_write_mode, p_mode)) { + return; + } + WARN_PRINT_ONCE("WebRTCDataChannelExtension::_set_write_mode is unimplemented!"); +} + +WebRTCDataChannel::WriteMode WebRTCDataChannelExtension::get_write_mode() const { + int mode; + if (GDVIRTUAL_CALL(_get_write_mode, mode)) { + return (WriteMode)mode; + } + WARN_PRINT_ONCE("WebRTCDataChannelExtension::_get_write_mode is unimplemented!"); + return WRITE_MODE_BINARY; +} + +bool WebRTCDataChannelExtension::was_string_packet() const { + bool was_string; + if (GDVIRTUAL_CALL(_was_string_packet, was_string)) { + return was_string; + } + WARN_PRINT_ONCE("WebRTCDataChannelExtension::_was_string_packet is unimplemented!"); + return false; +} + +WebRTCDataChannel::ChannelState WebRTCDataChannelExtension::get_ready_state() const { + int state; + if (GDVIRTUAL_CALL(_get_ready_state, state)) { + return (ChannelState)state; + } + WARN_PRINT_ONCE("WebRTCDataChannelExtension::_get_ready_state is unimplemented!"); + return STATE_CLOSED; +} + +String WebRTCDataChannelExtension::get_label() const { + String label; + if (GDVIRTUAL_CALL(_get_label, label)) { + return label; + } + WARN_PRINT_ONCE("WebRTCDataChannelExtension::_get_label is unimplemented!"); + return label; +} + +bool WebRTCDataChannelExtension::is_ordered() const { + bool ordered; + if (GDVIRTUAL_CALL(_is_ordered, ordered)) { + return ordered; + } + WARN_PRINT_ONCE("WebRTCDataChannelExtension::_is_ordered is unimplemented!"); + return false; +} + +int WebRTCDataChannelExtension::get_id() const { + int id; + if (GDVIRTUAL_CALL(_get_id, id)) { + return id; + } + WARN_PRINT_ONCE("WebRTCDataChannelExtension::_get_id is unimplemented!"); + return -1; +} + +int WebRTCDataChannelExtension::get_max_packet_life_time() const { + int lifetime; + if (GDVIRTUAL_CALL(_get_max_packet_life_time, lifetime)) { + return lifetime; + } + WARN_PRINT_ONCE("WebRTCDataChannelExtension::_get_max_packet_life_time is unimplemented!"); + return -1; +} + +int WebRTCDataChannelExtension::get_max_retransmits() const { + int retransmits; + if (GDVIRTUAL_CALL(_get_max_retransmits, retransmits)) { + return retransmits; + } + WARN_PRINT_ONCE("WebRTCDataChannelExtension::_get_max_retransmits is unimplemented!"); + return -1; +} + +String WebRTCDataChannelExtension::get_protocol() const { + String protocol; + if (GDVIRTUAL_CALL(_get_protocol, protocol)) { + return protocol; + } + WARN_PRINT_ONCE("WebRTCDataChannelExtension::_get_protocol is unimplemented!"); + return protocol; +} + +bool WebRTCDataChannelExtension::is_negotiated() const { + bool negotiated; + if (GDVIRTUAL_CALL(_is_negotiated, negotiated)) { + return negotiated; + } + WARN_PRINT_ONCE("WebRTCDataChannelExtension::_is_negotiated is unimplemented!"); + return false; +} + +int WebRTCDataChannelExtension::get_buffered_amount() const { + int amount; + if (GDVIRTUAL_CALL(_get_buffered_amount, amount)) { + return amount; + } + WARN_PRINT_ONCE("WebRTCDataChannelExtension::_get_buffered_amount is unimplemented!"); + return -1; +} diff --git a/modules/webrtc/webrtc_data_channel_gdnative.h b/modules/webrtc/webrtc_data_channel_extension.h index 7e02a32046..eec96b4c62 100644 --- a/modules/webrtc/webrtc_data_channel_gdnative.h +++ b/modules/webrtc/webrtc_data_channel_extension.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* webrtc_data_channel_gdnative.h */ +/* webrtc_data_channel_extension.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,26 +28,22 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef WEBRTC_DATA_CHANNEL_GDNATIVE_H -#define WEBRTC_DATA_CHANNEL_GDNATIVE_H +#ifndef WEBRTC_DATA_CHANNEL_EXTENSION_H +#define WEBRTC_DATA_CHANNEL_EXTENSION_H -#ifdef WEBRTC_GDNATIVE_ENABLED - -#include "modules/gdnative/include/net/godot_net.h" #include "webrtc_data_channel.h" -class WebRTCDataChannelGDNative : public WebRTCDataChannel { - GDCLASS(WebRTCDataChannelGDNative, WebRTCDataChannel); +#include "core/object/gdvirtual.gen.inc" +#include "core/object/script_language.h" +#include "core/variant/native_ptr.h" + +class WebRTCDataChannelExtension : public WebRTCDataChannel { + GDCLASS(WebRTCDataChannelExtension, WebRTCDataChannel); protected: static void _bind_methods(); -private: - const godot_net_webrtc_data_channel *interface; - public: - void set_native_webrtc_data_channel(const godot_net_webrtc_data_channel *p_impl); - virtual void set_write_mode(WriteMode mode) override; virtual WriteMode get_write_mode() const override; virtual bool was_string_packet() const override; @@ -60,6 +56,7 @@ public: virtual int get_max_retransmits() const override; virtual String get_protocol() const override; virtual bool is_negotiated() const override; + virtual int get_buffered_amount() const override; virtual Error poll() override; virtual void close() override; @@ -71,10 +68,31 @@ public: virtual int get_max_packet_size() const override; - WebRTCDataChannelGDNative(); - ~WebRTCDataChannelGDNative(); -}; + /** GDExtension **/ + GDVIRTUAL0RC(int, _get_available_packet_count); + GDVIRTUAL2R(int, _get_packet, GDNativeConstPtr<const uint8_t *>, GDNativePtr<int>); + GDVIRTUAL2R(int, _put_packet, GDNativeConstPtr<const uint8_t>, int); + GDVIRTUAL0RC(int, _get_max_packet_size); -#endif // WEBRTC_GDNATIVE_ENABLED + GDVIRTUAL0R(int, _poll); + GDVIRTUAL0(_close); + + GDVIRTUAL1(_set_write_mode, int); + GDVIRTUAL0RC(int, _get_write_mode); + + GDVIRTUAL0RC(bool, _was_string_packet); + + GDVIRTUAL0RC(int, _get_ready_state); + GDVIRTUAL0RC(String, _get_label); + GDVIRTUAL0RC(bool, _is_ordered); + GDVIRTUAL0RC(int, _get_id); + GDVIRTUAL0RC(int, _get_max_packet_life_time); + GDVIRTUAL0RC(int, _get_max_retransmits); + GDVIRTUAL0RC(String, _get_protocol); + GDVIRTUAL0RC(bool, _is_negotiated); + GDVIRTUAL0RC(int, _get_buffered_amount); + + WebRTCDataChannelExtension() {} +}; -#endif // WEBRTC_DATA_CHANNEL_GDNATIVE_H +#endif // WEBRTC_DATA_CHANNEL_EXTENSION_H diff --git a/modules/webrtc/webrtc_data_channel_gdnative.cpp b/modules/webrtc/webrtc_data_channel_gdnative.cpp deleted file mode 100644 index d4cf464c7c..0000000000 --- a/modules/webrtc/webrtc_data_channel_gdnative.cpp +++ /dev/null @@ -1,137 +0,0 @@ -/*************************************************************************/ -/* webrtc_data_channel_gdnative.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. */ -/*************************************************************************/ - -#ifdef WEBRTC_GDNATIVE_ENABLED - -#include "webrtc_data_channel_gdnative.h" -#include "core/io/resource_loader.h" -#include "modules/gdnative/nativescript/nativescript.h" - -void WebRTCDataChannelGDNative::_bind_methods() { - ADD_PROPERTY_DEFAULT("write_mode", WRITE_MODE_BINARY); -} - -WebRTCDataChannelGDNative::WebRTCDataChannelGDNative() { - interface = nullptr; -} - -WebRTCDataChannelGDNative::~WebRTCDataChannelGDNative() { -} - -Error WebRTCDataChannelGDNative::poll() { - ERR_FAIL_COND_V(interface == nullptr, ERR_UNCONFIGURED); - return (Error)interface->poll(interface->data); -} - -void WebRTCDataChannelGDNative::close() { - ERR_FAIL_COND(interface == nullptr); - interface->close(interface->data); -} - -void WebRTCDataChannelGDNative::set_write_mode(WriteMode p_mode) { - ERR_FAIL_COND(interface == nullptr); - interface->set_write_mode(interface->data, p_mode); -} - -WebRTCDataChannel::WriteMode WebRTCDataChannelGDNative::get_write_mode() const { - ERR_FAIL_COND_V(interface == nullptr, WRITE_MODE_BINARY); - return (WriteMode)interface->get_write_mode(interface->data); -} - -bool WebRTCDataChannelGDNative::was_string_packet() const { - ERR_FAIL_COND_V(interface == nullptr, false); - return interface->was_string_packet(interface->data); -} - -WebRTCDataChannel::ChannelState WebRTCDataChannelGDNative::get_ready_state() const { - ERR_FAIL_COND_V(interface == nullptr, STATE_CLOSED); - return (ChannelState)interface->get_ready_state(interface->data); -} - -String WebRTCDataChannelGDNative::get_label() const { - ERR_FAIL_COND_V(interface == nullptr, ""); - return String(interface->get_label(interface->data)); -} - -bool WebRTCDataChannelGDNative::is_ordered() const { - ERR_FAIL_COND_V(interface == nullptr, false); - return interface->is_ordered(interface->data); -} - -int WebRTCDataChannelGDNative::get_id() const { - ERR_FAIL_COND_V(interface == nullptr, -1); - return interface->get_id(interface->data); -} - -int WebRTCDataChannelGDNative::get_max_packet_life_time() const { - ERR_FAIL_COND_V(interface == nullptr, -1); - return interface->get_max_packet_life_time(interface->data); -} - -int WebRTCDataChannelGDNative::get_max_retransmits() const { - ERR_FAIL_COND_V(interface == nullptr, -1); - return interface->get_max_retransmits(interface->data); -} - -String WebRTCDataChannelGDNative::get_protocol() const { - ERR_FAIL_COND_V(interface == nullptr, ""); - return String(interface->get_protocol(interface->data)); -} - -bool WebRTCDataChannelGDNative::is_negotiated() const { - ERR_FAIL_COND_V(interface == nullptr, false); - return interface->is_negotiated(interface->data); -} - -Error WebRTCDataChannelGDNative::get_packet(const uint8_t **r_buffer, int &r_buffer_size) { - ERR_FAIL_COND_V(interface == nullptr, ERR_UNCONFIGURED); - return (Error)interface->get_packet(interface->data, r_buffer, &r_buffer_size); -} - -Error WebRTCDataChannelGDNative::put_packet(const uint8_t *p_buffer, int p_buffer_size) { - ERR_FAIL_COND_V(interface == nullptr, ERR_UNCONFIGURED); - return (Error)interface->put_packet(interface->data, p_buffer, p_buffer_size); -} - -int WebRTCDataChannelGDNative::get_max_packet_size() const { - ERR_FAIL_COND_V(interface == nullptr, 0); - return interface->get_max_packet_size(interface->data); -} - -int WebRTCDataChannelGDNative::get_available_packet_count() const { - ERR_FAIL_COND_V(interface == nullptr, 0); - return interface->get_available_packet_count(interface->data); -} - -void WebRTCDataChannelGDNative::set_native_webrtc_data_channel(const godot_net_webrtc_data_channel *p_impl) { - interface = p_impl; -} - -#endif // WEBRTC_GDNATIVE_ENABLED diff --git a/modules/webrtc/webrtc_data_channel_js.cpp b/modules/webrtc/webrtc_data_channel_js.cpp index dfbec80c86..31d6a0568c 100644 --- a/modules/webrtc/webrtc_data_channel_js.cpp +++ b/modules/webrtc/webrtc_data_channel_js.cpp @@ -46,6 +46,7 @@ extern int godot_js_rtc_datachannel_id_get(int p_id); extern int godot_js_rtc_datachannel_max_packet_lifetime_get(int p_id); extern int godot_js_rtc_datachannel_max_retransmits_get(int p_id); extern int godot_js_rtc_datachannel_is_negotiated(int p_id); +extern int godot_js_rtc_datachannel_get_buffered_amount(int p_id); extern char *godot_js_rtc_datachannel_label_get(int p_id); // Must free the returned string. extern char *godot_js_rtc_datachannel_protocol_get(int p_id); // Must free the returned string. extern void godot_js_rtc_datachannel_destroy(int p_id); @@ -181,6 +182,10 @@ bool WebRTCDataChannelJS::is_negotiated() const { return godot_js_rtc_datachannel_is_negotiated(_js_id); } +int WebRTCDataChannelJS::get_buffered_amount() const { + return godot_js_rtc_datachannel_get_buffered_amount(_js_id); +} + WebRTCDataChannelJS::WebRTCDataChannelJS() { } diff --git a/modules/webrtc/webrtc_data_channel_js.h b/modules/webrtc/webrtc_data_channel_js.h index db58ebccff..5cd6a32ed9 100644 --- a/modules/webrtc/webrtc_data_channel_js.h +++ b/modules/webrtc/webrtc_data_channel_js.h @@ -72,6 +72,7 @@ public: virtual int get_max_retransmits() const override; virtual String get_protocol() const override; virtual bool is_negotiated() const override; + virtual int get_buffered_amount() const override; virtual Error poll() override; virtual void close() override; diff --git a/modules/webrtc/webrtc_multiplayer.cpp b/modules/webrtc/webrtc_multiplayer_peer.cpp index 741cad5640..133bd71ddb 100644 --- a/modules/webrtc/webrtc_multiplayer.cpp +++ b/modules/webrtc/webrtc_multiplayer_peer.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* webrtc_multiplayer.cpp */ +/* webrtc_multiplayer_peer.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,51 +28,43 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "webrtc_multiplayer.h" +#include "webrtc_multiplayer_peer.h" #include "core/io/marshalls.h" #include "core/os/os.h" -void WebRTCMultiplayer::_bind_methods() { - ClassDB::bind_method(D_METHOD("initialize", "peer_id", "server_compatibility"), &WebRTCMultiplayer::initialize, DEFVAL(false)); - ClassDB::bind_method(D_METHOD("add_peer", "peer", "peer_id", "unreliable_lifetime"), &WebRTCMultiplayer::add_peer, DEFVAL(1)); - ClassDB::bind_method(D_METHOD("remove_peer", "peer_id"), &WebRTCMultiplayer::remove_peer); - ClassDB::bind_method(D_METHOD("has_peer", "peer_id"), &WebRTCMultiplayer::has_peer); - ClassDB::bind_method(D_METHOD("get_peer", "peer_id"), &WebRTCMultiplayer::get_peer); - ClassDB::bind_method(D_METHOD("get_peers"), &WebRTCMultiplayer::get_peers); - ClassDB::bind_method(D_METHOD("close"), &WebRTCMultiplayer::close); +void WebRTCMultiplayerPeer::_bind_methods() { + ClassDB::bind_method(D_METHOD("initialize", "peer_id", "server_compatibility", "channels_config"), &WebRTCMultiplayerPeer::initialize, DEFVAL(false), DEFVAL(Array())); + ClassDB::bind_method(D_METHOD("add_peer", "peer", "peer_id", "unreliable_lifetime"), &WebRTCMultiplayerPeer::add_peer, DEFVAL(1)); + ClassDB::bind_method(D_METHOD("remove_peer", "peer_id"), &WebRTCMultiplayerPeer::remove_peer); + ClassDB::bind_method(D_METHOD("has_peer", "peer_id"), &WebRTCMultiplayerPeer::has_peer); + ClassDB::bind_method(D_METHOD("get_peer", "peer_id"), &WebRTCMultiplayerPeer::get_peer); + ClassDB::bind_method(D_METHOD("get_peers"), &WebRTCMultiplayerPeer::get_peers); + ClassDB::bind_method(D_METHOD("close"), &WebRTCMultiplayerPeer::close); } -void WebRTCMultiplayer::set_transfer_mode(TransferMode p_mode) { - transfer_mode = p_mode; -} - -NetworkedMultiplayerPeer::TransferMode WebRTCMultiplayer::get_transfer_mode() const { - return transfer_mode; -} - -void WebRTCMultiplayer::set_target_peer(int p_peer_id) { +void WebRTCMultiplayerPeer::set_target_peer(int p_peer_id) { target_peer = p_peer_id; } -/* Returns the ID of the NetworkedMultiplayerPeer who sent the most recent packet: */ -int WebRTCMultiplayer::get_packet_peer() const { +/* Returns the ID of the MultiplayerPeer who sent the most recent packet: */ +int WebRTCMultiplayerPeer::get_packet_peer() const { return next_packet_peer; } -bool WebRTCMultiplayer::is_server() const { +bool WebRTCMultiplayerPeer::is_server() const { return unique_id == TARGET_PEER_SERVER; } -void WebRTCMultiplayer::poll() { +void WebRTCMultiplayerPeer::poll() { if (peer_map.size() == 0) { return; } List<int> remove; List<int> add; - for (Map<int, Ref<ConnectedPeer>>::Element *E = peer_map.front(); E; E = E->next()) { - Ref<ConnectedPeer> peer = E->get(); + for (KeyValue<int, Ref<ConnectedPeer>> &E : peer_map) { + Ref<ConnectedPeer> peer = E.value; peer->connection->poll(); // Check peer state switch (peer->connection->get_connection_state()) { @@ -85,7 +77,7 @@ void WebRTCMultiplayer::poll() { break; default: // Peer is closed or in error state. Got to next peer. - remove.push_back(E->key()); + remove.push_back(E.key); continue; } // Check channels state @@ -100,7 +92,7 @@ void WebRTCMultiplayer::poll() { continue; default: // Channel was closed or in error state, remove peer id. - remove.push_back(E->key()); + remove.push_back(E.key); } // We got a closed channel break out, the peer will be removed. break; @@ -108,34 +100,34 @@ void WebRTCMultiplayer::poll() { // This peer has newly connected, and all channels are now open. if (ready == peer->channels.size() && !peer->connected) { peer->connected = true; - add.push_back(E->key()); + add.push_back(E.key); } } // Remove disconnected peers - for (List<int>::Element *E = remove.front(); E; E = E->next()) { - remove_peer(E->get()); - if (next_packet_peer == E->get()) { + for (int &E : remove) { + remove_peer(E); + if (next_packet_peer == E) { next_packet_peer = 0; } } // Signal newly connected peers - for (List<int>::Element *E = add.front(); E; E = E->next()) { + for (int &E : add) { // Already connected to server: simply notify new peer. // NOTE: Mesh is always connected. if (connection_status == CONNECTION_CONNECTED) { - emit_signal("peer_connected", E->get()); + emit_signal(SNAME("peer_connected"), E); } // Server emulation mode suppresses peer_conencted until server connects. - if (server_compat && E->get() == TARGET_PEER_SERVER) { + if (server_compat && E == TARGET_PEER_SERVER) { // Server connected. connection_status = CONNECTION_CONNECTED; - emit_signal("peer_connected", TARGET_PEER_SERVER); - emit_signal("connection_succeeded"); + emit_signal(SNAME("peer_connected"), TARGET_PEER_SERVER); + emit_signal(SNAME("connection_succeeded")); // Notify of all previously connected peers - for (Map<int, Ref<ConnectedPeer>>::Element *F = peer_map.front(); F; F = F->next()) { - if (F->key() != 1 && F->get()->connected) { - emit_signal("peer_connected", F->key()); + for (const KeyValue<int, Ref<ConnectedPeer>> &F : peer_map) { + if (F.key != 1 && F.value->connected) { + emit_signal(SNAME("peer_connected"), F.key); } } break; // Because we already notified of all newly added peers. @@ -147,15 +139,15 @@ void WebRTCMultiplayer::poll() { } } -void WebRTCMultiplayer::_find_next_peer() { +void WebRTCMultiplayerPeer::_find_next_peer() { Map<int, Ref<ConnectedPeer>>::Element *E = peer_map.find(next_packet_peer); if (E) { E = E->next(); } // After last. while (E) { - for (List<Ref<WebRTCDataChannel>>::Element *F = E->get()->channels.front(); F; F = F->next()) { - if (F->get()->get_available_packet_count()) { + for (const Ref<WebRTCDataChannel> &F : E->get()->channels) { + if (F->get_available_packet_count()) { next_packet_peer = E->key(); return; } @@ -165,8 +157,8 @@ void WebRTCMultiplayer::_find_next_peer() { E = peer_map.front(); // Before last while (E) { - for (List<Ref<WebRTCDataChannel>>::Element *F = E->get()->channels.front(); F; F = F->next()) { - if (F->get()->get_available_packet_count()) { + for (const Ref<WebRTCDataChannel> &F : E->get()->channels) { + if (F->get_available_packet_count()) { next_packet_peer = E->key(); return; } @@ -180,20 +172,38 @@ void WebRTCMultiplayer::_find_next_peer() { next_packet_peer = 0; } -void WebRTCMultiplayer::set_refuse_new_connections(bool p_enable) { - refuse_connections = p_enable; -} - -bool WebRTCMultiplayer::is_refusing_new_connections() const { - return refuse_connections; -} - -NetworkedMultiplayerPeer::ConnectionStatus WebRTCMultiplayer::get_connection_status() const { +MultiplayerPeer::ConnectionStatus WebRTCMultiplayerPeer::get_connection_status() const { return connection_status; } -Error WebRTCMultiplayer::initialize(int p_self_id, bool p_server_compat) { - ERR_FAIL_COND_V(p_self_id < 0 || p_self_id > ~(1 << 31), ERR_INVALID_PARAMETER); +Error WebRTCMultiplayerPeer::initialize(int p_self_id, bool p_server_compat, Array p_channels_config) { + ERR_FAIL_COND_V(p_self_id < 1 || p_self_id > ~(1 << 31), ERR_INVALID_PARAMETER); + channels_config.clear(); + for (int i = 0; i < p_channels_config.size(); i++) { + ERR_FAIL_COND_V_MSG(p_channels_config[i].get_type() != Variant::INT, ERR_INVALID_PARAMETER, "The 'channels_config' array must contain only enum values from 'MultiplayerPeer.Multiplayer::TransferMode'"); + int mode = p_channels_config[i].operator int(); + // Initialize data channel configurations. + Dictionary cfg; + cfg["id"] = CH_RESERVED_MAX + i + 1; + cfg["negotiated"] = true; + cfg["ordered"] = true; + + switch (mode) { + case Multiplayer::TRANSFER_MODE_UNRELIABLE_ORDERED: + cfg["maxPacketLifetime"] = 1; + break; + case Multiplayer::TRANSFER_MODE_UNRELIABLE: + cfg["maxPacketLifetime"] = 1; + cfg["ordered"] = false; + break; + case Multiplayer::TRANSFER_MODE_RELIABLE: + break; + default: + ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, vformat("The 'channels_config' array must contain only enum values from 'MultiplayerPeer.Multiplayer::TransferMode'. Got: %d", mode)); + } + channels_config.push_back(cfg); + } + unique_id = p_self_id; server_compat = p_server_compat; @@ -206,46 +216,46 @@ Error WebRTCMultiplayer::initialize(int p_self_id, bool p_server_compat) { return OK; } -int WebRTCMultiplayer::get_unique_id() const { +int WebRTCMultiplayerPeer::get_unique_id() const { ERR_FAIL_COND_V(connection_status == CONNECTION_DISCONNECTED, 1); return unique_id; } -void WebRTCMultiplayer::_peer_to_dict(Ref<ConnectedPeer> p_connected_peer, Dictionary &r_dict) { +void WebRTCMultiplayerPeer::_peer_to_dict(Ref<ConnectedPeer> p_connected_peer, Dictionary &r_dict) { Array channels; - for (List<Ref<WebRTCDataChannel>>::Element *F = p_connected_peer->channels.front(); F; F = F->next()) { - channels.push_back(F->get()); + for (Ref<WebRTCDataChannel> &F : p_connected_peer->channels) { + channels.push_back(F); } r_dict["connection"] = p_connected_peer->connection; r_dict["connected"] = p_connected_peer->connected; r_dict["channels"] = channels; } -bool WebRTCMultiplayer::has_peer(int p_peer_id) { +bool WebRTCMultiplayerPeer::has_peer(int p_peer_id) { return peer_map.has(p_peer_id); } -Dictionary WebRTCMultiplayer::get_peer(int p_peer_id) { +Dictionary WebRTCMultiplayerPeer::get_peer(int p_peer_id) { ERR_FAIL_COND_V(!peer_map.has(p_peer_id), Dictionary()); Dictionary out; _peer_to_dict(peer_map[p_peer_id], out); return out; } -Dictionary WebRTCMultiplayer::get_peers() { +Dictionary WebRTCMultiplayerPeer::get_peers() { Dictionary out; - for (Map<int, Ref<ConnectedPeer>>::Element *E = peer_map.front(); E; E = E->next()) { + for (const KeyValue<int, Ref<ConnectedPeer>> &E : peer_map) { Dictionary d; - _peer_to_dict(E->get(), d); - out[E->key()] = d; + _peer_to_dict(E.value, d); + out[E.key] = d; } return out; } -Error WebRTCMultiplayer::add_peer(Ref<WebRTCPeerConnection> p_peer, int p_peer_id, int p_unreliable_lifetime) { +Error WebRTCMultiplayerPeer::add_peer(Ref<WebRTCPeerConnection> p_peer, int p_peer_id, int p_unreliable_lifetime) { ERR_FAIL_COND_V(p_peer_id < 0 || p_peer_id > ~(1 << 31), ERR_INVALID_PARAMETER); ERR_FAIL_COND_V(p_unreliable_lifetime < 0, ERR_INVALID_PARAMETER); - ERR_FAIL_COND_V(refuse_connections, ERR_UNAUTHORIZED); + ERR_FAIL_COND_V(is_refusing_new_connections(), ERR_UNAUTHORIZED); // Peer must be valid, and in new state (to create data channels) ERR_FAIL_COND_V(!p_peer.is_valid(), ERR_INVALID_PARAMETER); ERR_FAIL_COND_V(p_peer->get_connection_state() != WebRTCPeerConnection::STATE_NEW, ERR_INVALID_PARAMETER); @@ -260,46 +270,52 @@ Error WebRTCMultiplayer::add_peer(Ref<WebRTCPeerConnection> p_peer, int p_peer_i cfg["id"] = 1; peer->channels[CH_RELIABLE] = p_peer->create_data_channel("reliable", cfg); - ERR_FAIL_COND_V(!peer->channels[CH_RELIABLE].is_valid(), FAILED); + ERR_FAIL_COND_V(peer->channels[CH_RELIABLE].is_null(), FAILED); cfg["id"] = 2; cfg["maxPacketLifetime"] = p_unreliable_lifetime; peer->channels[CH_ORDERED] = p_peer->create_data_channel("ordered", cfg); - ERR_FAIL_COND_V(!peer->channels[CH_ORDERED].is_valid(), FAILED); + ERR_FAIL_COND_V(peer->channels[CH_ORDERED].is_null(), FAILED); cfg["id"] = 3; cfg["ordered"] = false; peer->channels[CH_UNRELIABLE] = p_peer->create_data_channel("unreliable", cfg); - ERR_FAIL_COND_V(!peer->channels[CH_UNRELIABLE].is_valid(), FAILED); + ERR_FAIL_COND_V(peer->channels[CH_UNRELIABLE].is_null(), FAILED); + + for (const Dictionary &dict : channels_config) { + Ref<WebRTCDataChannel> ch = p_peer->create_data_channel(String::num_int64(dict["id"]), dict); + ERR_FAIL_COND_V(ch.is_null(), FAILED); + peer->channels.push_back(ch); + } peer_map[p_peer_id] = peer; // add the new peer connection to the peer_map return OK; } -void WebRTCMultiplayer::remove_peer(int p_peer_id) { +void WebRTCMultiplayerPeer::remove_peer(int p_peer_id) { ERR_FAIL_COND(!peer_map.has(p_peer_id)); Ref<ConnectedPeer> peer = peer_map[p_peer_id]; peer_map.erase(p_peer_id); if (peer->connected) { peer->connected = false; - emit_signal("peer_disconnected", p_peer_id); + emit_signal(SNAME("peer_disconnected"), p_peer_id); if (server_compat && p_peer_id == TARGET_PEER_SERVER) { - emit_signal("server_disconnected"); + emit_signal(SNAME("server_disconnected")); connection_status = CONNECTION_DISCONNECTED; } } } -Error WebRTCMultiplayer::get_packet(const uint8_t **r_buffer, int &r_buffer_size) { +Error WebRTCMultiplayerPeer::get_packet(const uint8_t **r_buffer, int &r_buffer_size) { // Peer not available if (next_packet_peer == 0 || !peer_map.has(next_packet_peer)) { _find_next_peer(); ERR_FAIL_V(ERR_UNAVAILABLE); } - for (List<Ref<WebRTCDataChannel>>::Element *E = peer_map[next_packet_peer]->channels.front(); E; E = E->next()) { - if (E->get()->get_available_packet_count()) { - Error err = E->get()->get_packet(r_buffer, r_buffer_size); + for (Ref<WebRTCDataChannel> &E : peer_map[next_packet_peer]->channels) { + if (E->get_available_packet_count()) { + Error err = E->get_packet(r_buffer, r_buffer_size); _find_next_peer(); return err; } @@ -309,20 +325,24 @@ Error WebRTCMultiplayer::get_packet(const uint8_t **r_buffer, int &r_buffer_size ERR_FAIL_V(ERR_BUG); } -Error WebRTCMultiplayer::put_packet(const uint8_t *p_buffer, int p_buffer_size) { +Error WebRTCMultiplayerPeer::put_packet(const uint8_t *p_buffer, int p_buffer_size) { ERR_FAIL_COND_V(connection_status == CONNECTION_DISCONNECTED, ERR_UNCONFIGURED); - int ch = CH_RELIABLE; - switch (transfer_mode) { - case TRANSFER_MODE_RELIABLE: - ch = CH_RELIABLE; - break; - case TRANSFER_MODE_UNRELIABLE_ORDERED: - ch = CH_ORDERED; - break; - case TRANSFER_MODE_UNRELIABLE: - ch = CH_UNRELIABLE; - break; + int ch = get_transfer_channel(); + if (ch == 0) { + switch (get_transfer_mode()) { + case Multiplayer::TRANSFER_MODE_RELIABLE: + ch = CH_RELIABLE; + break; + case Multiplayer::TRANSFER_MODE_UNRELIABLE_ORDERED: + ch = CH_ORDERED; + break; + case Multiplayer::TRANSFER_MODE_UNRELIABLE: + ch = CH_UNRELIABLE; + break; + } + } else { + ch += CH_RESERVED_MAX - 1; } Map<int, Ref<ConnectedPeer>>::Element *E = nullptr; @@ -331,62 +351,53 @@ Error WebRTCMultiplayer::put_packet(const uint8_t *p_buffer, int p_buffer_size) E = peer_map.find(target_peer); ERR_FAIL_COND_V_MSG(!E, ERR_INVALID_PARAMETER, "Invalid target peer: " + itos(target_peer) + "."); - ERR_FAIL_COND_V(E->value()->channels.size() <= ch, ERR_BUG); - ERR_FAIL_COND_V(!E->value()->channels[ch].is_valid(), ERR_BUG); + ERR_FAIL_COND_V_MSG(E->value()->channels.size() <= ch, ERR_INVALID_PARAMETER, vformat("Unable to send packet on channel %d, max channels: %d", ch, E->value()->channels.size())); + ERR_FAIL_COND_V(E->value()->channels[ch].is_null(), ERR_BUG); return E->value()->channels[ch]->put_packet(p_buffer, p_buffer_size); } else { int exclude = -target_peer; - for (Map<int, Ref<ConnectedPeer>>::Element *F = peer_map.front(); F; F = F->next()) { + for (KeyValue<int, Ref<ConnectedPeer>> &F : peer_map) { // Exclude packet. If target_peer == 0 then don't exclude any packets - if (target_peer != 0 && F->key() == exclude) { + if (target_peer != 0 && F.key == exclude) { continue; } - ERR_CONTINUE(F->value()->channels.size() <= ch || !F->value()->channels[ch].is_valid()); - F->value()->channels[ch]->put_packet(p_buffer, p_buffer_size); + ERR_CONTINUE_MSG(F.value->channels.size() <= ch, vformat("Unable to send packet on channel %d, max channels: %d", ch, E->value()->channels.size())); + ERR_CONTINUE(F.value->channels[ch].is_null()); + F.value->channels[ch]->put_packet(p_buffer, p_buffer_size); } } return OK; } -int WebRTCMultiplayer::get_available_packet_count() const { +int WebRTCMultiplayerPeer::get_available_packet_count() const { if (next_packet_peer == 0) { return 0; // To be sure next call to get_packet works if size > 0 . } int size = 0; - for (Map<int, Ref<ConnectedPeer>>::Element *E = peer_map.front(); E; E = E->next()) { - for (List<Ref<WebRTCDataChannel>>::Element *F = E->get()->channels.front(); F; F = F->next()) { - size += F->get()->get_available_packet_count(); + for (const KeyValue<int, Ref<ConnectedPeer>> &E : peer_map) { + for (const Ref<WebRTCDataChannel> &F : E.value->channels) { + size += F->get_available_packet_count(); } } return size; } -int WebRTCMultiplayer::get_max_packet_size() const { +int WebRTCMultiplayerPeer::get_max_packet_size() const { return 1200; } -void WebRTCMultiplayer::close() { +void WebRTCMultiplayerPeer::close() { peer_map.clear(); + channels_config.clear(); unique_id = 0; next_packet_peer = 0; target_peer = 0; connection_status = CONNECTION_DISCONNECTED; } -WebRTCMultiplayer::WebRTCMultiplayer() { - unique_id = 0; - next_packet_peer = 0; - target_peer = 0; - client_count = 0; - transfer_mode = TRANSFER_MODE_RELIABLE; - refuse_connections = false; - connection_status = CONNECTION_DISCONNECTED; - server_compat = false; -} - -WebRTCMultiplayer::~WebRTCMultiplayer() { +WebRTCMultiplayerPeer::~WebRTCMultiplayerPeer() { close(); } diff --git a/modules/webrtc/webrtc_multiplayer.h b/modules/webrtc/webrtc_multiplayer_peer.h index 6b4ae6fcc8..4a7e9ad7c8 100644 --- a/modules/webrtc/webrtc_multiplayer.h +++ b/modules/webrtc/webrtc_multiplayer_peer.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* webrtc_multiplayer.h */ +/* webrtc_multiplayer_peer.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -31,11 +31,11 @@ #ifndef WEBRTC_MULTIPLAYER_H #define WEBRTC_MULTIPLAYER_H -#include "core/io/networked_multiplayer_peer.h" +#include "core/multiplayer/multiplayer_peer.h" #include "webrtc_peer_connection.h" -class WebRTCMultiplayer : public NetworkedMultiplayerPeer { - GDCLASS(WebRTCMultiplayer, NetworkedMultiplayerPeer); +class WebRTCMultiplayerPeer : public MultiplayerPeer { + GDCLASS(WebRTCMultiplayerPeer, MultiplayerPeer); protected: static void _bind_methods(); @@ -48,7 +48,7 @@ private: CH_RESERVED_MAX = 3 }; - class ConnectedPeer : public Reference { + class ConnectedPeer : public RefCounted { public: Ref<WebRTCPeerConnection> connection; List<Ref<WebRTCDataChannel>> channels; @@ -62,25 +62,24 @@ private: } }; - uint32_t unique_id; - int target_peer; - int client_count; - bool refuse_connections; - ConnectionStatus connection_status; - TransferMode transfer_mode; - int next_packet_peer; - bool server_compat; + uint32_t unique_id = 0; + int target_peer = 0; + int client_count = 0; + ConnectionStatus connection_status = CONNECTION_DISCONNECTED; + int next_packet_peer = 0; + bool server_compat = false; Map<int, Ref<ConnectedPeer>> peer_map; + List<Dictionary> channels_config; void _peer_to_dict(Ref<ConnectedPeer> p_connected_peer, Dictionary &r_dict); void _find_next_peer(); public: - WebRTCMultiplayer(); - ~WebRTCMultiplayer(); + WebRTCMultiplayerPeer() {} + ~WebRTCMultiplayerPeer(); - Error initialize(int p_self_id, bool p_server_compat = false); + Error initialize(int p_self_id, bool p_server_compat = false, Array p_channels_config = Array()); Error add_peer(Ref<WebRTCPeerConnection> p_peer, int p_peer_id, int p_unreliable_lifetime = 1); void remove_peer(int p_peer_id); bool has_peer(int p_peer_id); @@ -94,9 +93,7 @@ public: int get_available_packet_count() const override; int get_max_packet_size() const override; - // NetworkedMultiplayerPeer - void set_transfer_mode(TransferMode p_mode) override; - TransferMode get_transfer_mode() const override; + // MultiplayerPeer void set_target_peer(int p_peer_id) override; int get_unique_id() const override; @@ -106,9 +103,6 @@ public: void poll() override; - void set_refuse_new_connections(bool p_enable) override; - bool is_refusing_new_connections() const override; - ConnectionStatus get_connection_status() const override; }; diff --git a/modules/webrtc/webrtc_peer_connection.cpp b/modules/webrtc/webrtc_peer_connection.cpp index 3e2938bf7d..ad28aa76c7 100644 --- a/modules/webrtc/webrtc_peer_connection.cpp +++ b/modules/webrtc/webrtc_peer_connection.cpp @@ -30,17 +30,29 @@ #include "webrtc_peer_connection.h" -WebRTCPeerConnection *(*WebRTCPeerConnection::_create)() = nullptr; +#ifdef JAVASCRIPT_ENABLED +#include "webrtc_peer_connection_js.h" +#else +#include "webrtc_peer_connection_extension.h" +#endif -Ref<WebRTCPeerConnection> WebRTCPeerConnection::create_ref() { - return create(); +StringName WebRTCPeerConnection::default_extension; + +void WebRTCPeerConnection::set_default_extension(const StringName &p_extension) { + default_extension = p_extension; } WebRTCPeerConnection *WebRTCPeerConnection::create() { - if (!_create) { - return nullptr; +#ifdef JAVASCRIPT_ENABLED + return memnew(WebRTCPeerConnectionJS); +#else + if (default_extension == String()) { + WARN_PRINT_ONCE("No default WebRTC extension configured."); + return memnew(WebRTCPeerConnectionExtension); } - return _create(); + Object *obj = ClassDB::instantiate(default_extension); + return Object::cast_to<WebRTCPeerConnectionExtension>(obj); +#endif } void WebRTCPeerConnection::_bind_methods() { diff --git a/modules/webrtc/webrtc_peer_connection.h b/modules/webrtc/webrtc_peer_connection.h index ae75864489..e2ef3e55ad 100644 --- a/modules/webrtc/webrtc_peer_connection.h +++ b/modules/webrtc/webrtc_peer_connection.h @@ -34,8 +34,8 @@ #include "core/io/packet_peer.h" #include "modules/webrtc/webrtc_data_channel.h" -class WebRTCPeerConnection : public Reference { - GDCLASS(WebRTCPeerConnection, Reference); +class WebRTCPeerConnection : public RefCounted { + GDCLASS(WebRTCPeerConnection, RefCounted); public: enum ConnectionState { @@ -47,11 +47,15 @@ public: STATE_CLOSED }; +private: + static StringName default_extension; + protected: static void _bind_methods(); - static WebRTCPeerConnection *(*_create)(); public: + static void set_default_extension(const StringName &p_name); + virtual ConnectionState get_connection_state() const = 0; virtual Error initialize(Dictionary p_config = Dictionary()) = 0; @@ -63,7 +67,6 @@ public: virtual Error poll() = 0; virtual void close() = 0; - static Ref<WebRTCPeerConnection> create_ref(); static WebRTCPeerConnection *create(); WebRTCPeerConnection(); diff --git a/modules/webrtc/webrtc_peer_connection_extension.cpp b/modules/webrtc/webrtc_peer_connection_extension.cpp new file mode 100644 index 0000000000..33288e66d6 --- /dev/null +++ b/modules/webrtc/webrtc_peer_connection_extension.cpp @@ -0,0 +1,131 @@ +/*************************************************************************/ +/* webrtc_peer_connection_extension.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 "webrtc_peer_connection_extension.h" + +void WebRTCPeerConnectionExtension::_bind_methods() { + ClassDB::bind_method(D_METHOD("make_default"), &WebRTCPeerConnectionExtension::make_default); + + GDVIRTUAL_BIND(_get_connection_state); + GDVIRTUAL_BIND(_initialize, "p_config"); + GDVIRTUAL_BIND(_create_data_channel, "p_label", "p_config"); + GDVIRTUAL_BIND(_create_offer); + GDVIRTUAL_BIND(_set_remote_description, "p_type", "p_sdp"); + GDVIRTUAL_BIND(_set_local_description, "p_type", "p_sdp"); + GDVIRTUAL_BIND(_add_ice_candidate, "p_sdp_mid_name", "p_sdp_mline_index", "p_sdp_name"); + GDVIRTUAL_BIND(_poll); + GDVIRTUAL_BIND(_close); +} + +void WebRTCPeerConnectionExtension::make_default() { + ERR_FAIL_COND_MSG(!_get_extension(), vformat("Can't make %s the default without extending it.", get_class())); + WebRTCPeerConnection::set_default_extension(get_class()); +} + +WebRTCPeerConnection::ConnectionState WebRTCPeerConnectionExtension::get_connection_state() const { + int state; + if (GDVIRTUAL_CALL(_get_connection_state, state)) { + return (ConnectionState)state; + } + WARN_PRINT_ONCE("WebRTCPeerConnectionExtension::_get_connection_state is unimplemented!"); + return STATE_DISCONNECTED; +} + +Error WebRTCPeerConnectionExtension::initialize(Dictionary p_config) { + int err; + if (GDVIRTUAL_CALL(_initialize, p_config, err)) { + return (Error)err; + } + WARN_PRINT_ONCE("WebRTCPeerConnectionExtension::_initialize is unimplemented!"); + return ERR_UNCONFIGURED; +} + +Ref<WebRTCDataChannel> WebRTCPeerConnectionExtension::create_data_channel(String p_label, Dictionary p_options) { + Object *ret = nullptr; + if (GDVIRTUAL_CALL(_create_data_channel, p_label, p_options, ret)) { + WebRTCDataChannel *ch = Object::cast_to<WebRTCDataChannel>(ret); + ERR_FAIL_COND_V_MSG(ret && !ch, nullptr, "Returned object must be an instance of WebRTCDataChannel."); + return ch; + } + WARN_PRINT_ONCE("WebRTCPeerConnectionExtension::_create_data_channel is unimplemented!"); + return nullptr; +} + +Error WebRTCPeerConnectionExtension::create_offer() { + int err; + if (GDVIRTUAL_CALL(_create_offer, err)) { + return (Error)err; + } + WARN_PRINT_ONCE("WebRTCPeerConnectionExtension::_create_offer is unimplemented!"); + return ERR_UNCONFIGURED; +} + +Error WebRTCPeerConnectionExtension::set_local_description(String p_type, String p_sdp) { + int err; + if (GDVIRTUAL_CALL(_set_local_description, p_type, p_sdp, err)) { + return (Error)err; + } + WARN_PRINT_ONCE("WebRTCPeerConnectionExtension::_set_local_description is unimplemented!"); + return ERR_UNCONFIGURED; +} + +Error WebRTCPeerConnectionExtension::set_remote_description(String p_type, String p_sdp) { + int err; + if (GDVIRTUAL_CALL(_set_remote_description, p_type, p_sdp, err)) { + return (Error)err; + } + WARN_PRINT_ONCE("WebRTCPeerConnectionExtension::_set_remote_description is unimplemented!"); + return ERR_UNCONFIGURED; +} + +Error WebRTCPeerConnectionExtension::add_ice_candidate(String p_sdp_mid_name, int p_sdp_mline_index, String p_sdp_name) { + int err; + if (GDVIRTUAL_CALL(_add_ice_candidate, p_sdp_mid_name, p_sdp_mline_index, p_sdp_name, err)) { + return (Error)err; + } + WARN_PRINT_ONCE("WebRTCPeerConnectionExtension::_add_ice_candidate is unimplemented!"); + return ERR_UNCONFIGURED; +} + +Error WebRTCPeerConnectionExtension::poll() { + int err; + if (GDVIRTUAL_CALL(_poll, err)) { + return (Error)err; + } + WARN_PRINT_ONCE("WebRTCPeerConnectionExtension::_poll is unimplemented!"); + return ERR_UNCONFIGURED; +} + +void WebRTCPeerConnectionExtension::close() { + if (GDVIRTUAL_CALL(_close)) { + return; + } + WARN_PRINT_ONCE("WebRTCPeerConnectionExtension::_close is unimplemented!"); +} diff --git a/modules/webrtc/webrtc_peer_connection_gdnative.h b/modules/webrtc/webrtc_peer_connection_extension.h index 578af0202f..b3c2039fc1 100644 --- a/modules/webrtc/webrtc_peer_connection_gdnative.h +++ b/modules/webrtc/webrtc_peer_connection_extension.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* webrtc_peer_connection_gdnative.h */ +/* webrtc_peer_connection_extension.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,30 +28,23 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef WEBRTC_PEER_CONNECTION_GDNATIVE_H -#define WEBRTC_PEER_CONNECTION_GDNATIVE_H +#ifndef WEBRTC_PEER_CONNECTION_EXTENSION_H +#define WEBRTC_PEER_CONNECTION_EXTENSION_H -#ifdef WEBRTC_GDNATIVE_ENABLED - -#include "modules/gdnative/include/net/godot_net.h" #include "webrtc_peer_connection.h" -class WebRTCPeerConnectionGDNative : public WebRTCPeerConnection { - GDCLASS(WebRTCPeerConnectionGDNative, WebRTCPeerConnection); +#include "core/object/gdvirtual.gen.inc" +#include "core/object/script_language.h" +#include "core/variant/native_ptr.h" + +class WebRTCPeerConnectionExtension : public WebRTCPeerConnection { + GDCLASS(WebRTCPeerConnectionExtension, WebRTCPeerConnection); protected: static void _bind_methods(); - static WebRTCPeerConnection *_create(); - -private: - static const godot_net_webrtc_library *default_library; - const godot_net_webrtc_peer_connection *interface; public: - static Error set_default_library(const godot_net_webrtc_library *p_library); - static void make_default() { WebRTCPeerConnection::_create = WebRTCPeerConnectionGDNative::_create; } - - void set_native_webrtc_peer_connection(const godot_net_webrtc_peer_connection *p_impl); + void make_default(); virtual ConnectionState get_connection_state() const override; @@ -60,14 +53,22 @@ public: virtual Error create_offer() override; virtual Error set_remote_description(String type, String sdp) override; virtual Error set_local_description(String type, String sdp) override; - virtual Error add_ice_candidate(String sdpMidName, int sdpMlineIndexName, String sdpName) override; + virtual Error add_ice_candidate(String p_sdp_mid_name, int p_sdp_mline_index, String p_sdp_name) override; virtual Error poll() override; virtual void close() override; - WebRTCPeerConnectionGDNative(); - ~WebRTCPeerConnectionGDNative(); -}; + /** GDExtension **/ + GDVIRTUAL0RC(int, _get_connection_state); + GDVIRTUAL1R(int, _initialize, Dictionary); + GDVIRTUAL2R(Object *, _create_data_channel, String, Dictionary); + GDVIRTUAL0R(int, _create_offer); + GDVIRTUAL2R(int, _set_remote_description, String, String); + GDVIRTUAL2R(int, _set_local_description, String, String); + GDVIRTUAL3R(int, _add_ice_candidate, String, int, String); + GDVIRTUAL0R(int, _poll); + GDVIRTUAL0(_close); -#endif // WEBRTC_GDNATIVE_ENABLED + WebRTCPeerConnectionExtension() {} +}; -#endif // WEBRTC_PEER_CONNECTION_GDNATIVE_H +#endif // WEBRTC_PEER_CONNECTION_EXTENSION_H diff --git a/modules/webrtc/webrtc_peer_connection_gdnative.cpp b/modules/webrtc/webrtc_peer_connection_gdnative.cpp deleted file mode 100644 index dcf78dfb73..0000000000 --- a/modules/webrtc/webrtc_peer_connection_gdnative.cpp +++ /dev/null @@ -1,121 +0,0 @@ -/*************************************************************************/ -/* webrtc_peer_connection_gdnative.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. */ -/*************************************************************************/ - -#ifdef WEBRTC_GDNATIVE_ENABLED - -#include "webrtc_peer_connection_gdnative.h" - -#include "core/io/resource_loader.h" -#include "modules/gdnative/nativescript/nativescript.h" -#include "webrtc_data_channel_gdnative.h" - -const godot_net_webrtc_library *WebRTCPeerConnectionGDNative::default_library = nullptr; - -Error WebRTCPeerConnectionGDNative::set_default_library(const godot_net_webrtc_library *p_lib) { - if (default_library) { - const godot_net_webrtc_library *old = default_library; - default_library = nullptr; - old->unregistered(); - } - default_library = p_lib; - return OK; // Maybe add version check and fail accordingly -} - -WebRTCPeerConnection *WebRTCPeerConnectionGDNative::_create() { - WebRTCPeerConnectionGDNative *obj = memnew(WebRTCPeerConnectionGDNative); - ERR_FAIL_COND_V_MSG(!default_library, obj, "Default GDNative WebRTC implementation not defined."); - - // Call GDNative constructor - Error err = (Error)default_library->create_peer_connection(obj); - ERR_FAIL_COND_V_MSG(err != OK, obj, "GDNative default library constructor returned an error."); - - return obj; -} - -void WebRTCPeerConnectionGDNative::_bind_methods() { -} - -WebRTCPeerConnectionGDNative::WebRTCPeerConnectionGDNative() { - interface = nullptr; -} - -WebRTCPeerConnectionGDNative::~WebRTCPeerConnectionGDNative() { -} - -Error WebRTCPeerConnectionGDNative::initialize(Dictionary p_config) { - ERR_FAIL_COND_V(interface == nullptr, ERR_UNCONFIGURED); - return (Error)interface->initialize(interface->data, (const godot_dictionary *)&p_config); -} - -Ref<WebRTCDataChannel> WebRTCPeerConnectionGDNative::create_data_channel(String p_label, Dictionary p_options) { - ERR_FAIL_COND_V(interface == nullptr, nullptr); - return (WebRTCDataChannel *)interface->create_data_channel(interface->data, p_label.utf8().get_data(), (const godot_dictionary *)&p_options); -} - -Error WebRTCPeerConnectionGDNative::create_offer() { - ERR_FAIL_COND_V(interface == nullptr, ERR_UNCONFIGURED); - return (Error)interface->create_offer(interface->data); -} - -Error WebRTCPeerConnectionGDNative::set_local_description(String p_type, String p_sdp) { - ERR_FAIL_COND_V(interface == nullptr, ERR_UNCONFIGURED); - return (Error)interface->set_local_description(interface->data, p_type.utf8().get_data(), p_sdp.utf8().get_data()); -} - -Error WebRTCPeerConnectionGDNative::set_remote_description(String p_type, String p_sdp) { - ERR_FAIL_COND_V(interface == nullptr, ERR_UNCONFIGURED); - return (Error)interface->set_remote_description(interface->data, p_type.utf8().get_data(), p_sdp.utf8().get_data()); -} - -Error WebRTCPeerConnectionGDNative::add_ice_candidate(String sdpMidName, int sdpMlineIndexName, String sdpName) { - ERR_FAIL_COND_V(interface == nullptr, ERR_UNCONFIGURED); - return (Error)interface->add_ice_candidate(interface->data, sdpMidName.utf8().get_data(), sdpMlineIndexName, sdpName.utf8().get_data()); -} - -Error WebRTCPeerConnectionGDNative::poll() { - ERR_FAIL_COND_V(interface == nullptr, ERR_UNCONFIGURED); - return (Error)interface->poll(interface->data); -} - -void WebRTCPeerConnectionGDNative::close() { - ERR_FAIL_COND(interface == nullptr); - interface->close(interface->data); -} - -WebRTCPeerConnection::ConnectionState WebRTCPeerConnectionGDNative::get_connection_state() const { - ERR_FAIL_COND_V(interface == nullptr, STATE_DISCONNECTED); - return (ConnectionState)interface->get_connection_state(interface->data); -} - -void WebRTCPeerConnectionGDNative::set_native_webrtc_peer_connection(const godot_net_webrtc_peer_connection *p_impl) { - interface = p_impl; -} - -#endif // WEBRTC_GDNATIVE_ENABLED diff --git a/modules/webrtc/webrtc_peer_connection_js.cpp b/modules/webrtc/webrtc_peer_connection_js.cpp index 8879f7d6ec..ed3459d5f8 100644 --- a/modules/webrtc/webrtc_peer_connection_js.cpp +++ b/modules/webrtc/webrtc_peer_connection_js.cpp @@ -34,17 +34,16 @@ #include "webrtc_data_channel_js.h" -#include "core/io/json.h" #include "emscripten.h" void WebRTCPeerConnectionJS::_on_ice_candidate(void *p_obj, const char *p_mid_name, int p_mline_idx, const char *p_candidate) { WebRTCPeerConnectionJS *peer = static_cast<WebRTCPeerConnectionJS *>(p_obj); - peer->emit_signal("ice_candidate_created", String(p_mid_name), p_mline_idx, String(p_candidate)); + peer->emit_signal(SNAME("ice_candidate_created"), String(p_mid_name), p_mline_idx, String(p_candidate)); } void WebRTCPeerConnectionJS::_on_session_created(void *p_obj, const char *p_type, const char *p_session) { WebRTCPeerConnectionJS *peer = static_cast<WebRTCPeerConnectionJS *>(p_obj); - peer->emit_signal("session_description_created", String(p_type), String(p_session)); + peer->emit_signal(SNAME("session_description_created"), String(p_type), String(p_session)); } void WebRTCPeerConnectionJS::_on_connection_state_changed(void *p_obj, int p_state) { @@ -58,7 +57,7 @@ void WebRTCPeerConnectionJS::_on_error(void *p_obj) { void WebRTCPeerConnectionJS::_on_data_channel(void *p_obj, int p_id) { WebRTCPeerConnectionJS *peer = static_cast<WebRTCPeerConnectionJS *>(p_obj); - peer->emit_signal("data_channel_received", Ref<WebRTCDataChannelJS>(new WebRTCDataChannelJS(p_id))); + peer->emit_signal(SNAME("data_channel_received"), Ref<WebRTCDataChannelJS>(new WebRTCDataChannelJS(p_id))); } void WebRTCPeerConnectionJS::close() { @@ -100,7 +99,7 @@ Error WebRTCPeerConnectionJS::initialize(Dictionary p_config) { } _conn_state = STATE_NEW; - String config = JSON::print(p_config); + String config = Variant(p_config).to_json_string(); _js_id = godot_js_rtc_pc_create(config.utf8().get_data(), this, &_on_connection_state_changed, &_on_ice_candidate, &_on_data_channel); return _js_id ? OK : FAILED; } @@ -108,7 +107,7 @@ Error WebRTCPeerConnectionJS::initialize(Dictionary p_config) { Ref<WebRTCDataChannel> WebRTCPeerConnectionJS::create_data_channel(String p_channel, Dictionary p_channel_config) { ERR_FAIL_COND_V(_conn_state != STATE_NEW, nullptr); - String config = JSON::print(p_channel_config); + String config = Variant(p_channel_config).to_json_string(); int id = godot_js_rtc_pc_datachannel_create(_js_id, p_channel.utf8().get_data(), config.utf8().get_data()); ERR_FAIL_COND_V(id == 0, nullptr); return memnew(WebRTCDataChannelJS(id)); diff --git a/modules/webrtc/webrtc_peer_connection_js.h b/modules/webrtc/webrtc_peer_connection_js.h index 0272e67f6f..d2beccaf03 100644 --- a/modules/webrtc/webrtc_peer_connection_js.h +++ b/modules/webrtc/webrtc_peer_connection_js.h @@ -63,9 +63,6 @@ private: static void _on_error(void *p_obj); public: - static WebRTCPeerConnection *_create() { return memnew(WebRTCPeerConnectionJS); } - static void make_default() { WebRTCPeerConnection::_create = WebRTCPeerConnectionJS::_create; } - virtual ConnectionState get_connection_state() const; virtual Error initialize(Dictionary configuration = Dictionary()); |