mirror of
https://github.com/Relintai/pandemonium_engine.git
synced 2025-02-06 16:16:06 +01:00
After thinking about it removed the webrtc module alltogether.
This commit is contained in:
parent
ca1d12b6b6
commit
e89f0b56dc
@ -1,12 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
Import("env")
|
||||
Import("env_modules")
|
||||
|
||||
env_webrtc = env_modules.Clone()
|
||||
|
||||
if env["platform"] == "javascript":
|
||||
# Our JavaScript/C++ interface.
|
||||
env.AddJSLibraries(["library_godot_webrtc.js"])
|
||||
|
||||
env_webrtc.add_source_files(env.modules_sources, "*.cpp")
|
@ -1,14 +0,0 @@
|
||||
def can_build(env, platform):
|
||||
return True
|
||||
|
||||
|
||||
def configure(env):
|
||||
pass
|
||||
|
||||
|
||||
def get_doc_classes():
|
||||
return ["WebRTCPeerConnection", "WebRTCDataChannel", "WebRTCMultiplayer"]
|
||||
|
||||
|
||||
def get_doc_path():
|
||||
return "doc_classes"
|
@ -1,111 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="WebRTCDataChannel" inherits="PacketPeer" version="3.5">
|
||||
<brief_description>
|
||||
</brief_description>
|
||||
<description>
|
||||
</description>
|
||||
<tutorials>
|
||||
</tutorials>
|
||||
<methods>
|
||||
<method name="close">
|
||||
<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" />
|
||||
<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" />
|
||||
<description>
|
||||
Returns the label assigned to this channel during creation.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_max_packet_life_time" qualifiers="const">
|
||||
<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" />
|
||||
<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" />
|
||||
<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" />
|
||||
<description>
|
||||
Returns the current state of this channel, see [enum ChannelState].
|
||||
</description>
|
||||
</method>
|
||||
<method name="is_negotiated" qualifiers="const">
|
||||
<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" />
|
||||
<description>
|
||||
Returns [code]true[/code] if this channel was created with ordering enabled (default).
|
||||
</description>
|
||||
</method>
|
||||
<method name="poll">
|
||||
<return type="int" enum="Error" />
|
||||
<description>
|
||||
Reserved, but not used for now.
|
||||
</description>
|
||||
</method>
|
||||
<method name="was_string_packet" qualifiers="const">
|
||||
<return type="bool" />
|
||||
<description>
|
||||
Returns [code]true[/code] if the last received packet was transferred as text. See [member write_mode].
|
||||
</description>
|
||||
</method>
|
||||
</methods>
|
||||
<members>
|
||||
<member name="write_mode" type="int" setter="set_write_mode" getter="get_write_mode" enum="WebRTCDataChannel.WriteMode">
|
||||
The transfer mode to use when sending outgoing packet. Either text or binary.
|
||||
</member>
|
||||
</members>
|
||||
<constants>
|
||||
<constant name="WRITE_MODE_TEXT" value="0" enum="WriteMode">
|
||||
Tells the channel to send data over this channel as text. An external peer (non-Godot) would receive this as a string.
|
||||
</constant>
|
||||
<constant name="WRITE_MODE_BINARY" value="1" enum="WriteMode">
|
||||
Tells the channel to send data over this channel as binary. An external peer (non-Godot) would receive this as array buffer or blob.
|
||||
</constant>
|
||||
<constant name="STATE_CONNECTING" value="0" enum="ChannelState">
|
||||
The channel was created, but it's still trying to connect.
|
||||
</constant>
|
||||
<constant name="STATE_OPEN" value="1" enum="ChannelState">
|
||||
The channel is currently open, and data can flow over it.
|
||||
</constant>
|
||||
<constant name="STATE_CLOSING" value="2" enum="ChannelState">
|
||||
The channel is being closed, no new messages will be accepted, but those already in queue will be flushed.
|
||||
</constant>
|
||||
<constant name="STATE_CLOSED" value="3" enum="ChannelState">
|
||||
The channel was closed, or connection failed.
|
||||
</constant>
|
||||
</constants>
|
||||
</class>
|
@ -1,70 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="WebRTCMultiplayer" inherits="NetworkedMultiplayerPeer" version="3.5">
|
||||
<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].
|
||||
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].
|
||||
</description>
|
||||
<tutorials>
|
||||
</tutorials>
|
||||
<methods>
|
||||
<method name="add_peer">
|
||||
<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" />
|
||||
<description>
|
||||
Close all the add peer connections and channels, freeing all resources.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_peer">
|
||||
<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" />
|
||||
<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" />
|
||||
<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" />
|
||||
<argument index="0" name="peer_id" type="int" />
|
||||
<argument index="1" name="server_compatibility" type="bool" default="false" />
|
||||
<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].
|
||||
</description>
|
||||
</method>
|
||||
<method name="remove_peer">
|
||||
<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.
|
||||
</description>
|
||||
</method>
|
||||
</methods>
|
||||
<constants>
|
||||
</constants>
|
||||
</class>
|
@ -1,164 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="WebRTCPeerConnection" inherits="Reference" version="3.5">
|
||||
<brief_description>
|
||||
Interface to a WebRTC peer connection.
|
||||
</brief_description>
|
||||
<description>
|
||||
A WebRTC connection between the local computer and a remote peer. Provides an interface to connect, maintain and monitor the connection.
|
||||
Setting up a WebRTC connection between two peers from now on) may not seem a trivial task, but it can be broken down into 3 main steps:
|
||||
- The peer that wants to initiate the connection ([code]A[/code] from now on) creates an offer and send it to the other peer ([code]B[/code] from now on).
|
||||
- [code]B[/code] receives the offer, generate and answer, and sends it to [code]A[/code]).
|
||||
- [code]A[/code] and [code]B[/code] then generates and exchange ICE candidates with each other.
|
||||
After these steps, the connection should become connected. Keep on reading or look into the tutorial for more information.
|
||||
</description>
|
||||
<tutorials>
|
||||
</tutorials>
|
||||
<methods>
|
||||
<method name="add_ice_candidate">
|
||||
<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" />
|
||||
<description>
|
||||
Close the peer connection and all data channels associated with it.
|
||||
[b]Note:[/b] You cannot reuse this object for a new connection unless you call [method initialize].
|
||||
</description>
|
||||
</method>
|
||||
<method name="create_data_channel">
|
||||
<return type="WebRTCDataChannel" />
|
||||
<argument index="0" name="label" type="String" />
|
||||
<argument index="1" name="options" type="Dictionary" default="{
|
||||
}" />
|
||||
<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.
|
||||
"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).
|
||||
"maxRetransmits": 1, # Specify the maximum number of attempt the peer will make to retransmits packets if they are not acknowledged.
|
||||
"maxPacketLifeTime": 100, # Specify the maximum amount of time before giving up retransmitions of unacknowledged packets (in milliseconds).
|
||||
"ordered": true, # When in unreliable mode (i.e. either "maxRetransmits" or "maxPacketLifetime" is set), "ordered" (true by default) specify if packet ordering is to be enforced.
|
||||
|
||||
"protocol": "my-custom-protocol", # A custom sub-protocol string for this channel.
|
||||
}
|
||||
[/codeblock]
|
||||
[b]Note:[/b] You must keep a reference to channels created this way, or it will be closed.
|
||||
</description>
|
||||
</method>
|
||||
<method name="create_offer">
|
||||
<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" />
|
||||
<description>
|
||||
Returns the connection state. See [enum ConnectionState].
|
||||
</description>
|
||||
</method>
|
||||
<method name="initialize">
|
||||
<return type="int" enum="Error" />
|
||||
<argument index="0" name="configuration" type="Dictionary" default="{
|
||||
}" />
|
||||
<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:
|
||||
[codeblock]
|
||||
{
|
||||
"iceServers": [
|
||||
{
|
||||
"urls": [ "stun:stun.example.com:3478" ], # One or more STUN servers.
|
||||
},
|
||||
{
|
||||
"urls": [ "turn:turn.example.com:3478" ], # One or more TURN servers.
|
||||
"username": "a_username", # Optional username for the TURN server.
|
||||
"credential": "a_password", # Optional password for the TURN server.
|
||||
}
|
||||
]
|
||||
}
|
||||
[/codeblock]
|
||||
</description>
|
||||
</method>
|
||||
<method name="poll">
|
||||
<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" />
|
||||
<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" />
|
||||
<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.
|
||||
If [code]type[/code] is [code]answer[/code] the peer will start emitting [signal ice_candidate_created].
|
||||
</description>
|
||||
</method>
|
||||
</methods>
|
||||
<signals>
|
||||
<signal name="data_channel_received">
|
||||
<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 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 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>
|
||||
</signal>
|
||||
</signals>
|
||||
<constants>
|
||||
<constant name="STATE_NEW" value="0" enum="ConnectionState">
|
||||
The connection is new, data channels and an offer can be created in this state.
|
||||
</constant>
|
||||
<constant name="STATE_CONNECTING" value="1" enum="ConnectionState">
|
||||
The peer is connecting, ICE is in progress, none of the transports has failed.
|
||||
</constant>
|
||||
<constant name="STATE_CONNECTED" value="2" enum="ConnectionState">
|
||||
The peer is connected, all ICE transports are connected.
|
||||
</constant>
|
||||
<constant name="STATE_DISCONNECTED" value="3" enum="ConnectionState">
|
||||
At least one ICE transport is disconnected.
|
||||
</constant>
|
||||
<constant name="STATE_FAILED" value="4" enum="ConnectionState">
|
||||
One or more of the ICE transports failed.
|
||||
</constant>
|
||||
<constant name="STATE_CLOSED" value="5" enum="ConnectionState">
|
||||
The peer connection is closed (after calling [method close] for example).
|
||||
</constant>
|
||||
</constants>
|
||||
</class>
|
@ -1,438 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* library_godot_webrtc.js */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
const GodotRTCDataChannel = {
|
||||
// Our socket implementation that forwards events to C++.
|
||||
$GodotRTCDataChannel__deps: ['$IDHandler', '$GodotRuntime'],
|
||||
$GodotRTCDataChannel: {
|
||||
connect: function (p_id, p_on_open, p_on_message, p_on_error, p_on_close) {
|
||||
const ref = IDHandler.get(p_id);
|
||||
if (!ref) {
|
||||
return;
|
||||
}
|
||||
|
||||
ref.binaryType = 'arraybuffer';
|
||||
ref.onopen = function (event) {
|
||||
p_on_open();
|
||||
};
|
||||
ref.onclose = function (event) {
|
||||
p_on_close();
|
||||
};
|
||||
ref.onerror = function (event) {
|
||||
p_on_error();
|
||||
};
|
||||
ref.onmessage = function (event) {
|
||||
let buffer;
|
||||
let is_string = 0;
|
||||
if (event.data instanceof ArrayBuffer) {
|
||||
buffer = new Uint8Array(event.data);
|
||||
} else if (event.data instanceof Blob) {
|
||||
GodotRuntime.error('Blob type not supported');
|
||||
return;
|
||||
} else if (typeof event.data === 'string') {
|
||||
is_string = 1;
|
||||
const enc = new TextEncoder('utf-8');
|
||||
buffer = new Uint8Array(enc.encode(event.data));
|
||||
} else {
|
||||
GodotRuntime.error('Unknown message type');
|
||||
return;
|
||||
}
|
||||
const len = buffer.length * buffer.BYTES_PER_ELEMENT;
|
||||
const out = GodotRuntime.malloc(len);
|
||||
HEAPU8.set(buffer, out);
|
||||
p_on_message(out, len, is_string);
|
||||
GodotRuntime.free(out);
|
||||
};
|
||||
},
|
||||
|
||||
close: function (p_id) {
|
||||
const ref = IDHandler.get(p_id);
|
||||
if (!ref) {
|
||||
return;
|
||||
}
|
||||
ref.onopen = null;
|
||||
ref.onmessage = null;
|
||||
ref.onerror = null;
|
||||
ref.onclose = null;
|
||||
ref.close();
|
||||
},
|
||||
|
||||
get_prop: function (p_id, p_prop, p_def) {
|
||||
const ref = IDHandler.get(p_id);
|
||||
return (ref && ref[p_prop] !== undefined) ? ref[p_prop] : p_def;
|
||||
},
|
||||
},
|
||||
|
||||
godot_js_rtc_datachannel_ready_state_get__sig: 'ii',
|
||||
godot_js_rtc_datachannel_ready_state_get: function (p_id) {
|
||||
const ref = IDHandler.get(p_id);
|
||||
if (!ref) {
|
||||
return 3; // CLOSED
|
||||
}
|
||||
|
||||
switch (ref.readyState) {
|
||||
case 'connecting':
|
||||
return 0;
|
||||
case 'open':
|
||||
return 1;
|
||||
case 'closing':
|
||||
return 2;
|
||||
case 'closed':
|
||||
default:
|
||||
return 3;
|
||||
}
|
||||
},
|
||||
|
||||
godot_js_rtc_datachannel_send__sig: 'iiiii',
|
||||
godot_js_rtc_datachannel_send: function (p_id, p_buffer, p_length, p_raw) {
|
||||
const ref = IDHandler.get(p_id);
|
||||
if (!ref) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
const bytes_array = new Uint8Array(p_length);
|
||||
for (let i = 0; i < p_length; i++) {
|
||||
bytes_array[i] = GodotRuntime.getHeapValue(p_buffer + i, 'i8');
|
||||
}
|
||||
|
||||
if (p_raw) {
|
||||
ref.send(bytes_array.buffer);
|
||||
} else {
|
||||
const string = new TextDecoder('utf-8').decode(bytes_array);
|
||||
ref.send(string);
|
||||
}
|
||||
return 0;
|
||||
},
|
||||
|
||||
godot_js_rtc_datachannel_is_ordered__sig: 'ii',
|
||||
godot_js_rtc_datachannel_is_ordered: function (p_id) {
|
||||
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 GodotRTCDataChannel.get_prop(p_id, 'id', 65535);
|
||||
},
|
||||
|
||||
godot_js_rtc_datachannel_max_packet_lifetime_get__sig: 'ii',
|
||||
godot_js_rtc_datachannel_max_packet_lifetime_get: function (p_id) {
|
||||
const ref = IDHandler.get(p_id);
|
||||
if (!ref) {
|
||||
return 65535;
|
||||
}
|
||||
if (ref['maxPacketLifeTime'] !== undefined) {
|
||||
return ref['maxPacketLifeTime'];
|
||||
} else if (ref['maxRetransmitTime'] !== undefined) {
|
||||
// Guess someone didn't appreciate the standardization process.
|
||||
return ref['maxRetransmitTime'];
|
||||
}
|
||||
return 65535;
|
||||
},
|
||||
|
||||
godot_js_rtc_datachannel_max_retransmits_get__sig: 'ii',
|
||||
godot_js_rtc_datachannel_max_retransmits_get: function (p_id) {
|
||||
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 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',
|
||||
godot_js_rtc_datachannel_label_get: function (p_id) {
|
||||
const ref = IDHandler.get(p_id);
|
||||
if (!ref || !ref.label) {
|
||||
return 0;
|
||||
}
|
||||
return GodotRuntime.allocString(ref.label);
|
||||
},
|
||||
|
||||
godot_js_rtc_datachannel_protocol_get__sig: 'ii',
|
||||
godot_js_rtc_datachannel_protocol_get: function (p_id) {
|
||||
const ref = IDHandler.get(p_id);
|
||||
if (!ref || !ref.protocol) {
|
||||
return 0;
|
||||
}
|
||||
return GodotRuntime.allocString(ref.protocol);
|
||||
},
|
||||
|
||||
godot_js_rtc_datachannel_destroy__sig: 'vi',
|
||||
godot_js_rtc_datachannel_destroy: function (p_id) {
|
||||
GodotRTCDataChannel.close(p_id);
|
||||
IDHandler.remove(p_id);
|
||||
},
|
||||
|
||||
godot_js_rtc_datachannel_connect__sig: 'viiiiii',
|
||||
godot_js_rtc_datachannel_connect: function (p_id, p_ref, p_on_open, p_on_message, p_on_error, p_on_close) {
|
||||
const onopen = GodotRuntime.get_func(p_on_open).bind(null, p_ref);
|
||||
const onmessage = GodotRuntime.get_func(p_on_message).bind(null, p_ref);
|
||||
const onerror = GodotRuntime.get_func(p_on_error).bind(null, p_ref);
|
||||
const onclose = GodotRuntime.get_func(p_on_close).bind(null, p_ref);
|
||||
GodotRTCDataChannel.connect(p_id, onopen, onmessage, onerror, onclose);
|
||||
},
|
||||
|
||||
godot_js_rtc_datachannel_close__sig: 'vi',
|
||||
godot_js_rtc_datachannel_close: function (p_id) {
|
||||
const ref = IDHandler.get(p_id);
|
||||
if (!ref) {
|
||||
return;
|
||||
}
|
||||
GodotRTCDataChannel.close(p_id);
|
||||
},
|
||||
};
|
||||
|
||||
autoAddDeps(GodotRTCDataChannel, '$GodotRTCDataChannel');
|
||||
mergeInto(LibraryManager.library, GodotRTCDataChannel);
|
||||
|
||||
const GodotRTCPeerConnection = {
|
||||
$GodotRTCPeerConnection__deps: ['$IDHandler', '$GodotRuntime', '$GodotRTCDataChannel'],
|
||||
$GodotRTCPeerConnection: {
|
||||
onstatechange: function (p_id, p_conn, callback, event) {
|
||||
const ref = IDHandler.get(p_id);
|
||||
if (!ref) {
|
||||
return;
|
||||
}
|
||||
let state;
|
||||
switch (p_conn.iceConnectionState) {
|
||||
case 'new':
|
||||
state = 0;
|
||||
break;
|
||||
case 'checking':
|
||||
state = 1;
|
||||
break;
|
||||
case 'connected':
|
||||
case 'completed':
|
||||
state = 2;
|
||||
break;
|
||||
case 'disconnected':
|
||||
state = 3;
|
||||
break;
|
||||
case 'failed':
|
||||
state = 4;
|
||||
break;
|
||||
case 'closed':
|
||||
default:
|
||||
state = 5;
|
||||
break;
|
||||
}
|
||||
callback(state);
|
||||
},
|
||||
|
||||
onicecandidate: function (p_id, callback, event) {
|
||||
const ref = IDHandler.get(p_id);
|
||||
if (!ref || !event.candidate) {
|
||||
return;
|
||||
}
|
||||
|
||||
const c = event.candidate;
|
||||
const candidate_str = GodotRuntime.allocString(c.candidate);
|
||||
const mid_str = GodotRuntime.allocString(c.sdpMid);
|
||||
callback(mid_str, c.sdpMLineIndex, candidate_str);
|
||||
GodotRuntime.free(candidate_str);
|
||||
GodotRuntime.free(mid_str);
|
||||
},
|
||||
|
||||
ondatachannel: function (p_id, callback, event) {
|
||||
const ref = IDHandler.get(p_id);
|
||||
if (!ref) {
|
||||
return;
|
||||
}
|
||||
|
||||
const cid = IDHandler.add(event.channel);
|
||||
callback(cid);
|
||||
},
|
||||
|
||||
onsession: function (p_id, callback, session) {
|
||||
const ref = IDHandler.get(p_id);
|
||||
if (!ref) {
|
||||
return;
|
||||
}
|
||||
const type_str = GodotRuntime.allocString(session.type);
|
||||
const sdp_str = GodotRuntime.allocString(session.sdp);
|
||||
callback(type_str, sdp_str);
|
||||
GodotRuntime.free(type_str);
|
||||
GodotRuntime.free(sdp_str);
|
||||
},
|
||||
|
||||
onerror: function (p_id, callback, error) {
|
||||
const ref = IDHandler.get(p_id);
|
||||
if (!ref) {
|
||||
return;
|
||||
}
|
||||
GodotRuntime.error(error);
|
||||
callback();
|
||||
},
|
||||
},
|
||||
|
||||
godot_js_rtc_pc_create__sig: 'iiiiii',
|
||||
godot_js_rtc_pc_create: function (p_config, p_ref, p_on_state_change, p_on_candidate, p_on_datachannel) {
|
||||
const onstatechange = GodotRuntime.get_func(p_on_state_change).bind(null, p_ref);
|
||||
const oncandidate = GodotRuntime.get_func(p_on_candidate).bind(null, p_ref);
|
||||
const ondatachannel = GodotRuntime.get_func(p_on_datachannel).bind(null, p_ref);
|
||||
|
||||
const config = JSON.parse(GodotRuntime.parseString(p_config));
|
||||
let conn = null;
|
||||
try {
|
||||
conn = new RTCPeerConnection(config);
|
||||
} catch (e) {
|
||||
GodotRuntime.error(e);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const base = GodotRTCPeerConnection;
|
||||
const id = IDHandler.add(conn);
|
||||
conn.oniceconnectionstatechange = base.onstatechange.bind(null, id, conn, onstatechange);
|
||||
conn.onicecandidate = base.onicecandidate.bind(null, id, oncandidate);
|
||||
conn.ondatachannel = base.ondatachannel.bind(null, id, ondatachannel);
|
||||
return id;
|
||||
},
|
||||
|
||||
godot_js_rtc_pc_close__sig: 'vi',
|
||||
godot_js_rtc_pc_close: function (p_id) {
|
||||
const ref = IDHandler.get(p_id);
|
||||
if (!ref) {
|
||||
return;
|
||||
}
|
||||
ref.close();
|
||||
},
|
||||
|
||||
godot_js_rtc_pc_destroy__sig: 'vi',
|
||||
godot_js_rtc_pc_destroy: function (p_id) {
|
||||
const ref = IDHandler.get(p_id);
|
||||
if (!ref) {
|
||||
return;
|
||||
}
|
||||
ref.oniceconnectionstatechange = null;
|
||||
ref.onicecandidate = null;
|
||||
ref.ondatachannel = null;
|
||||
IDHandler.remove(p_id);
|
||||
},
|
||||
|
||||
godot_js_rtc_pc_offer_create__sig: 'viiii',
|
||||
godot_js_rtc_pc_offer_create: function (p_id, p_obj, p_on_session, p_on_error) {
|
||||
const ref = IDHandler.get(p_id);
|
||||
if (!ref) {
|
||||
return;
|
||||
}
|
||||
const onsession = GodotRuntime.get_func(p_on_session).bind(null, p_obj);
|
||||
const onerror = GodotRuntime.get_func(p_on_error).bind(null, p_obj);
|
||||
ref.createOffer().then(function (session) {
|
||||
GodotRTCPeerConnection.onsession(p_id, onsession, session);
|
||||
}).catch(function (error) {
|
||||
GodotRTCPeerConnection.onerror(p_id, onerror, error);
|
||||
});
|
||||
},
|
||||
|
||||
godot_js_rtc_pc_local_description_set__sig: 'viiiii',
|
||||
godot_js_rtc_pc_local_description_set: function (p_id, p_type, p_sdp, p_obj, p_on_error) {
|
||||
const ref = IDHandler.get(p_id);
|
||||
if (!ref) {
|
||||
return;
|
||||
}
|
||||
const type = GodotRuntime.parseString(p_type);
|
||||
const sdp = GodotRuntime.parseString(p_sdp);
|
||||
const onerror = GodotRuntime.get_func(p_on_error).bind(null, p_obj);
|
||||
ref.setLocalDescription({
|
||||
'sdp': sdp,
|
||||
'type': type,
|
||||
}).catch(function (error) {
|
||||
GodotRTCPeerConnection.onerror(p_id, onerror, error);
|
||||
});
|
||||
},
|
||||
|
||||
godot_js_rtc_pc_remote_description_set__sig: 'viiiiii',
|
||||
godot_js_rtc_pc_remote_description_set: function (p_id, p_type, p_sdp, p_obj, p_session_created, p_on_error) {
|
||||
const ref = IDHandler.get(p_id);
|
||||
if (!ref) {
|
||||
return;
|
||||
}
|
||||
const type = GodotRuntime.parseString(p_type);
|
||||
const sdp = GodotRuntime.parseString(p_sdp);
|
||||
const onerror = GodotRuntime.get_func(p_on_error).bind(null, p_obj);
|
||||
const onsession = GodotRuntime.get_func(p_session_created).bind(null, p_obj);
|
||||
ref.setRemoteDescription({
|
||||
'sdp': sdp,
|
||||
'type': type,
|
||||
}).then(function () {
|
||||
if (type !== 'offer') {
|
||||
return Promise.resolve();
|
||||
}
|
||||
return ref.createAnswer().then(function (session) {
|
||||
GodotRTCPeerConnection.onsession(p_id, onsession, session);
|
||||
});
|
||||
}).catch(function (error) {
|
||||
GodotRTCPeerConnection.onerror(p_id, onerror, error);
|
||||
});
|
||||
},
|
||||
|
||||
godot_js_rtc_pc_ice_candidate_add__sig: 'viiii',
|
||||
godot_js_rtc_pc_ice_candidate_add: function (p_id, p_mid_name, p_mline_idx, p_sdp) {
|
||||
const ref = IDHandler.get(p_id);
|
||||
if (!ref) {
|
||||
return;
|
||||
}
|
||||
const sdpMidName = GodotRuntime.parseString(p_mid_name);
|
||||
const sdpName = GodotRuntime.parseString(p_sdp);
|
||||
ref.addIceCandidate(new RTCIceCandidate({
|
||||
'candidate': sdpName,
|
||||
'sdpMid': sdpMidName,
|
||||
'sdpMlineIndex': p_mline_idx,
|
||||
}));
|
||||
},
|
||||
|
||||
godot_js_rtc_pc_datachannel_create__deps: ['$GodotRTCDataChannel'],
|
||||
godot_js_rtc_pc_datachannel_create__sig: 'iiii',
|
||||
godot_js_rtc_pc_datachannel_create: function (p_id, p_label, p_config) {
|
||||
try {
|
||||
const ref = IDHandler.get(p_id);
|
||||
if (!ref) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const label = GodotRuntime.parseString(p_label);
|
||||
const config = JSON.parse(GodotRuntime.parseString(p_config));
|
||||
|
||||
const channel = ref.createDataChannel(label, config);
|
||||
return IDHandler.add(channel);
|
||||
} catch (e) {
|
||||
GodotRuntime.error(e);
|
||||
return 0;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
autoAddDeps(GodotRTCPeerConnection, '$GodotRTCPeerConnection');
|
||||
mergeInto(LibraryManager.library, GodotRTCPeerConnection);
|
@ -1,62 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* register_types.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "register_types.h"
|
||||
#include "core/project_settings.h"
|
||||
#include "webrtc_data_channel.h"
|
||||
#include "webrtc_peer_connection.h"
|
||||
|
||||
#ifdef JAVASCRIPT_ENABLED
|
||||
#include "emscripten.h"
|
||||
#include "webrtc_peer_connection_js.h"
|
||||
#endif
|
||||
|
||||
#include "webrtc_multiplayer.h"
|
||||
|
||||
void register_webrtc_types() {
|
||||
#define _SET_HINT(NAME, _VAL_, _MAX_) \
|
||||
GLOBAL_DEF(NAME, _VAL_); \
|
||||
ProjectSettings::get_singleton()->set_custom_property_info(NAME, PropertyInfo(Variant::INT, NAME, PROPERTY_HINT_RANGE, "2," #_MAX_ ",1,or_greater"));
|
||||
|
||||
_SET_HINT(WRTC_IN_BUF, 64, 4096);
|
||||
|
||||
#ifdef JAVASCRIPT_ENABLED
|
||||
WebRTCPeerConnectionJS::make_default();
|
||||
#else
|
||||
WebRTCPeerConnection::make_default();
|
||||
#endif
|
||||
|
||||
ClassDB::register_custom_instance_class<WebRTCPeerConnection>();
|
||||
|
||||
ClassDB::register_virtual_class<WebRTCDataChannel>();
|
||||
ClassDB::register_class<WebRTCMultiplayer>();
|
||||
}
|
||||
|
||||
void unregister_webrtc_types() {}
|
@ -1,36 +0,0 @@
|
||||
#ifndef WEBRTC_REGISTER_TYPES_H
|
||||
#define WEBRTC_REGISTER_TYPES_H
|
||||
/*************************************************************************/
|
||||
/* register_types.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
void register_webrtc_types();
|
||||
void unregister_webrtc_types();
|
||||
|
||||
#endif // WEBRTC_REGISTER_TYPES_H
|
@ -1,67 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* webrtc_data_channel.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 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.h"
|
||||
#include "core/project_settings.h"
|
||||
|
||||
void WebRTCDataChannel::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("poll"), &WebRTCDataChannel::poll);
|
||||
ClassDB::bind_method(D_METHOD("close"), &WebRTCDataChannel::close);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("was_string_packet"), &WebRTCDataChannel::was_string_packet);
|
||||
ClassDB::bind_method(D_METHOD("set_write_mode", "write_mode"), &WebRTCDataChannel::set_write_mode);
|
||||
ClassDB::bind_method(D_METHOD("get_write_mode"), &WebRTCDataChannel::get_write_mode);
|
||||
ClassDB::bind_method(D_METHOD("get_ready_state"), &WebRTCDataChannel::get_ready_state);
|
||||
ClassDB::bind_method(D_METHOD("get_label"), &WebRTCDataChannel::get_label);
|
||||
ClassDB::bind_method(D_METHOD("is_ordered"), &WebRTCDataChannel::is_ordered);
|
||||
ClassDB::bind_method(D_METHOD("get_id"), &WebRTCDataChannel::get_id);
|
||||
ClassDB::bind_method(D_METHOD("get_max_packet_life_time"), &WebRTCDataChannel::get_max_packet_life_time);
|
||||
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");
|
||||
|
||||
BIND_ENUM_CONSTANT(WRITE_MODE_TEXT);
|
||||
BIND_ENUM_CONSTANT(WRITE_MODE_BINARY);
|
||||
|
||||
BIND_ENUM_CONSTANT(STATE_CONNECTING);
|
||||
BIND_ENUM_CONSTANT(STATE_OPEN);
|
||||
BIND_ENUM_CONSTANT(STATE_CLOSING);
|
||||
BIND_ENUM_CONSTANT(STATE_CLOSED);
|
||||
}
|
||||
|
||||
WebRTCDataChannel::WebRTCDataChannel() {
|
||||
_in_buffer_shift = nearest_shift((int)GLOBAL_GET(WRTC_IN_BUF) - 1) + 10;
|
||||
}
|
||||
|
||||
WebRTCDataChannel::~WebRTCDataChannel() {
|
||||
}
|
@ -1,90 +0,0 @@
|
||||
#ifndef WEBRTC_DATA_CHANNEL_H
|
||||
#define WEBRTC_DATA_CHANNEL_H
|
||||
/*************************************************************************/
|
||||
/* webrtc_data_channel.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 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 "core/io/packet_peer.h"
|
||||
|
||||
#define WRTC_IN_BUF "network/limits/webrtc/max_channel_in_buffer_kb"
|
||||
|
||||
class WebRTCDataChannel : public PacketPeer {
|
||||
GDCLASS(WebRTCDataChannel, PacketPeer);
|
||||
|
||||
public:
|
||||
enum WriteMode {
|
||||
WRITE_MODE_TEXT,
|
||||
WRITE_MODE_BINARY,
|
||||
};
|
||||
|
||||
enum ChannelState {
|
||||
STATE_CONNECTING,
|
||||
STATE_OPEN,
|
||||
STATE_CLOSING,
|
||||
STATE_CLOSED
|
||||
};
|
||||
|
||||
protected:
|
||||
unsigned int _in_buffer_shift;
|
||||
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
virtual void set_write_mode(WriteMode mode) = 0;
|
||||
virtual WriteMode get_write_mode() const = 0;
|
||||
virtual bool was_string_packet() const = 0;
|
||||
|
||||
virtual ChannelState get_ready_state() const = 0;
|
||||
virtual String 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 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;
|
||||
|
||||
/** Inherited from PacketPeer: **/
|
||||
virtual int get_available_packet_count() const = 0;
|
||||
virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size) = 0; ///< buffer is GONE after next get_packet
|
||||
virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size) = 0;
|
||||
|
||||
virtual int get_max_packet_size() const = 0;
|
||||
|
||||
WebRTCDataChannel();
|
||||
~WebRTCDataChannel();
|
||||
};
|
||||
|
||||
VARIANT_ENUM_CAST(WebRTCDataChannel::WriteMode);
|
||||
VARIANT_ENUM_CAST(WebRTCDataChannel::ChannelState);
|
||||
#endif // WEBRTC_DATA_CHANNEL_H
|
@ -1,220 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* webrtc_data_channel_js.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifdef JAVASCRIPT_ENABLED
|
||||
|
||||
#include "webrtc_data_channel_js.h"
|
||||
#include "emscripten.h"
|
||||
|
||||
extern "C" {
|
||||
typedef void (*RTCChOnOpen)(void *p_obj);
|
||||
typedef void (*RTCChOnMessage)(void *p_obj, const uint8_t *p_buffer, int p_size, int p_is_string);
|
||||
typedef void (*RTCChOnClose)(void *p_obj);
|
||||
typedef void (*RTCChOnError)(void *p_obj);
|
||||
|
||||
extern int godot_js_rtc_datachannel_ready_state_get(int p_id);
|
||||
extern int godot_js_rtc_datachannel_send(int p_id, const uint8_t *p_buffer, int p_length, int p_raw);
|
||||
extern int godot_js_rtc_datachannel_is_ordered(int p_id);
|
||||
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);
|
||||
extern void godot_js_rtc_datachannel_connect(int p_id, void *p_obj, RTCChOnOpen p_on_open, RTCChOnMessage p_on_message, RTCChOnError p_on_error, RTCChOnClose p_on_close);
|
||||
extern void godot_js_rtc_datachannel_close(int p_id);
|
||||
}
|
||||
|
||||
void WebRTCDataChannelJS::_on_open(void *p_obj) {
|
||||
WebRTCDataChannelJS *peer = static_cast<WebRTCDataChannelJS *>(p_obj);
|
||||
peer->in_buffer.resize(peer->_in_buffer_shift);
|
||||
}
|
||||
|
||||
void WebRTCDataChannelJS::_on_close(void *p_obj) {
|
||||
WebRTCDataChannelJS *peer = static_cast<WebRTCDataChannelJS *>(p_obj);
|
||||
peer->close();
|
||||
}
|
||||
|
||||
void WebRTCDataChannelJS::_on_error(void *p_obj) {
|
||||
WebRTCDataChannelJS *peer = static_cast<WebRTCDataChannelJS *>(p_obj);
|
||||
peer->close();
|
||||
}
|
||||
|
||||
void WebRTCDataChannelJS::_on_message(void *p_obj, const uint8_t *p_data, int p_size, int p_is_string) {
|
||||
WebRTCDataChannelJS *peer = static_cast<WebRTCDataChannelJS *>(p_obj);
|
||||
RingBuffer<uint8_t> &in_buffer = peer->in_buffer;
|
||||
|
||||
ERR_FAIL_COND_MSG(in_buffer.space_left() < (int)(p_size + 5), "Buffer full! Dropping data.");
|
||||
|
||||
uint8_t is_string = p_is_string ? 1 : 0;
|
||||
in_buffer.write((uint8_t *)&p_size, 4);
|
||||
in_buffer.write((uint8_t *)&is_string, 1);
|
||||
in_buffer.write(p_data, p_size);
|
||||
peer->queue_count++;
|
||||
}
|
||||
|
||||
void WebRTCDataChannelJS::close() {
|
||||
in_buffer.resize(0);
|
||||
queue_count = 0;
|
||||
_was_string = false;
|
||||
godot_js_rtc_datachannel_close(_js_id);
|
||||
}
|
||||
|
||||
Error WebRTCDataChannelJS::poll() {
|
||||
return OK;
|
||||
}
|
||||
|
||||
WebRTCDataChannelJS::ChannelState WebRTCDataChannelJS::get_ready_state() const {
|
||||
return (ChannelState)godot_js_rtc_datachannel_ready_state_get(_js_id);
|
||||
}
|
||||
|
||||
int WebRTCDataChannelJS::get_available_packet_count() const {
|
||||
return queue_count;
|
||||
}
|
||||
|
||||
Error WebRTCDataChannelJS::get_packet(const uint8_t **r_buffer, int &r_buffer_size) {
|
||||
ERR_FAIL_COND_V(get_ready_state() != STATE_OPEN, ERR_UNCONFIGURED);
|
||||
|
||||
if (queue_count == 0)
|
||||
return ERR_UNAVAILABLE;
|
||||
|
||||
uint32_t to_read = 0;
|
||||
uint32_t left = 0;
|
||||
uint8_t is_string = 0;
|
||||
r_buffer_size = 0;
|
||||
|
||||
in_buffer.read((uint8_t *)&to_read, 4);
|
||||
--queue_count;
|
||||
left = in_buffer.data_left();
|
||||
|
||||
if (left < to_read + 1) {
|
||||
in_buffer.advance_read(left);
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
in_buffer.read(&is_string, 1);
|
||||
_was_string = is_string == 1;
|
||||
in_buffer.read(packet_buffer, to_read);
|
||||
*r_buffer = packet_buffer;
|
||||
r_buffer_size = to_read;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
Error WebRTCDataChannelJS::put_packet(const uint8_t *p_buffer, int p_buffer_size) {
|
||||
ERR_FAIL_COND_V(get_ready_state() != STATE_OPEN, ERR_UNCONFIGURED);
|
||||
|
||||
int is_bin = _write_mode == WebRTCDataChannel::WRITE_MODE_BINARY ? 1 : 0;
|
||||
godot_js_rtc_datachannel_send(_js_id, p_buffer, p_buffer_size, is_bin);
|
||||
return OK;
|
||||
}
|
||||
|
||||
int WebRTCDataChannelJS::get_max_packet_size() const {
|
||||
return 1200;
|
||||
}
|
||||
|
||||
void WebRTCDataChannelJS::set_write_mode(WriteMode p_mode) {
|
||||
_write_mode = p_mode;
|
||||
}
|
||||
|
||||
WebRTCDataChannel::WriteMode WebRTCDataChannelJS::get_write_mode() const {
|
||||
return _write_mode;
|
||||
}
|
||||
|
||||
bool WebRTCDataChannelJS::was_string_packet() const {
|
||||
return _was_string;
|
||||
}
|
||||
|
||||
String WebRTCDataChannelJS::get_label() const {
|
||||
return _label;
|
||||
}
|
||||
|
||||
bool WebRTCDataChannelJS::is_ordered() const {
|
||||
return godot_js_rtc_datachannel_is_ordered(_js_id);
|
||||
}
|
||||
|
||||
int WebRTCDataChannelJS::get_id() const {
|
||||
return godot_js_rtc_datachannel_id_get(_js_id);
|
||||
}
|
||||
|
||||
int WebRTCDataChannelJS::get_max_packet_life_time() const {
|
||||
return godot_js_rtc_datachannel_max_packet_lifetime_get(_js_id);
|
||||
}
|
||||
|
||||
int WebRTCDataChannelJS::get_max_retransmits() const {
|
||||
return godot_js_rtc_datachannel_max_retransmits_get(_js_id);
|
||||
}
|
||||
|
||||
String WebRTCDataChannelJS::get_protocol() const {
|
||||
return _protocol;
|
||||
}
|
||||
|
||||
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() {
|
||||
queue_count = 0;
|
||||
_was_string = false;
|
||||
_write_mode = WRITE_MODE_BINARY;
|
||||
_js_id = 0;
|
||||
}
|
||||
|
||||
WebRTCDataChannelJS::WebRTCDataChannelJS(int js_id) {
|
||||
queue_count = 0;
|
||||
_was_string = false;
|
||||
_write_mode = WRITE_MODE_BINARY;
|
||||
_js_id = js_id;
|
||||
|
||||
godot_js_rtc_datachannel_connect(js_id, this, &_on_open, &_on_message, &_on_error, &_on_close);
|
||||
// Parse label
|
||||
char *label = godot_js_rtc_datachannel_label_get(js_id);
|
||||
if (label) {
|
||||
_label.parse_utf8(label);
|
||||
free(label);
|
||||
}
|
||||
char *protocol = godot_js_rtc_datachannel_protocol_get(js_id);
|
||||
if (protocol) {
|
||||
_protocol.parse_utf8(protocol);
|
||||
free(protocol);
|
||||
}
|
||||
}
|
||||
|
||||
WebRTCDataChannelJS::~WebRTCDataChannelJS() {
|
||||
close();
|
||||
godot_js_rtc_datachannel_destroy(_js_id);
|
||||
}
|
||||
#endif
|
@ -1,93 +0,0 @@
|
||||
#ifndef WEBRTC_DATA_CHANNEL_JS_H
|
||||
#define WEBRTC_DATA_CHANNEL_JS_H
|
||||
/*************************************************************************/
|
||||
/* webrtc_data_channel_js.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifdef JAVASCRIPT_ENABLED
|
||||
|
||||
#include "webrtc_data_channel.h"
|
||||
|
||||
class WebRTCDataChannelJS : public WebRTCDataChannel {
|
||||
GDCLASS(WebRTCDataChannelJS, WebRTCDataChannel);
|
||||
|
||||
private:
|
||||
String _label;
|
||||
String _protocol;
|
||||
|
||||
bool _was_string;
|
||||
WriteMode _write_mode;
|
||||
|
||||
enum {
|
||||
PACKET_BUFFER_SIZE = 65536 - 5 // 4 bytes for the size, 1 for for type
|
||||
};
|
||||
|
||||
int _js_id;
|
||||
RingBuffer<uint8_t> in_buffer;
|
||||
int queue_count;
|
||||
uint8_t packet_buffer[PACKET_BUFFER_SIZE];
|
||||
|
||||
static void _on_open(void *p_obj);
|
||||
static void _on_close(void *p_obj);
|
||||
static void _on_error(void *p_obj);
|
||||
static void _on_message(void *p_obj, const uint8_t *p_data, int p_size, int p_is_string);
|
||||
|
||||
public:
|
||||
virtual void set_write_mode(WriteMode mode);
|
||||
virtual WriteMode get_write_mode() const;
|
||||
virtual bool was_string_packet() const;
|
||||
|
||||
virtual ChannelState get_ready_state() const;
|
||||
virtual String get_label() const;
|
||||
virtual bool is_ordered() const;
|
||||
virtual int get_id() const;
|
||||
virtual int get_max_packet_life_time() const;
|
||||
virtual int get_max_retransmits() const;
|
||||
virtual String get_protocol() const;
|
||||
virtual bool is_negotiated() const;
|
||||
virtual int get_buffered_amount() const;
|
||||
|
||||
virtual Error poll();
|
||||
virtual void close();
|
||||
|
||||
/** Inherited from PacketPeer: **/
|
||||
virtual int get_available_packet_count() const;
|
||||
virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size); ///< buffer is GONE after next get_packet
|
||||
virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size);
|
||||
|
||||
virtual int get_max_packet_size() const;
|
||||
|
||||
WebRTCDataChannelJS();
|
||||
WebRTCDataChannelJS(int js_id);
|
||||
~WebRTCDataChannelJS();
|
||||
};
|
||||
|
||||
#endif // WEBRTC_DATA_CHANNEL_JS_H
|
||||
|
||||
#endif // JAVASCRIPT_ENABLED
|
@ -1,402 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* webrtc_multiplayer.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 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_multiplayer.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 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) {
|
||||
target_peer = p_peer_id;
|
||||
}
|
||||
|
||||
/* Returns the ID of the NetworkedMultiplayerPeer who sent the most recent packet: */
|
||||
int WebRTCMultiplayer::get_packet_peer() const {
|
||||
return next_packet_peer;
|
||||
}
|
||||
|
||||
bool WebRTCMultiplayer::is_server() const {
|
||||
return unique_id == TARGET_PEER_SERVER;
|
||||
}
|
||||
|
||||
void WebRTCMultiplayer::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();
|
||||
peer->connection->poll();
|
||||
// Check peer state
|
||||
switch (peer->connection->get_connection_state()) {
|
||||
case WebRTCPeerConnection::STATE_NEW:
|
||||
case WebRTCPeerConnection::STATE_CONNECTING:
|
||||
// Go to next peer, not ready yet.
|
||||
continue;
|
||||
case WebRTCPeerConnection::STATE_CONNECTED:
|
||||
// Good to go, go ahead and check channel state.
|
||||
break;
|
||||
default:
|
||||
// Peer is closed or in error state. Got to next peer.
|
||||
remove.push_back(E->key());
|
||||
continue;
|
||||
}
|
||||
// Check channels state
|
||||
int ready = 0;
|
||||
for (List<Ref<WebRTCDataChannel>>::Element *C = peer->channels.front(); C && C->get().is_valid(); C = C->next()) {
|
||||
Ref<WebRTCDataChannel> ch = C->get();
|
||||
switch (ch->get_ready_state()) {
|
||||
case WebRTCDataChannel::STATE_CONNECTING:
|
||||
continue;
|
||||
case WebRTCDataChannel::STATE_OPEN:
|
||||
ready++;
|
||||
continue;
|
||||
default:
|
||||
// Channel was closed or in error state, remove peer id.
|
||||
remove.push_back(E->key());
|
||||
}
|
||||
// We got a closed channel break out, the peer will be removed.
|
||||
break;
|
||||
}
|
||||
// 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());
|
||||
}
|
||||
}
|
||||
// Remove disconnected peers
|
||||
for (List<int>::Element *E = remove.front(); E; E = E->next()) {
|
||||
remove_peer(E->get());
|
||||
if (next_packet_peer == E->get()) {
|
||||
next_packet_peer = 0;
|
||||
}
|
||||
}
|
||||
// Signal newly connected peers
|
||||
for (List<int>::Element *E = add.front(); E; E = E->next()) {
|
||||
// Already connected to server: simply notify new peer.
|
||||
// NOTE: Mesh is always connected.
|
||||
if (connection_status == CONNECTION_CONNECTED) {
|
||||
emit_signal("peer_connected", E->get());
|
||||
}
|
||||
|
||||
// Server emulation mode suppresses peer_conencted until server connects.
|
||||
if (server_compat && E->get() == TARGET_PEER_SERVER) {
|
||||
// Server connected.
|
||||
connection_status = CONNECTION_CONNECTED;
|
||||
emit_signal("peer_connected", TARGET_PEER_SERVER);
|
||||
emit_signal("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());
|
||||
}
|
||||
}
|
||||
break; // Because we already notified of all newly added peers.
|
||||
}
|
||||
}
|
||||
// Fetch next packet
|
||||
if (next_packet_peer == 0) {
|
||||
_find_next_peer();
|
||||
}
|
||||
}
|
||||
|
||||
void WebRTCMultiplayer::_find_next_peer() {
|
||||
Map<int, Ref<ConnectedPeer>>::Element *E = peer_map.find(next_packet_peer);
|
||||
if (E) {
|
||||
E = E->next();
|
||||
}
|
||||
// After last.
|
||||
while (E) {
|
||||
if (!E->get()->connected) {
|
||||
E = E->next();
|
||||
continue;
|
||||
}
|
||||
for (List<Ref<WebRTCDataChannel>>::Element *F = E->get()->channels.front(); F; F = F->next()) {
|
||||
if (F->get()->get_available_packet_count()) {
|
||||
next_packet_peer = E->key();
|
||||
return;
|
||||
}
|
||||
}
|
||||
E = E->next();
|
||||
}
|
||||
E = peer_map.front();
|
||||
// Before last
|
||||
while (E) {
|
||||
if (!E->get()->connected) {
|
||||
E = E->next();
|
||||
continue;
|
||||
}
|
||||
for (List<Ref<WebRTCDataChannel>>::Element *F = E->get()->channels.front(); F; F = F->next()) {
|
||||
if (F->get()->get_available_packet_count()) {
|
||||
next_packet_peer = E->key();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (E->key() == (int)next_packet_peer) {
|
||||
break;
|
||||
}
|
||||
E = E->next();
|
||||
}
|
||||
// No packet found
|
||||
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 {
|
||||
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);
|
||||
unique_id = p_self_id;
|
||||
server_compat = p_server_compat;
|
||||
|
||||
// Mesh and server are always connected
|
||||
if (!server_compat || p_self_id == 1) {
|
||||
connection_status = CONNECTION_CONNECTED;
|
||||
} else {
|
||||
connection_status = CONNECTION_CONNECTING;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
int WebRTCMultiplayer::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) {
|
||||
Array channels;
|
||||
for (List<Ref<WebRTCDataChannel>>::Element *F = p_connected_peer->channels.front(); F; F = F->next()) {
|
||||
channels.push_back(F->get());
|
||||
}
|
||||
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) {
|
||||
return peer_map.has(p_peer_id);
|
||||
}
|
||||
|
||||
Dictionary WebRTCMultiplayer::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 out;
|
||||
for (Map<int, Ref<ConnectedPeer>>::Element *E = peer_map.front(); E; E = E->next()) {
|
||||
Dictionary d;
|
||||
_peer_to_dict(E->get(), d);
|
||||
out[E->key()] = d;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
Error WebRTCMultiplayer::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);
|
||||
// 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);
|
||||
|
||||
Ref<ConnectedPeer> peer = memnew(ConnectedPeer);
|
||||
peer->connection = p_peer;
|
||||
|
||||
// Initialize data channels
|
||||
Dictionary cfg;
|
||||
cfg["negotiated"] = true;
|
||||
cfg["ordered"] = true;
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
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) {
|
||||
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);
|
||||
if (server_compat && p_peer_id == TARGET_PEER_SERVER) {
|
||||
emit_signal("server_disconnected");
|
||||
connection_status = CONNECTION_DISCONNECTED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Error WebRTCMultiplayer::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);
|
||||
_find_next_peer();
|
||||
return err;
|
||||
}
|
||||
}
|
||||
// Channels for that peer were empty. Bug?
|
||||
_find_next_peer();
|
||||
ERR_FAIL_V(ERR_BUG);
|
||||
}
|
||||
|
||||
Error WebRTCMultiplayer::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;
|
||||
}
|
||||
|
||||
Map<int, Ref<ConnectedPeer>>::Element *E = nullptr;
|
||||
|
||||
if (target_peer > 0) {
|
||||
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);
|
||||
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()) {
|
||||
// Exclude packet. If target_peer == 0 then don't exclude any packets
|
||||
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);
|
||||
}
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
int WebRTCMultiplayer::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()) {
|
||||
if (!E->get()->connected) {
|
||||
continue;
|
||||
}
|
||||
for (List<Ref<WebRTCDataChannel>>::Element *F = E->get()->channels.front(); F; F = F->next()) {
|
||||
size += F->get()->get_available_packet_count();
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
int WebRTCMultiplayer::get_max_packet_size() const {
|
||||
return 1200;
|
||||
}
|
||||
|
||||
void WebRTCMultiplayer::close() {
|
||||
peer_map.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;
|
||||
transfer_mode = TRANSFER_MODE_RELIABLE;
|
||||
refuse_connections = false;
|
||||
connection_status = CONNECTION_DISCONNECTED;
|
||||
server_compat = false;
|
||||
}
|
||||
|
||||
WebRTCMultiplayer::~WebRTCMultiplayer() {
|
||||
close();
|
||||
}
|
@ -1,114 +0,0 @@
|
||||
#ifndef WEBRTC_MULTIPLAYER_H
|
||||
#define WEBRTC_MULTIPLAYER_H
|
||||
/*************************************************************************/
|
||||
/* webrtc_multiplayer.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 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 "core/io/networked_multiplayer_peer.h"
|
||||
#include "webrtc_peer_connection.h"
|
||||
|
||||
class WebRTCMultiplayer : public NetworkedMultiplayerPeer {
|
||||
GDCLASS(WebRTCMultiplayer, NetworkedMultiplayerPeer);
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
private:
|
||||
enum {
|
||||
CH_RELIABLE = 0,
|
||||
CH_ORDERED = 1,
|
||||
CH_UNRELIABLE = 2,
|
||||
CH_RESERVED_MAX = 3
|
||||
};
|
||||
|
||||
class ConnectedPeer : public Reference {
|
||||
public:
|
||||
Ref<WebRTCPeerConnection> connection;
|
||||
List<Ref<WebRTCDataChannel>> channels;
|
||||
bool connected;
|
||||
|
||||
ConnectedPeer() {
|
||||
connected = false;
|
||||
for (int i = 0; i < CH_RESERVED_MAX; i++) {
|
||||
channels.push_front(Ref<WebRTCDataChannel>());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
Map<int, Ref<ConnectedPeer>> peer_map;
|
||||
|
||||
void _peer_to_dict(Ref<ConnectedPeer> p_connected_peer, Dictionary &r_dict);
|
||||
void _find_next_peer();
|
||||
|
||||
public:
|
||||
WebRTCMultiplayer();
|
||||
~WebRTCMultiplayer();
|
||||
|
||||
Error initialize(int p_self_id, bool p_server_compat = false);
|
||||
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);
|
||||
Dictionary get_peer(int p_peer_id);
|
||||
Dictionary get_peers();
|
||||
void close();
|
||||
|
||||
// PacketPeer
|
||||
Error get_packet(const uint8_t **r_buffer, int &r_buffer_size); ///< buffer is GONE after next get_packet
|
||||
Error put_packet(const uint8_t *p_buffer, int p_buffer_size);
|
||||
int get_available_packet_count() const;
|
||||
int get_max_packet_size() const;
|
||||
|
||||
// NetworkedMultiplayerPeer
|
||||
void set_transfer_mode(TransferMode p_mode);
|
||||
TransferMode get_transfer_mode() const;
|
||||
void set_target_peer(int p_peer_id);
|
||||
|
||||
int get_unique_id() const;
|
||||
int get_packet_peer() const;
|
||||
|
||||
bool is_server() const;
|
||||
|
||||
void poll();
|
||||
|
||||
void set_refuse_new_connections(bool p_enable);
|
||||
bool is_refusing_new_connections() const;
|
||||
|
||||
ConnectionStatus get_connection_status() const;
|
||||
};
|
||||
|
||||
#endif
|
@ -1,106 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* webrtc_peer_connection.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 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.h"
|
||||
|
||||
WebRTCPeerConnection *(*WebRTCPeerConnection::_create)() = nullptr;
|
||||
|
||||
Ref<WebRTCPeerConnection> WebRTCPeerConnection::create_ref() {
|
||||
return create();
|
||||
}
|
||||
|
||||
WebRTCPeerConnection *WebRTCPeerConnection::create() {
|
||||
if (!_create) {
|
||||
return nullptr;
|
||||
}
|
||||
return _create();
|
||||
}
|
||||
|
||||
WebRTCPeerConnection *WebRTCPeerConnection::_create_func() {
|
||||
return memnew(WebRTCPeerConnection);
|
||||
}
|
||||
|
||||
WebRTCPeerConnection::ConnectionState WebRTCPeerConnection::get_connection_state() const {
|
||||
return WebRTCPeerConnection::STATE_FAILED;
|
||||
}
|
||||
Error WebRTCPeerConnection::initialize(Dictionary p_config) {
|
||||
ERR_FAIL_V(ERR_UNAVAILABLE);
|
||||
}
|
||||
Ref<WebRTCDataChannel> WebRTCPeerConnection::create_data_channel(String p_label, Dictionary p_options) {
|
||||
ERR_FAIL_V(Ref<WebRTCDataChannel>());
|
||||
}
|
||||
Error WebRTCPeerConnection::create_offer() {
|
||||
ERR_FAIL_V(ERR_UNAVAILABLE);
|
||||
}
|
||||
Error WebRTCPeerConnection::set_remote_description(String type, String sdp) {
|
||||
ERR_FAIL_V(ERR_UNAVAILABLE);
|
||||
}
|
||||
Error WebRTCPeerConnection::set_local_description(String type, String sdp) {
|
||||
ERR_FAIL_V(ERR_UNAVAILABLE);
|
||||
}
|
||||
Error WebRTCPeerConnection::add_ice_candidate(String sdpMidName, int sdpMlineIndexName, String sdpName) {
|
||||
ERR_FAIL_V(ERR_UNAVAILABLE);
|
||||
}
|
||||
Error WebRTCPeerConnection::poll() {
|
||||
ERR_FAIL_V(ERR_UNAVAILABLE);
|
||||
}
|
||||
void WebRTCPeerConnection::close() {
|
||||
ERR_FAIL();
|
||||
}
|
||||
|
||||
void WebRTCPeerConnection::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("initialize", "configuration"), &WebRTCPeerConnection::initialize, DEFVAL(Dictionary()));
|
||||
ClassDB::bind_method(D_METHOD("create_data_channel", "label", "options"), &WebRTCPeerConnection::create_data_channel, DEFVAL(Dictionary()));
|
||||
ClassDB::bind_method(D_METHOD("create_offer"), &WebRTCPeerConnection::create_offer);
|
||||
ClassDB::bind_method(D_METHOD("set_local_description", "type", "sdp"), &WebRTCPeerConnection::set_local_description);
|
||||
ClassDB::bind_method(D_METHOD("set_remote_description", "type", "sdp"), &WebRTCPeerConnection::set_remote_description);
|
||||
ClassDB::bind_method(D_METHOD("add_ice_candidate", "media", "index", "name"), &WebRTCPeerConnection::add_ice_candidate);
|
||||
ClassDB::bind_method(D_METHOD("poll"), &WebRTCPeerConnection::poll);
|
||||
ClassDB::bind_method(D_METHOD("close"), &WebRTCPeerConnection::close);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("get_connection_state"), &WebRTCPeerConnection::get_connection_state);
|
||||
|
||||
ADD_SIGNAL(MethodInfo("session_description_created", PropertyInfo(Variant::STRING, "type"), PropertyInfo(Variant::STRING, "sdp")));
|
||||
ADD_SIGNAL(MethodInfo("ice_candidate_created", PropertyInfo(Variant::STRING, "media"), PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::STRING, "name")));
|
||||
ADD_SIGNAL(MethodInfo("data_channel_received", PropertyInfo(Variant::OBJECT, "channel")));
|
||||
|
||||
BIND_ENUM_CONSTANT(STATE_NEW);
|
||||
BIND_ENUM_CONSTANT(STATE_CONNECTING);
|
||||
BIND_ENUM_CONSTANT(STATE_CONNECTED);
|
||||
BIND_ENUM_CONSTANT(STATE_DISCONNECTED);
|
||||
BIND_ENUM_CONSTANT(STATE_FAILED);
|
||||
BIND_ENUM_CONSTANT(STATE_CLOSED);
|
||||
}
|
||||
|
||||
WebRTCPeerConnection::WebRTCPeerConnection() {
|
||||
}
|
||||
|
||||
WebRTCPeerConnection::~WebRTCPeerConnection() {
|
||||
}
|
@ -1,77 +0,0 @@
|
||||
#ifndef WEBRTC_PEER_CONNECTION_H
|
||||
#define WEBRTC_PEER_CONNECTION_H
|
||||
/*************************************************************************/
|
||||
/* webrtc_peer_connection.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 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 "core/io/packet_peer.h"
|
||||
#include "modules/webrtc/webrtc_data_channel.h"
|
||||
|
||||
class WebRTCPeerConnection : public Reference {
|
||||
GDCLASS(WebRTCPeerConnection, Reference);
|
||||
|
||||
public:
|
||||
enum ConnectionState {
|
||||
STATE_NEW,
|
||||
STATE_CONNECTING,
|
||||
STATE_CONNECTED,
|
||||
STATE_DISCONNECTED,
|
||||
STATE_FAILED,
|
||||
STATE_CLOSED
|
||||
};
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
static WebRTCPeerConnection *(*_create)();
|
||||
|
||||
static WebRTCPeerConnection *_create_func();
|
||||
|
||||
public:
|
||||
static void make_default() { WebRTCPeerConnection::_create = WebRTCPeerConnection::_create_func; }
|
||||
|
||||
virtual ConnectionState get_connection_state() const;
|
||||
|
||||
virtual Error initialize(Dictionary p_config = Dictionary());
|
||||
virtual Ref<WebRTCDataChannel> create_data_channel(String p_label, Dictionary p_options = Dictionary());
|
||||
virtual Error create_offer();
|
||||
virtual Error set_remote_description(String type, String sdp);
|
||||
virtual Error set_local_description(String type, String sdp);
|
||||
virtual Error add_ice_candidate(String sdpMidName, int sdpMlineIndexName, String sdpName);
|
||||
virtual Error poll();
|
||||
virtual void close();
|
||||
|
||||
static Ref<WebRTCPeerConnection> create_ref();
|
||||
static WebRTCPeerConnection *create();
|
||||
|
||||
WebRTCPeerConnection();
|
||||
~WebRTCPeerConnection();
|
||||
};
|
||||
|
||||
VARIANT_ENUM_CAST(WebRTCPeerConnection::ConnectionState);
|
||||
#endif // WEBRTC_PEER_CONNECTION_H
|
@ -1,140 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* webrtc_peer_connection_js.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifdef JAVASCRIPT_ENABLED
|
||||
|
||||
#include "webrtc_peer_connection_js.h"
|
||||
|
||||
#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));
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
void WebRTCPeerConnectionJS::_on_connection_state_changed(void *p_obj, int p_state) {
|
||||
WebRTCPeerConnectionJS *peer = static_cast<WebRTCPeerConnectionJS *>(p_obj);
|
||||
peer->_conn_state = (ConnectionState)p_state;
|
||||
}
|
||||
|
||||
void WebRTCPeerConnectionJS::_on_error(void *p_obj) {
|
||||
ERR_PRINT("RTCPeerConnection error!");
|
||||
}
|
||||
|
||||
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)));
|
||||
}
|
||||
|
||||
void WebRTCPeerConnectionJS::close() {
|
||||
godot_js_rtc_pc_close(_js_id);
|
||||
_conn_state = STATE_CLOSED;
|
||||
}
|
||||
|
||||
Error WebRTCPeerConnectionJS::create_offer() {
|
||||
ERR_FAIL_COND_V(_conn_state != STATE_NEW, FAILED);
|
||||
|
||||
_conn_state = STATE_CONNECTING;
|
||||
godot_js_rtc_pc_offer_create(_js_id, this, &_on_session_created, &_on_error);
|
||||
return OK;
|
||||
}
|
||||
|
||||
Error WebRTCPeerConnectionJS::set_local_description(String type, String sdp) {
|
||||
godot_js_rtc_pc_local_description_set(_js_id, type.utf8().get_data(), sdp.utf8().get_data(), this, &_on_error);
|
||||
return OK;
|
||||
}
|
||||
|
||||
Error WebRTCPeerConnectionJS::set_remote_description(String type, String sdp) {
|
||||
if (type == "offer") {
|
||||
ERR_FAIL_COND_V(_conn_state != STATE_NEW, FAILED);
|
||||
_conn_state = STATE_CONNECTING;
|
||||
}
|
||||
godot_js_rtc_pc_remote_description_set(_js_id, type.utf8().get_data(), sdp.utf8().get_data(), this, &_on_session_created, &_on_error);
|
||||
return OK;
|
||||
}
|
||||
|
||||
Error WebRTCPeerConnectionJS::add_ice_candidate(String sdpMidName, int sdpMlineIndexName, String sdpName) {
|
||||
godot_js_rtc_pc_ice_candidate_add(_js_id, sdpMidName.utf8().get_data(), sdpMlineIndexName, sdpName.utf8().get_data());
|
||||
return OK;
|
||||
}
|
||||
|
||||
Error WebRTCPeerConnectionJS::initialize(Dictionary p_config) {
|
||||
if (_js_id) {
|
||||
godot_js_rtc_pc_destroy(_js_id);
|
||||
_js_id = 0;
|
||||
}
|
||||
_conn_state = STATE_NEW;
|
||||
|
||||
String config = JSON::print(p_config);
|
||||
_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;
|
||||
}
|
||||
|
||||
Ref<WebRTCDataChannel> WebRTCPeerConnectionJS::create_data_channel(String p_channel, Dictionary p_channel_config) {
|
||||
ERR_FAIL_COND_V(_conn_state != STATE_NEW, NULL);
|
||||
|
||||
String config = JSON::print(p_channel_config);
|
||||
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, NULL);
|
||||
return memnew(WebRTCDataChannelJS(id));
|
||||
}
|
||||
|
||||
Error WebRTCPeerConnectionJS::poll() {
|
||||
return OK;
|
||||
}
|
||||
|
||||
WebRTCPeerConnection::ConnectionState WebRTCPeerConnectionJS::get_connection_state() const {
|
||||
return _conn_state;
|
||||
}
|
||||
|
||||
WebRTCPeerConnectionJS::WebRTCPeerConnectionJS() {
|
||||
_conn_state = STATE_NEW;
|
||||
_js_id = 0;
|
||||
|
||||
Dictionary config;
|
||||
initialize(config);
|
||||
}
|
||||
|
||||
WebRTCPeerConnectionJS::~WebRTCPeerConnectionJS() {
|
||||
close();
|
||||
if (_js_id) {
|
||||
godot_js_rtc_pc_destroy(_js_id);
|
||||
_js_id = 0;
|
||||
}
|
||||
};
|
||||
#endif
|
@ -1,85 +0,0 @@
|
||||
#ifndef WEBRTC_PEER_CONNECTION_JS_H
|
||||
#define WEBRTC_PEER_CONNECTION_JS_H
|
||||
/*************************************************************************/
|
||||
/* webrtc_peer_connection_js.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifdef JAVASCRIPT_ENABLED
|
||||
|
||||
#include "webrtc_peer_connection.h"
|
||||
|
||||
extern "C" {
|
||||
typedef void (*RTCOnIceConnectionStateChange)(void *p_obj, int p_state);
|
||||
typedef void (*RTCOnIceCandidate)(void *p_obj, const char *p_mid, int p_mline_idx, const char *p_candidate);
|
||||
typedef void (*RTCOnDataChannel)(void *p_obj, int p_id);
|
||||
typedef void (*RTCOnSession)(void *p_obj, const char *p_type, const char *p_sdp);
|
||||
typedef void (*RTCOnError)(void *p_obj);
|
||||
extern int godot_js_rtc_pc_create(const char *p_config, void *p_obj, RTCOnIceConnectionStateChange p_on_state_change, RTCOnIceCandidate p_on_candidate, RTCOnDataChannel p_on_datachannel);
|
||||
extern void godot_js_rtc_pc_close(int p_id);
|
||||
extern void godot_js_rtc_pc_destroy(int p_id);
|
||||
extern void godot_js_rtc_pc_offer_create(int p_id, void *p_obj, RTCOnSession p_on_session, RTCOnError p_on_error);
|
||||
extern void godot_js_rtc_pc_local_description_set(int p_id, const char *p_type, const char *p_sdp, void *p_obj, RTCOnError p_on_error);
|
||||
extern void godot_js_rtc_pc_remote_description_set(int p_id, const char *p_type, const char *p_sdp, void *p_obj, RTCOnSession p_on_session, RTCOnError p_on_error);
|
||||
extern void godot_js_rtc_pc_ice_candidate_add(int p_id, const char *p_mid_name, int p_mline_idx, const char *p_sdo);
|
||||
extern int godot_js_rtc_pc_datachannel_create(int p_id, const char *p_label, const char *p_config);
|
||||
}
|
||||
|
||||
class WebRTCPeerConnectionJS : public WebRTCPeerConnection {
|
||||
private:
|
||||
int _js_id;
|
||||
ConnectionState _conn_state;
|
||||
|
||||
static void _on_connection_state_changed(void *p_obj, int p_state);
|
||||
static void _on_ice_candidate(void *p_obj, const char *p_mid_name, int p_mline_idx, const char *p_candidate);
|
||||
static void _on_data_channel(void *p_obj, int p_channel);
|
||||
static void _on_session_created(void *p_obj, const char *p_type, const char *p_session);
|
||||
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());
|
||||
virtual Ref<WebRTCDataChannel> create_data_channel(String p_channel_name, Dictionary p_channel_config = Dictionary());
|
||||
virtual Error create_offer();
|
||||
virtual Error set_remote_description(String type, String sdp);
|
||||
virtual Error set_local_description(String type, String sdp);
|
||||
virtual Error add_ice_candidate(String sdpMidName, int sdpMlineIndexName, String sdpName);
|
||||
virtual Error poll();
|
||||
virtual void close();
|
||||
|
||||
WebRTCPeerConnectionJS();
|
||||
~WebRTCPeerConnectionJS();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif // WEBRTC_PEER_CONNECTION_JS_H
|
Loading…
Reference in New Issue
Block a user