Compare commits

..

107 Commits

Author SHA1 Message Date
Fabio Alessandrelli
6e2262b6c3 Merge pull request #113 from Faless/spike/4.1
Support building for Godot 4.1 (new default).
2023-07-01 19:43:42 +02:00
Fabio Alessandrelli
cb2be8723a Support building for Godot 4.1 (new default). 2023-06-30 16:52:36 +02:00
Fabio Alessandrelli
d278661d76 Merge pull request #112 from Faless/spike/buildroot
Build Linux binaries using the Godot toolchian.
2023-06-30 16:46:58 +02:00
Fabio Alessandrelli
552d696e0a Build Linux binaries using the Godot toolchian.
So we link to very old glibc and support ancient distros.
2023-06-30 10:06:06 +02:00
Fabio Alessandrelli
6f4d8f5238 Merge pull request #111 from Faless/bump/openssl_3.0.9
[OpenSSL] Update to version 3.0.9
2023-06-30 09:00:55 +02:00
Fabio Alessandrelli
8040565b0e [OpenSSL] Update to version 3.0.9 2023-06-30 08:25:32 +02:00
Fabio Alessandrelli
38c83f667d Merge pull request #109 from Faless/fix/linux_static_gcc_cpp
Statically link libgcc and libstdc++ on linux
2023-06-30 07:56:59 +02:00
Fabio Alessandrelli
1de32aa9ea Statically link libgcc and libstdc++ on Linux.
More compatibility at the cost of bigger binaries.
2023-06-29 14:57:55 +02:00
Fabio Alessandrelli
ed3771ced0 Merge pull request #108 from Faless/fix/normalize_ios_min_version
Better normalize the GDNative build environment.
2023-06-29 14:51:47 +02:00
Fabio Alessandrelli
ac3bdb3613 Better normalize the GDNative build environment.
The "ios_min_version" is missing from godot-cpp-3.x, and the macos CC
variable is not explicitely set to "clang".

Since the values are passed to cmake, they used to cause unnecessary
rebuilds of libdatchannel when compiling both version 3 and 4.
2023-06-29 14:15:48 +02:00
Fabio Alessandrelli
931a7551f5 Merge pull request #107 from Faless/build/cmake_helper
[SCons] Simplify building cmake libraries.
2023-06-29 14:04:53 +02:00
Fabio Alessandrelli
0771084b54 [SCons] Simplify building cmake libraries.
Add an extra "CMakeBuild" method to reduce configuration needed by each
library.
2023-06-29 13:37:09 +02:00
Fabio Alessandrelli
ae0dd0626a Merge pull request #106 from Faless/build/openssl_external
[OpenSSL] Allow using external (static) libraries.
2023-06-23 17:12:25 +02:00
Fabio Alessandrelli
0be6b671e5 [OpenSSL] Allow using external (static) libraries.
In case one wants to handle openssl builds manually (or use static
libraries provided by third parties like those in Linux distros).

Note that they still must be *static* libraries, adding support for
linking against *shared* libraries needs more work (and testing).
2023-06-23 16:08:04 +02:00
Fabio Alessandrelli
d96b43b7ee Merge pull request #104 from Faless/bump/libdatachannel_0.18.5
[libdatachannel] Update to v0.18.5
2023-06-21 06:08:27 +02:00
Fabio Alessandrelli
ec8cd5c0e4 [libdatachannel] Update to v0.18.5 2023-06-21 04:36:40 +02:00
Fabio Alessandrelli
b03099f7b4 Merge pull request #105 from Faless/build/tool_options
Linux ARM32/ARM64, better toolchains support.
2023-06-21 04:34:38 +02:00
Fabio Alessandrelli
85efdfd6ce Linux ARM32/ARM64, better toolchains support.
Needs updated godot-cpp to build library with custom toolchains.

Make the OpenSSL and CMake tools more customizable letting the user
override the default platform flags via build options.

Improve dependency handling.
2023-06-21 03:54:39 +02:00
Fabio Alessandrelli
32ae1d1195 Merge pull request #103 from Faless/build/less_rebuilds
[SCons] Fix regression causing unnecessary rebuilds.
2023-06-20 18:53:08 +02:00
Fabio Alessandrelli
54c8586235 [SCons] Fix regression causing unnecessary rebuilds.
The num_jobs (-j flag) was being tracked as part of the cmake and
openssl build actions, thus causing a rebuild when compiling with
different concurrently.

This commit strip the -j flag from the signature of the actions so
scons won't rebuild openssl/libdatachannel when changing the parallelism
option.
2023-06-20 17:45:23 +02:00
Fabio Alessandrelli
f19011f2fb Merge pull request #102 from Faless/build/builders
[SCons] Refactor CMake and OpenSSL tools to use actions.
2023-06-20 16:24:45 +02:00
Fabio Alessandrelli
86c27ec7ef [SCons] Refactor CMake and OpenSSL tools to use actions.
Improve build reliability, allow for more customization.
2023-06-20 13:22:07 +02:00
Fabio Alessandrelli
f2ee596bd9 Merge pull request #100 from Faless/build/openssl_universal
[SCons] Refactor build system.
2023-06-17 20:19:10 +02:00
Fabio Alessandrelli
61299ca4b7 [SCons] Refactor build system.
Update ssl tool (now renamed openssl).

Move universal library "lipo" action to openssl tool, and add universal
builds support to cmake tool.

Add support for MSVC builds (requires nasm and perl in PATH, tested with
Strawberry Perl, VS 2019 and VS 2022).

Add support for building "macos" via OSXCross.
2023-06-17 19:46:54 +02:00
Fabio Alessandrelli
df643250f5 Merge pull request #98 from Faless/build/cmake_platform
[SCons] Move platform configuration to cmake tool.
2023-05-25 07:29:57 +02:00
Fabio Alessandrelli
45549e020f [SCons] Move platform configuration to cmake tool. 2023-05-25 06:07:03 +02:00
Fabio Alessandrelli
ee40730c20 Merge pull request #97 from Faless/fix/ci_scripts
[CI] Update static checks, copyright headers.
2023-05-25 05:31:07 +02:00
Fabio Alessandrelli
8f7cb77f34 [CI] Update static checks, copyright headers. 2023-05-25 04:34:31 +02:00
Fabio Alessandrelli
eb65d88cd4 Merge pull request #96 from Faless/fix/black
[CI] Fix python black formatting.
2023-05-25 03:15:43 +02:00
Fabio Alessandrelli
e8de07dbb1 [CI] Fix python black formatting. 2023-05-25 02:42:26 +02:00
Fabio Alessandrelli
e34000653b Merge pull request #95 from Faless/bump/openssl_3.0.8_libdatachannel_0.18.4
[3rd Party] Bump to openssl 3.0.8 and libdatachannel 0.18.4
2023-05-24 20:16:15 +02:00
Fabio Alessandrelli
826a736176 [libdatachannel] Bump to version 0.18.4 2023-05-24 19:12:25 +02:00
Fabio Alessandrelli
b7098e7496 [OpenSSL] Bump to version 3.0.8 2023-05-24 16:40:47 +02:00
Fabio Alessandrelli
6de604ffee Merge pull request #94 from Faless/fix/macos_releases
[macOS] Add support for universal builds.
2023-05-24 16:28:34 +02:00
Fabio Alessandrelli
f0af5f9982 [macOS] Add support for universal builds.
Since the OpenSSL build system does not support macOS universal
binaries, we first need to build the two libraries separately, then we
join them together using lipo.
2023-05-24 00:53:28 +02:00
Fabio Alessandrelli
fbe4e06b9f Merge pull request #93 from Faless/bump/4.0-stable
Bump godot-cpp to 4.0-stable.
2023-05-23 12:53:57 +02:00
Fabio Alessandrelli
9a9fc0953b Bump godot-cpp to 4.0-stable. 2023-05-23 10:43:45 +02:00
Fabio Alessandrelli
c6b6f7e18c Merge pull request #87 from Faless/bump/rc1
Update to Godot 4.0 rc1.
2023-02-09 19:20:56 +01:00
Fabio Alessandrelli
00f952bcf1 Update to Godot 4.0 rc1. 2023-02-09 15:31:39 +01:00
Fabio Alessandrelli
d7032f7b85 Merge pull request #85 from Faless/fix/godot3_mingw
Workaround incorrect CC for 3.x mingw builds.
2023-02-07 23:14:09 +01:00
Fabio Alessandrelli
c9a1efc7a0 Workaround incorrect CC for 3.x mingw builds. 2023-02-06 19:08:45 +01:00
Fabio Alessandrelli
5bc4b79435 Merge pull request #83 from Faless/bump/beta14
Update to Godot 4.0 beta14.
2023-01-21 16:07:16 +01:00
Fabio Alessandrelli
b7b76dddab Update to Godot 4.0 beta14. 2023-01-21 10:00:01 +01:00
Fabio Alessandrelli
0b1c55ed83 Merge pull request #82 from Faless/bump/beta13
Update to Godot 4.0 beta13.
2023-01-20 12:27:43 +01:00
Fabio Alessandrelli
093ac7d489 Update to Godot 4.0 beta13. 2023-01-18 08:57:07 +01:00
Fabio Alessandrelli
84e9d6dd37 Merge pull request #81 from Faless/bump/beta12
Update to Godot 4.0 beta12.
2023-01-14 04:15:34 +01:00
Fabio Alessandrelli
a49a2b03e1 Revert "[Extension] Fix library resource waiting for Godot auto prefix."
This reverts commit 0c10a7f3e3.
2023-01-13 18:09:17 +01:00
Fabio Alessandrelli
656d3a9964 Update to Godot 4.0 beta12.
Also update thirdparty README with correct libdatachannel version.
2023-01-13 18:06:10 +01:00
Fabio Alessandrelli
2bc2a5d162 Merge pull request #80 from Faless/bump/beta11
Update to Godot 4.0-beta11, libdatachannel v0.18.1
2023-01-12 17:08:36 +01:00
Fabio Alessandrelli
7176344056 Update to Godot 4.0-beta11, libdatachannel v0.18.1
Also update godot-cpp-3.x for better cache support.
2023-01-12 15:59:48 +01:00
Fabio Alessandrelli
7d260b1b32 Merge pull request #79 from Faless/fix/template_debug
[Extension] Fix library resource waiting for Godot auto prefix.
2023-01-12 15:57:10 +01:00
Fabio Alessandrelli
0c10a7f3e3 [Extension] Fix library resource waiting for Godot auto prefix. 2023-01-12 15:12:09 +01:00
Fabio Alessandrelli
40962dbe19 Merge pull request #78 from Faless/build/split_deps
[SCons] Refactor build tools.
2023-01-09 21:48:09 +01:00
Fabio Alessandrelli
bdd9d50745 [SCons] Refactor build tools.
Split dependency builders into separate tools, optimize OpenSSL builds.
2022-12-30 14:34:15 +01:00
Fabio Alessandrelli
5348407de9 Merge pull request #77 from Faless/bump/beta10
Update to Godot 4.0-beta10.
2022-12-29 17:30:51 +01:00
Fabio Alessandrelli
5002991511 Update to Godot 4.0-beta10. 2022-12-29 15:38:48 +01:00
Fabio Alessandrelli
0fc992e0d5 Merge pull request #76 from Faless/bump/beta9
Update to Godot 4.0 beta9
2022-12-19 22:11:33 +01:00
Fabio Alessandrelli
fbadff454c Update to Godot 4.0 beta9 2022-12-19 20:42:56 +01:00
Fabio Alessandrelli
61a6d25c47 Merge pull request #75 from Faless/bump/beta8
Bump godot-cpp to beta8, libdatachannel to v0.18.0
2022-12-10 18:26:25 +01:00
Fabio Alessandrelli
dfaad6f5ba Bump godot-cpp to beta8, libdatachannel to v0.18.0
libdatachannel and libjuice are now released under MPL 2.0.

Dependencies has been refactored under a `thirdparty` folder similar to
what we have in Godot, with a dedicated `thirdparty/README.md`
containing details information on dependencies upstreams, versions, and
licenses.
2022-12-10 17:13:59 +01:00
Fabio Alessandrelli
35bdd5efa7 Merge pull request #73 from Faless/bump/beta6
Update to Godot 4.0 beta6, and bump dependencies.
2022-11-28 20:19:47 +01:00
Fabio Alessandrelli
90aaa0b82e Update to libdatachannel v0.17.12+git. 2022-11-28 17:54:19 +01:00
Fabio Alessandrelli
16f311844b Update to OpenSSL 3.0.7. 2022-11-28 17:54:19 +01:00
Fabio Alessandrelli
dfb34df36e Update to Godot 4.0-beta6 2022-11-28 17:54:19 +01:00
Fabio Alessandrelli
9715e73ae4 Merge pull request #74 from Faless/build/cache_and_paths
[SCons] Fix caching and path detection.
2022-11-28 17:53:10 +01:00
Fabio Alessandrelli
2e9a25bb39 [SCons] Fix caching and path detection.
Add version file depenencies to SSL and RTC targets.

Disable OpenSSL caching since it causes issues as it doesn't properly
cache generated header files.

Add hack to prepend PATH and few other vars (should probably be added
to upstream godot-cpp), and clone scons envs when building ssl/rtc (so
that PATHs are properly setup).
2022-11-28 03:10:20 +01:00
Fabio Alessandrelli
6067addd96 Merge pull request #72 from JonathanPicques/patch-1
Rename osx to macos in webrtc.gdextension
2022-11-26 15:50:07 +01:00
Jonathan Picques
a3fbd33464 Rename osx to macos in webrtc.gdextension
The plugin wouldn't work with Godot beta 5 because it expects a macos key instead of an osx
2022-11-26 13:56:06 +01:00
Fabio Alessandrelli
d697901f81 Merge pull request #70 from Faless/bump/beta5
Update to Godot 4.0-beta5
2022-11-19 11:08:34 +01:00
Fabio Alessandrelli
3eb7d0aa3b Update to Godot 4.0-beta5 2022-11-19 01:43:24 +01:00
Fabio Alessandrelli
ecec40f59e Merge pull request #68 from Faless/bump/beta4
Update to Godot 4.0-beta4.
2022-11-15 00:41:01 +01:00
Fabio Alessandrelli
37a289addf Update to Godot 4.0-beta4. 2022-11-14 22:48:46 +01:00
Fabio Alessandrelli
1436024f59 Merge pull request #65 from Faless/bump/beta3
[Upstream] Update to Godot Beta 3
2022-10-17 22:42:33 +02:00
Fabio Alessandrelli
690b31e7dd [Upstream] Update to Godot beta 3.
Update build targets.
Move release script out of CI yaml.
Disable debug CI builds for Godot 3.x since they are mostly used for
debugging the extension itself.
2022-10-17 20:59:33 +02:00
Fabio Alessandrelli
9b0a5d8b46 [CI] Update actions, add cache for faster builds. 2022-10-16 16:15:42 +02:00
Fabio Alessandrelli
1769730ef0 Merge pull request #63 from Faless/bump/beta2
[CPP] Bump godot-cpp to beta2 headers.
2022-10-10 11:49:36 +02:00
Fabio Alessandrelli
04898f2714 [CPP] Bump godot-cpp to beta2 headers. 2022-10-09 19:42:31 +02:00
Fabio Alessandrelli
d7fc6cde3b Merge pull request #61 from Faless/bump/beta1
[Extension] Update to Godot 4.0 beta 1
2022-09-16 14:39:41 +02:00
Fabio Alessandrelli
1009e8bb1c Add methods to get gathering and signaling state. 2022-09-16 13:07:06 +02:00
Fabio Alessandrelli
5fd359f674 Bump godot-cpp to Godot 4.0 beta1. 2022-09-16 13:07:06 +02:00
Fabio Alessandrelli
822e0532c2 Merge pull request #60 from Faless/bump/alpha16
Update to Godot alpha16
2022-09-11 18:26:08 +02:00
Fabio Alessandrelli
d8cbd14a28 Disable android 32 bits builds. 2022-09-11 15:34:08 +02:00
Fabio Alessandrelli
6e52fce986 Update sources to alpha16 2022-09-11 15:34:08 +02:00
Fabio Alessandrelli
a93af67d75 [godot-cpp] Bump to alpha16. 2022-09-11 14:48:51 +02:00
Fabio Alessandrelli
22ee6435a1 Update to libdatachannel 0.17.10+git. 2022-09-11 14:48:51 +02:00
Fabio Alessandrelli
b5d8a72ef8 Update to OpenSSL 3.0.5 2022-09-11 14:48:51 +02:00
Fabio Alessandrelli
2ad1bf1716 Merge pull request #57 from Faless/bump/4.0_alpha11
Bump godot-cpp to alpha11.
2022-07-06 13:24:04 +02:00
Fabio Alessandrelli
e683c79938 Bump godot-cpp to alpha11. 2022-07-06 11:45:03 +02:00
Fabio Alessandrelli
426ca6cc8e Merge pull request #56 from Faless/fix/write_mode
Fix default data channel write mode to binary.
2022-06-19 13:48:20 +02:00
Fabio Alessandrelli
9b53ef3325 Fix default data channel write mode to binary.
It's the engine expected default, and the least surprising for the users
since it allows any data to be sent, while text mode requires valid UTF.
2022-06-19 12:18:49 +02:00
Fabio Alessandrelli
e41d2903ad Merge pull request #54 from Faless/fix/win32_mingw
[Windows] Fix windows build with mingw.
2022-06-18 16:46:06 +02:00
Fabio Alessandrelli
f315912d85 [Windows] Fix windows build with mingw.
Forces ".dll" extension for library when building with mingw.

Override GDN_EXPORT which is incorrectly defined in the upstream
gdnative headers (3.x) and godot-cpp include (4.0) when building for
windows with mingw.
2022-06-18 14:35:51 +02:00
Fabio Alessandrelli
62ab2e59f8 Merge pull request #53 from Faless/fix/build_deps_target
[SCons] Apply "target" to dependencies.
2022-06-18 03:00:48 +02:00
Fabio Alessandrelli
a2fc27f646 [SCons] Apply "target" to dependencies.
Dependencies used to be built with the default option (release for
OpenSSL, debug for libdachannel).
They now follow the desired target (producing smaller binaries in
release, and bigger in debug).
2022-06-18 02:00:18 +02:00
Fabio Alessandrelli
b2654cc2bd Merge pull request #51 from Faless/libdatachannel_pr
Switch to libdatachannel as RTC library. Add GDExtension support.
2022-06-16 11:32:10 +02:00
Fabio Alessandrelli
e19b370126 Use libdatachannel library, add Godot 4 support. 2022-06-15 21:38:12 +02:00
Fabio Alessandrelli
8c18112f5d Merge pull request #43 from dsnopek/buffered-amount
Add get_buffered_amount() to WebRTCDataChannel (GDNative)
2021-09-22 23:06:19 +02:00
Fabio Alessandrelli
c37cc530e7 Merge pull request #46 from Faless/issue_template
Add issue templates for reporting bugs.
2021-07-26 15:39:53 +02:00
Fabio Alessandrelli
13ab33af36 Add issue templates for reporting bugs. 2021-07-26 13:19:29 +02:00
David Snopek
3bdf6cdc13 Add get_buffered_amount() to WebRTCDataChannel 2021-07-21 10:48:09 -05:00
Fabio Alessandrelli
072ba5c1d0 Merge pull request #40 from Faless/osx/arm64
Add OSX arm64 build.
2021-07-11 10:51:37 +02:00
Fabio Alessandrelli
7cb6d6c846 Add OSX arm64 build.
Needs a more recent revision of godot-cpp, but can still use
godot-headers from 3.2 . See CI script update for details.
2021-07-11 10:01:55 +02:00
Fabio Alessandrelli
c0b31562f5 Merge pull request #39 from Faless/style/clang_black
Add static checks
2021-07-09 19:43:04 +02:00
Fabio Alessandrelli
69f92fa26c Run clang-format on src/* 2021-07-09 18:55:32 +02:00
Fabio Alessandrelli
d06e536d12 Add copyright headers 2021-07-09 18:55:32 +02:00
Fabio Alessandrelli
68a892d9f3 run black -l 120 on SConstruct. 2021-07-09 18:55:32 +02:00
Fabio Alessandrelli
72b337e32c static checks. 2021-07-09 18:55:32 +02:00
38 changed files with 2500 additions and 1013 deletions

199
.clang-format Normal file
View File

@@ -0,0 +1,199 @@
# Commented out parameters are those with the same value as base LLVM style.
# We can uncomment them if we want to change their value, or enforce the
# chosen value in case the base style changes (last sync: Clang 14.0).
---
### General config, applies to all languages ###
BasedOnStyle: LLVM
AccessModifierOffset: -4
AlignAfterOpenBracket: DontAlign
# AlignArrayOfStructures: None
# AlignConsecutiveMacros: None
# AlignConsecutiveAssignments: None
# AlignConsecutiveBitFields: None
# AlignConsecutiveDeclarations: None
# AlignEscapedNewlines: Right
AlignOperands: DontAlign
AlignTrailingComments: false
# AllowAllArgumentsOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: false
# AllowShortEnumsOnASingleLine: true
# AllowShortBlocksOnASingleLine: Never
# AllowShortCaseLabelsOnASingleLine: false
# AllowShortFunctionsOnASingleLine: All
# AllowShortLambdasOnASingleLine: All
# AllowShortIfStatementsOnASingleLine: Never
# AllowShortLoopsOnASingleLine: false
# AlwaysBreakAfterDefinitionReturnType: None
# AlwaysBreakAfterReturnType: None
# AlwaysBreakBeforeMultilineStrings: false
# AlwaysBreakTemplateDeclarations: MultiLine
# AttributeMacros:
# - __capability
# BinPackArguments: true
# BinPackParameters: true
# BraceWrapping:
# AfterCaseLabel: false
# AfterClass: false
# AfterControlStatement: Never
# AfterEnum: false
# AfterFunction: false
# AfterNamespace: false
# AfterObjCDeclaration: false
# AfterStruct: false
# AfterUnion: false
# AfterExternBlock: false
# BeforeCatch: false
# BeforeElse: false
# BeforeLambdaBody: false
# BeforeWhile: false
# IndentBraces: false
# SplitEmptyFunction: true
# SplitEmptyRecord: true
# SplitEmptyNamespace: true
# BreakBeforeBinaryOperators: None
# BreakBeforeConceptDeclarations: true
# BreakBeforeBraces: Attach
# BreakBeforeInheritanceComma: false
# BreakInheritanceList: BeforeColon
# BreakBeforeTernaryOperators: true
# BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: AfterColon
# BreakStringLiterals: true
ColumnLimit: 0
# CommentPragmas: '^ IWYU pragma:'
# QualifierAlignment: Leave
# CompactNamespaces: false
ConstructorInitializerIndentWidth: 8
ContinuationIndentWidth: 8
Cpp11BracedListStyle: false
# DeriveLineEnding: true
# DerivePointerAlignment: false
# DisableFormat: false
# EmptyLineAfterAccessModifier: Never
# EmptyLineBeforeAccessModifier: LogicalBlock
# ExperimentalAutoDetectBinPacking: false
# PackConstructorInitializers: BinPack
ConstructorInitializerAllOnOneLineOrOnePerLine: true
# AllowAllConstructorInitializersOnNextLine: true
# FixNamespaceComments: true
# ForEachMacros:
# - foreach
# - Q_FOREACH
# - BOOST_FOREACH
# IfMacros:
# - KJ_IF_MAYBE
# IncludeBlocks: Preserve
IncludeCategories:
- Regex: '".*"'
Priority: 1
- Regex: '^<.*\.h>'
Priority: 2
- Regex: '^<.*'
Priority: 3
# IncludeIsMainRegex: '(Test)?$'
# IncludeIsMainSourceRegex: ''
# IndentAccessModifiers: false
IndentCaseLabels: true
# IndentCaseBlocks: false
# IndentGotoLabels: true
# IndentPPDirectives: None
# IndentExternBlock: AfterExternBlock
# IndentRequires: false
IndentWidth: 4
# IndentWrappedFunctionNames: false
# InsertTrailingCommas: None
# JavaScriptQuotes: Leave
# JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: false
# LambdaBodyIndentation: Signature
# MacroBlockBegin: ''
# MacroBlockEnd: ''
# MaxEmptyLinesToKeep: 1
# NamespaceIndentation: None
# PenaltyBreakAssignment: 2
# PenaltyBreakBeforeFirstCallParameter: 19
# PenaltyBreakComment: 300
# PenaltyBreakFirstLessLess: 120
# PenaltyBreakOpenParenthesis: 0
# PenaltyBreakString: 1000
# PenaltyBreakTemplateDeclaration: 10
# PenaltyExcessCharacter: 1000000
# PenaltyReturnTypeOnItsOwnLine: 60
# PenaltyIndentedWhitespace: 0
# PointerAlignment: Right
# PPIndentWidth: -1
# ReferenceAlignment: Pointer
# ReflowComments: true
# RemoveBracesLLVM: false
# SeparateDefinitionBlocks: Leave
# ShortNamespaceLines: 1
# SortIncludes: CaseSensitive
# SortJavaStaticImport: Before
# SortUsingDeclarations: true
# SpaceAfterCStyleCast: false
# SpaceAfterLogicalNot: false
# SpaceAfterTemplateKeyword: true
# SpaceBeforeAssignmentOperators: true
# SpaceBeforeCaseColon: false
# SpaceBeforeCpp11BracedList: false
# SpaceBeforeCtorInitializerColon: true
# SpaceBeforeInheritanceColon: true
# SpaceBeforeParens: ControlStatements
# SpaceBeforeParensOptions:
# AfterControlStatements: true
# AfterForeachMacros: true
# AfterFunctionDefinitionName: false
# AfterFunctionDeclarationName: false
# AfterIfMacros: true
# AfterOverloadedOperator: false
# BeforeNonEmptyParentheses: false
# SpaceAroundPointerQualifiers: Default
# SpaceBeforeRangeBasedForLoopColon: true
# SpaceInEmptyBlock: false
# SpaceInEmptyParentheses: false
# SpacesBeforeTrailingComments: 1
# SpacesInAngles: Never
# SpacesInConditionalStatement: false
# SpacesInContainerLiterals: true
# SpacesInCStyleCastParentheses: false
## Godot TODO: We'll want to use a min of 1, but we need to see how to fix
## our comment capitalization at the same time.
SpacesInLineCommentPrefix:
Minimum: 0
Maximum: -1
# SpacesInParentheses: false
# SpacesInSquareBrackets: false
# SpaceBeforeSquareBrackets: false
# BitFieldColonSpacing: Both
# StatementAttributeLikeMacros:
# - Q_EMIT
# StatementMacros:
# - Q_UNUSED
# - QT_REQUIRE_VERSION
TabWidth: 4
# UseCRLF: false
UseTab: Always
# WhitespaceSensitiveMacros:
# - STRINGIZE
# - PP_STRINGIZE
# - BOOST_PP_STRINGIZE
# - NS_SWIFT_NAME
# - CF_SWIFT_NAME
---
### C++ specific config ###
Language: Cpp
Standard: c++17
---
### ObjC specific config ###
Language: ObjC
# ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 4
# ObjCBreakBeforeNestedBlockParam: true
# ObjCSpaceAfterProperty: false
# ObjCSpaceBeforeProtocolList: true
---
### Java specific config ###
Language: Java
# BreakAfterJavaFieldAnnotations: false
JavaImportGroups: ['org.godotengine', 'android', 'androidx', 'com.android', 'com.google', 'java', 'javax']
...

64
.github/ISSUE_TEMPLATE/bug_report.yml vendored Normal file
View File

@@ -0,0 +1,64 @@
name: Bug report
description: Report a bug in the WebRTC native plugin.
body:
- type: markdown
attributes:
value: |
- Write a descriptive issue title above.
- Search [open](https://github.com/godotengine/webrtc-native/issues) and [closed](https://github.com/godotengine/webrtc-native/issues?q=is%3Aissue+is%3Aclosed) issues to ensure it has not already been reported.
- Verify that you are using a [supported Godot version](https://docs.godotengine.org/en/stable/about/release_policy.html).
- type: input
attributes:
label: Godot version
description: >
Specify the Git commit hash if using a development or non-official build.
If you use a custom build, please test if your issue is reproducible in official builds too.
placeholder: 3.3.stable, 4.0.dev (3041becc6)
validations:
required: true
- type: input
attributes:
label: Plugin version
description: >
Specify the Git commit hash if using a development or non-official build.
If you use a custom build, please test if your issue is reproducible in official builds too.
placeholder: 0.3, 0.5, 0.6.dev (072ba5c)
validations:
required: true
- type: input
attributes:
label: System information
description: |
Specify the OS version, and when relevant hardware information.
placeholder: Android 10, Fairphone 3+.
validations:
required: true
- type: textarea
attributes:
label: Issue description
description: |
Describe your issue briefly. What doesn't work, and how do you expect it to work instead?
You can include images or videos with drag and drop, and format code blocks or logs with <code>```</code> tags.
validations:
required: true
- type: textarea
attributes:
label: Steps to reproduce
description: |
List of steps or sample code that reproduces the issue. Having reproducible issues is a prerequisite for contributors to be able to solve them.
If you include a minimal reproduction project below, you can detail how to use it here.
validations:
required: true
- type: textarea
attributes:
label: Minimal reproduction project
description: |
A small Godot project which reproduces the issue. Highly recommended to speed up troubleshooting.
Drag and drop a ZIP archive to upload it.

6
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@@ -0,0 +1,6 @@
blank_issues_enabled: false
contact_links:
- name: Godot proposals
url: https://github.com/godotengine/godot-proposals
about: Please submit feature proposals about the WebRTC exposed API on the Godot proposals repository, not here.

View File

@@ -1,51 +0,0 @@
name: 'Get WebRTC Library'
description: 'Get pre-build statically linked WebRTC library from Faless/webrtc-builds'
inputs:
repo:
description: 'Base repository'
required: true
default: "godotengine/webrtc-actions"
release:
description: 'Release tag'
required: true
default: '4472-33644-92ba70c'
webrtc-base-name:
description: 'The WebRTC version'
required: true
default: "webrtc-33644-92ba70c"
out-dir:
description: 'Directory where to extract the library'
required: true
default: "webrtc"
platform:
description: 'Platform to download'
required: true
archs:
description: 'Space separated list of architecture to fetch'
required: true
runs:
using: "composite"
steps:
- shell: bash
env:
RTC_BASE_URL: https://github.com/${{ inputs.repo }}/releases/download/${{ inputs.release }}/${{ inputs.webrtc-base-name }}
run: |
cd ${{ inputs.out-dir }}
libplat=${{ inputs.platform }}
if [ "${{ inputs.platform }}" = "windows" ]; then
libplat=win
elif [ "${{ inputs.platform }}" = "osx" ]; then
libplat=mac
fi
for arch in ${{ inputs.archs }}
do
echo "Downloading ${{ env.RTC_BASE_URL }}-${{ inputs.platform }}-${arch}.tar.gz"
curl -L ${{ env.RTC_BASE_URL }}-${libplat}-${arch}.tar.gz -o ${arch}.tar.gz
tar -xzf ${arch}.tar.gz
done
mv lib ${{ inputs.platform }}
ls -l
ls -l *

View File

@@ -1,116 +1,170 @@
name: 🔧 Build -> Package 📦
on: [push, pull_request]
env:
# Only used for the cache key. Increment version to force clean build.
GODOT_BASE_BRANCH: master
jobs:
static-checks:
name: 📊 Static Checks (clang-format, black format, file format)
runs-on: ubuntu-20.04
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Install dependencies
run: |
# Add clang repository (so we have clang-format-14)
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
sudo apt-add-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-14 main"
sudo apt-get update
# Install required deps
sudo apt-get install -qq dos2unix moreutils recode clang-format-14
sudo update-alternatives --remove-all clang-format
sudo update-alternatives --install /usr/bin/clang-format clang-format /usr/bin/clang-format-14 100
sudo pip3 install black==22.3.0 pygments
- name: File formatting checks (file_format.sh)
run: |
bash ./misc/scripts/file_format.sh
- name: Style checks via clang-format (clang_format.sh)
run: |
bash ./misc/scripts/clang_format.sh
- name: Python style checks via black (black_format.sh)
run: |
bash ./misc/scripts/black_format.sh
build:
runs-on: ${{ matrix.os }}
name: 🔧 Build
needs: static-checks
strategy:
fail-fast: false
matrix:
include:
# Android
- platform: android
arch: 'x86'
sconsflags: 'android_arch=x86'
os: 'ubuntu-20.04'
- platform: android
arch: 'x64'
sconsflags: 'android_arch=x86_64'
os: 'ubuntu-20.04'
- platform: android
arch: 'arm'
sconsflags: 'android_arch=armv7'
arch: 'x86_64'
gdnative_flags: 'android_arch=x86_64'
sconsflags: ''
os: 'ubuntu-20.04'
cache-name: android-x86_64
- platform: android
arch: 'arm64'
sconsflags: 'android_arch=arm64v8'
gdnative_flags: 'android_arch=arm64v8'
sconsflags: ''
os: 'ubuntu-20.04'
cache-name: android-arm64
# iOS
- platform: ios
arch: 'x64'
sconsflags: 'ios_arch=x86_64 ios_simulator=true'
os: 'macos-latest'
- platform: ios
arch: 'arm'
sconsflags: 'ios_arch=armv7'
os: 'macos-latest'
arch: 'x86_64'
gdnative_flags: 'ios_arch=x86_64'
sconsflags: 'ios_simulator=true'
os: 'macos-11'
cache-name: ios-x86_64-simulator
- platform: ios
arch: 'arm64'
sconsflags: 'ios_arch=arm64'
os: 'macos-latest'
gdnative_flags: 'ios_arch=arm64'
sconsflags: ''
os: 'macos-11'
cache-name: ios-arm64
# Linux
- platform: linux
arch: 'x86'
sconsflags: 'bits=32'
arch: 'x86_32'
buildroot: 'i686'
gdnative_flags: 'bits=32'
sconsflags: ''
os: 'ubuntu-20.04'
cache-name: linux-x86_32
- platform: linux
arch: 'x64'
sconsflags: 'bits=64'
arch: 'x86_64'
buildroot: 'x86_64'
gdnative_flags: 'bits=64'
sconsflags: ''
os: 'ubuntu-20.04'
cache-name: linux-x86_64
# macOS
- platform: osx
arch: 'x64'
sconsflags: 'bits=64'
os: 'macos-latest'
- platform: macos
arch: 'universal'
gdnative_flags: 'macos_arch=universal bits=64'
sconsflags: ''
os: 'macos-11'
cache-name: macos-universal
# Windows
- platform: windows
arch: 'x86'
sconsflags: 'bits=32'
os: 'windows-latest'
arch: 'x86_32'
gdnative_flags: 'bits=32'
sconsflags: 'use_mingw=yes'
os: 'ubuntu-20.04'
msvc_arch: amd64_x86
cache-name: win-x86_32
- platform: windows
arch: 'x64'
sconsflags: 'bits=64'
os: 'windows-latest'
arch: 'x86_64'
gdnative_flags: 'bits=64'
sconsflags: 'use_mingw=yes'
os: 'ubuntu-20.04'
msvc_arch: amd64
cache-name: win-x86_64
env:
SCONSFLAGS: ${{ matrix.sconsflags }} platform=${{ matrix.platform }} --jobs=2
NDK_VERSION: 22b
ANDROID_NDK_ROOT: ${{github.workspace}}/android-ndk-r22b
MSVC_VARS: 'C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat'
SCONS_CACHE: ${{ github.workspace }}/.scons-cache/
SCONSFLAGS: ${{ matrix.sconsflags }} platform=${{ matrix.platform }} arch=${{ matrix.arch }} --jobs=2
defaults:
run:
shell: bash
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with:
submodules: recursive
- name: Cache NDK
id: cache-ndk
if: ${{ matrix.platform == 'android' }}
uses: actions/cache@v2
- name: Setup Godot build cache
uses: ./godot-cpp/.github/actions/godot-cache
with:
path: ${{ env.ANDROID_NDK_ROOT }}
key: ndk-${{ env.NDK_VERSION }}
cache-name: ${{ matrix.cache-name }}
continue-on-error: true
- name: Download NDK
if: ${{ matrix.platform == 'android' && steps.cache-ndk.outputs.cache-hit != 'true' }}
id: setup-ndk
run: |
cd ${{ github.workspace }}
curl -L https://dl.google.com/android/repository/android-ndk-r${{ env.NDK_VERSION }}-linux-x86_64.zip -o ndk.zip
unzip ndk.zip
ls
- name: Setup MSVC build environment for ${{ matrix.msvc_arch }}
- name: Install Windows build dependencies
if: ${{ matrix.platform == 'windows' }}
run: "'${{ env.MSVC_VARS }}' ${{ matrix.msvc_arch }}"
run: |
sudo apt-get update
sudo apt-get install build-essential mingw-w64
sudo update-alternatives --set i686-w64-mingw32-gcc /usr/bin/i686-w64-mingw32-gcc-posix
sudo update-alternatives --set i686-w64-mingw32-g++ /usr/bin/i686-w64-mingw32-g++-posix
sudo update-alternatives --set x86_64-w64-mingw32-gcc /usr/bin/x86_64-w64-mingw32-gcc-posix
sudo update-alternatives --set x86_64-w64-mingw32-g++ /usr/bin/x86_64-w64-mingw32-g++-posix
dpkg -l | grep ii | grep mingw
update-alternatives --get-selections | grep mingw
- name: Setup Linux buildroot toolchain cache
if: ${{ matrix.platform == 'linux' }}
uses: actions/cache@v3
with:
path: |
${{ matrix.buildroot }}-godot-linux-gnu_sdk-buildroot.tar.bz2
key: linux-${{ matrix.buildroot }}-buildroot
- name: Install Linux build dependencies
if: ${{ matrix.platform == 'linux' }}
run: |
sudo apt-get install build-essential gcc-multilib wget g++-multilib
sudo apt-get install build-essential gcc-multilib g++-multilib wget
if [ ! -f ${{ matrix.buildroot }}-godot-linux-gnu_sdk-buildroot.tar.bz2 ]; then
wget https://downloads.tuxfamily.org/godotengine/toolchains/linux/${{ matrix.buildroot }}-godot-linux-gnu_sdk-buildroot.tar.bz2
fi
tar -xjf ${{ matrix.buildroot }}-godot-linux-gnu_sdk-buildroot.tar.bz2
echo "$GITHUB_WORKSPACE/${{ matrix.buildroot }}-godot-linux-gnu_sdk-buildroot/bin" >> $GITHUB_PATH
patch -p1 < misc/patches/scons_path.diff
- name: Set up Python 3.x
uses: actions/setup-python@v2
uses: actions/setup-python@v4
with:
python-version: '3.x'
architecture: 'x64'
@@ -121,60 +175,82 @@ jobs:
python -m pip install scons
python --version
scons --version
cmake --version
- name: Get WebRTC package for ${{ matrix.platform }} - ${{ matrix.arch }}
uses: ./.github/actions/webrtc-download
with:
platform: ${{ matrix.platform }}
archs: ${{ matrix.arch }}
- name: Compilation ${{ matrix.platform }} - ${{ matrix.arch }} - godot-cpp
- name: Compile Extension (4.1+) - template_debug - ${{ matrix.platform }} - ${{ matrix.arch }}
run: |
scons -C godot-cpp target=debug generate_bindings=yes
scons -C godot-cpp target=release
scons target=template_debug godot_version=4.1
- name: Compilation ${{ matrix.platform }} - ${{ matrix.arch }} - webrtc-native
- name: Compile Extension (4.1+) - template_release - ${{ matrix.platform }} - ${{ matrix.arch }}
run: |
scons target=debug
scons target=release
scons target=template_release godot_version=4.1
- uses: actions/upload-artifact@v2
- name: Compile Extension (4.0) - template_debug - ${{ matrix.platform }} - ${{ matrix.arch }}
run: |
scons target=template_debug godot_version=4.0
- name: Compile Extension (4.0) - template_release - ${{ matrix.platform }} - ${{ matrix.arch }}
run: |
scons target=template_release godot_version=4.0
- name: Compile GDNative (3.5+) - release ${{ matrix.platform }} - ${{ matrix.arch }}
run: |
scons target=release generate_bindings=yes ${{ matrix.gdnative_flags }} godot_version=3
- uses: actions/upload-artifact@v3
with:
name: ${{ github.job }}-${{ matrix.platform }}-${{ matrix.arch }}
path: bin/*
path: |
bin/
!bin/thirdparty/
package:
name: 📦 Package
needs: build
runs-on: "ubuntu-latest"
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with:
submodules: recursive
- uses: actions/download-artifact@v2
- uses: actions/download-artifact@v3
with:
path: artifacts
- name: Bundle licenses.
run: |
cp LICENSE artifacts/LICENSE.webrtc-native
cp thirdparty/libdatachannel/LICENSE artifacts/LICENSE.libdatachannel
cp thirdparty/openssl/LICENSE.txt artifacts/LICENSE.openssl
cp thirdparty/libdatachannel/deps/libjuice/LICENSE artifacts/LICENSE.libjuice
cp thirdparty/libdatachannel/deps/usrsctp/LICENSE.md artifacts/LICENSE.usrsctp
cp thirdparty/libdatachannel/deps/libsrtp/LICENSE artifacts/LICENSE.libsrtp
cp thirdparty/libdatachannel/deps/json/LICENSE.MIT artifacts/LICENSE.json
cp thirdparty/libdatachannel/deps/plog/LICENSE artifacts/LICENSE.plog
- name: Package artifacts for release
env:
DESTINATION: "release"
run: |
mkdir release
cd release
for name in webrtc webrtc_debug
do
mkdir -p ${name}/lib/
find ../artifacts -wholename "*/${name}/lib/*" | xargs cp -t ${name}/lib/
find ../artifacts -wholename "*/${name}/${name}.tres" | head -n 1 | xargs cp -t ${name}/
done
zip -r godot-webrtc-native-release.zip webrtc
zip -r godot-webrtc-native-debug.zip webrtc_debug
ls -R
VERSION="extension-4.1" TYPE="webrtc" ./misc/scripts/package_release.sh
VERSION="extension-4.0" TYPE="webrtc" ./misc/scripts/package_release.sh
VERSION="gdnative" TYPE="webrtc" ./misc/scripts/package_release.sh
- uses: actions/upload-artifact@v2
ls -R release
- uses: actions/upload-artifact@v3
with:
name: godot-webrtc-native-debug.zip
path: release/godot-webrtc-native-debug.zip
name: godot-webrtc-extension-4.1
path: release/*-extension-4.1-*.zip
- uses: actions/upload-artifact@v2
- uses: actions/upload-artifact@v3
with:
name: godot-webrtc-native-release.zip
path: release/godot-webrtc-native-release.zip
name: godot-webrtc-extension-4.0
path: release/*-extension-4.0-*.zip
- uses: actions/upload-artifact@v3
with:
name: godot-webrtc-gdnative
path: release/*-gdnative-*.zip

2
.gitignore vendored
View File

@@ -5,3 +5,5 @@ bin/*
.sconsign.dblite
*.obj
*.swp
__pycache__/*
*.pyc

14
.gitmodules vendored
View File

@@ -1,3 +1,15 @@
[submodule "godot-cpp"]
path = godot-cpp
url = https://github.com/GodotNativeTools/godot-cpp
url = https://github.com/godotengine/godot-cpp.git
[submodule "godot-cpp-4.0"]
path = godot-cpp-4.0
url = https://github.com/godotengine/godot-cpp.git
[submodule "godot-cpp-3.x"]
path = godot-cpp-3.x
url = https://github.com/godotengine/godot-cpp.git
[submodule "libdatachannel"]
path = thirdparty/libdatachannel
url = https://github.com/paullouisageneau/libdatachannel.git
[submodule "openssl"]
path = thirdparty/openssl
url = https://github.com/openssl/openssl.git

View File

@@ -7,65 +7,48 @@
### Compiling
Clone this repository with the following command to checkout both [godot-cpp](https://github.com/godotengine/godot-cpp) and [godot-headers](https://github.com/godotengine/godot-headers) dependencies.
Clone this repository with the following command to checkout all the dependencies: [godot-cpp](https://github.com/godotengine/godot-cpp), [openssl](https://www.openssl.org/) and [libdatachannel](https://github.com/paullouisageneau/libdatachannel) (and sub-dependencies).
```
$ git clone --recurse-submodules https://github.com/godotengine/webrtc-native.git
```
Note that if you wish to use a specific branch, add the -b option to the clone command:
```
$ git clone --recurse-submodules -b 3.2 https://github.com/godotengine/webrtc-native.git
```
If you already checked out the branch use the following commands to update the dependencies:
```
$ git submodule update --init --recursive
```
Right now our directory structure should look like this:
```
webrtc-native/
├─bin/
├─godot-cpp/
| └─godot-headers/
├─src/
└─webrtc/
```
### Compiling the extension.
### Compiling the cpp bindings library
First, we need to compile our cpp bindings library:
```
$ cd godot-cpp
$ scons platform=<your platform> generate_bindings=yes
$ cd ..
```
> Replace `<your platform>` with either `windows`, `linux` or `osx`.
> Include `use_llvm=yes` for using clang++
> Include `target=runtime` to build a runtime build (windows only at the moment)
> Include `target=release` or `target=debug` for release or debug build.
> The resulting library will be created in `godot-cpp/bin/`, take note of its name as it will be different depending on platform.
### Building WebRTC
Building WebRTC is quite a complex task, involves huge downloads and long build times, and produces multiple output libraries that needs to bundled together.
To make things easier, a set of [GitHub Actions](https://docs.github.com/en/actions) are used to generate the library for this plugin, [available in this repository](https://github.com/godotengine/webrtc-actions).
Alternatively, [**download the latest pre-compiled libraries**](https://github.com/godotengine/webrtc-actions/releases).
Extract content of `include` into `webrtc/include` and content of `bin` into `webrtc/<your platform>`
### Compiling the plugin.
To build the GDExtension version of the plugin (Godot 4.1+) run the following command from the `webrtc-native` folder:
```
$ scons platform=<your platform> target=<your target>
$ scons platform=<your platform>
```
The generated library and associated `tres` will be placed in `bin/webrtc/` or `bin/webrtc_debug/` according to the desired target. You simply need to copy that folder to the root folder of your project.
This will build all the required dependencies into a single shared library.
To build the "legacy" GDExtension version of the plugin (Godot 4.0) run the following command instead:
```
$ scons platform=<your platform> godot_version=4.0
```
To build the GDNative version of the plugin (Godot 3.x) run the following command instead:
```
$ scons platform=<your platform> godot_version=3
```
> Replace `<your platform>` with either `windows`, `linux`, `osx`, `android`, or `ios`.
> Include `target=release` or `target=debug` for release or debug build (default is `debug`).
The resulting library and associated `tres` or `gdextension` will be created in `bin/[extension|gdnative]/webrtc[_debug]` depending on the `target` and `godot_version`.
You simply need to copy that folder to the root folder of your project. Note that you will have to build the library for all the desired export platforms.
### License
The `webrtc-native` plugin is licensed under the MIT license (see [LICENSE](https://github.com/godotengine/webrtc-native/blob/master/LICENSE)), while `libdatachannel` and its dependencies are licensed under other permissive open source licences. Please see [`thirdparty/README.md`](thirdparty/README.md) for more informations.

View File

@@ -1,354 +1,202 @@
#!python
import os, sys, platform, json, subprocess
if sys.version_info < (3,):
def decode_utf8(x):
return x
else:
import codecs
def decode_utf8(x):
return codecs.utf_8_decode(x)[0]
import SCons
def add_sources(sources, dirpath, extension):
for f in os.listdir(dirpath):
if f.endswith('.' + extension):
sources.append(dirpath + '/' + f)
for f in os.listdir(dirpath):
if f.endswith("." + extension):
sources.append(dirpath + "/" + f)
def gen_gdnative_lib(target, source, env):
for t in target:
with open(t.srcnode().path, 'w') as w:
w.write(decode_utf8(source[0].get_contents()).replace('{GDNATIVE_PATH}', os.path.splitext(t.name)[0]).replace('{TARGET}', env['target']))
def replace_flags(flags, replaces):
for k, v in replaces.items():
if k in flags:
flags[flags.index(k)] = v
env = Environment()
target_arch = ARGUMENTS.get('b', ARGUMENTS.get('bits', '64'))
target_platform = ARGUMENTS.get('p', ARGUMENTS.get('platform', 'linux'))
if target_platform == 'windows':
# This makes sure to keep the session environment variables on windows,
# that way you can run scons in a vs 2017 prompt and it will find all the required tools
if (target_arch == '64'):
env = Environment(ENV = os.environ, TARGET_ARCH='amd64')
else:
env = Environment(ENV = os.environ, TARGET_ARCH='x86')
env.Append(BUILDERS={'GDNativeLibBuilder': Builder(action=gen_gdnative_lib)})
customs = ['custom.py']
opts = Variables(customs, ARGUMENTS)
opts.Add(BoolVariable('use_llvm', 'Use the LLVM compiler', False))
opts.Add(EnumVariable('target', "Compilation target", 'debug', ('debug', 'release')))
opts.Add(EnumVariable(
'android_arch',
'Target Android architecture',
'armv7',
['armv7','arm64v8', 'x86', 'x86_64']
))
opts.Add(
'android_api_level',
'Target Android API level',
'18' if ARGUMENTS.get("android_arch", 'armv7') in ['armv7', 'x86'] else '21'
)
opts.Add(
'ANDROID_NDK_ROOT',
'Path to your Android NDK installation. By default, uses ANDROID_NDK_ROOT from your defined environment variables.',
os.environ.get("ANDROID_NDK_ROOT", None)
)
opts.Add(EnumVariable(
'ios_arch',
'Target iOS architecture',
'arm64',
['armv7', 'arm64', 'x86_64']
))
opts.Add(BoolVariable(
'ios_simulator',
'Target iOS Simulator',
False
))
opts.Add(
'IPHONEPATH',
'Path to iPhone toolchain',
'/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain',
)
# Update environment (parse options)
opts = Variables(["customs.py"], ARGUMENTS)
opts.Add(EnumVariable("godot_version", "The Godot target version", "4.1", ["3", "4.0", "4.1"]))
opts.Update(env)
target = env['target']
# Minimum target platform versions.
if "ios_min_version" not in ARGUMENTS:
ARGUMENTS["ios_min_version"] = "11.0"
if "macos_deployment_target" not in ARGUMENTS:
ARGUMENTS["macos_deployment_target"] = "11.0"
if "android_api_level" not in ARGUMENTS:
ARGUMENTS["android_api_level"] = "28"
if target_platform == 'android':
target_arch = env['android_arch']
elif target_platform == 'ios':
target_arch = env['ios_arch']
if env["godot_version"] == "3":
if "platform" in ARGUMENTS and ARGUMENTS["platform"] == "macos":
ARGUMENTS["platform"] = "osx" # compatibility with old osx name
host_platform = platform.system()
# Local dependency paths, adapt them to your setup
godot_headers = ARGUMENTS.get('headers', 'godot-cpp/godot-headers')
godot_cpp_headers = ARGUMENTS.get('godot_cpp_headers', 'godot-cpp/include')
godot_cpp_lib_dir = ARGUMENTS.get('godot_cpp_lib_dir', 'godot-cpp/bin')
result_path = os.path.join('bin', 'webrtc' if env['target'] == 'release' else 'webrtc_debug', 'lib')
lib_prefix = ""
env = SConscript("godot-cpp-3.x/SConstruct")
# Convenience check to enforce the use_llvm overrides when CXX is clang(++)
if 'CXX' in env and 'clang' in os.path.basename(env['CXX']):
env['use_llvm'] = True
# Patch base env
replace_flags(
env["CCFLAGS"],
{
"-mios-simulator-version-min=10.0": "-mios-simulator-version-min=11.0",
"-miphoneos-version-min=10.0": "-miphoneos-version-min=11.0",
"/std:c++14": "/std:c++17",
"-std=c++14": "-std=c++17",
},
)
if target_platform == 'linux':
env['CXX']='g++'
env = env.Clone()
# LLVM
if env['use_llvm']:
if ('clang++' not in os.path.basename(env['CXX'])):
env['CC'] = 'clang'
env["CXX"] = "clang++"
env["LINK"] = "clang++"
if env["target"] == "debug":
env.Append(CPPDEFINES=["DEBUG_ENABLED"])
if (env["target"] == "debug"):
env.Prepend(CCFLAGS=['-g3'])
env.Append(LINKFLAGS=['-rdynamic'])
else:
env.Prepend(CCFLAGS=['-O3'])
if env["platform"] == "windows" and env["use_mingw"]:
env.Append(LINKFLAGS=["-static-libgcc"])
env.Append(CCFLAGS=['-fPIC', '-std=c++14'])
if env["platform"] == "osx":
env["platform"] = "macos" # compatibility with old osx name
ARGUMENTS["platform"] = "macos"
env["CC"] = "clang" # CC is not set in 3.x and can result in it being "gcc".
if target_arch == '32':
env.Append(CCFLAGS = [ '-m32' ])
env.Append(LINKFLAGS = [ '-m32' ])
elif target_arch == '64':
env.Append(CCFLAGS = [ '-m64' ])
env.Append(LINKFLAGS = [ '-m64' ])
# i386 does not like static libstdc++
env.Append(LINKFLAGS=['-static-libgcc', '-static-libstdc++'])
if env["platform"] == "ios":
env["ios_min_version"] = "11.0"
elif target_platform == 'windows':
if host_platform == 'Windows':
# Normalize suffix
if env["platform"] in ["windows", "linux"]:
env["arch"] = "x86_32" if env["bits"] == "32" else "x86_64"
env["arch_suffix"] = env["arch"]
elif env["platform"] == "macos":
env["arch"] = env["macos_arch"]
env["arch_suffix"] = env["arch"]
elif env["platform"] == "ios":
env["arch"] = "arm32" if env["ios_arch"] == "armv7" else env["ios_arch"]
env["arch_suffix"] = env["ios_arch"] + (".simulator" if env["ios_simulator"] else "")
elif env["platform"] == "android":
env["arch"] = {
"armv7": "arm32",
"arm64v8": "arm64",
"x86": "x86_32",
"x86_64": "x86_64",
}[env["android_arch"]]
env["arch_suffix"] = env["arch"]
lib_prefix = "lib"
env.Append(LINKFLAGS = [ '/WX' ])
if target == 'debug':
env.Append(CCFLAGS = ['/EHsc', '/D_DEBUG', '/MDd' ])
else:
env.Append(CCFLAGS = ['/O2', '/EHsc', '/DNDEBUG', '/MD' ])
else:
if target_arch == '32':
env['CXX']='i686-w64-mingw32-g++'
elif target_arch == '64':
env['CXX']='x86_64-w64-mingw32-g++'
if env['target'] == 'debug':
env.Append(CCFLAGS=['-Og', '-g'])
elif env['target'] == 'release':
env.Append(CCFLAGS=['-O3'])
env.Append(CCFLAGS = [ '-std=c++14', '-Wwrite-strings' ])
env.Append(LINKFLAGS = [ '--static', '-Wl,--no-undefined', '-static-libgcc', '-static-libstdc++' ])
elif target_platform == 'osx':
if env['use_llvm']:
env['CXX'] = 'clang++'
# Only 64-bits is supported for OS X
target_arch = '64'
env.Append(CCFLAGS = [ '-std=c++14', '-arch', 'x86_64' ])
env.Append(LINKFLAGS = [ '-arch', 'x86_64', '-framework', 'Cocoa', '-Wl,-undefined,dynamic_lookup' ])
if env['target'] == 'debug':
env.Append(CCFLAGS=['-Og', '-g'])
elif env['target'] == 'release':
env.Append(CCFLAGS=['-O3'])
elif target_platform == 'ios':
if env['ios_simulator']:
sdk_name = 'iphonesimulator'
env.Append(CCFLAGS=['-mios-simulator-version-min=10.0'])
env['LIBSUFFIX'] = ".simulator" + env['LIBSUFFIX']
else:
sdk_name = 'iphoneos'
env.Append(CCFLAGS=['-miphoneos-version-min=10.0'])
try:
sdk_path = decode_utf8(subprocess.check_output(['xcrun', '--sdk', sdk_name, '--show-sdk-path']).strip())
except (subprocess.CalledProcessError, OSError):
raise ValueError("Failed to find SDK path while running xcrun --sdk {} --show-sdk-path.".format(sdk_name))
compiler_path = env['IPHONEPATH'] + '/usr/bin/'
env['ENV']['PATH'] = env['IPHONEPATH'] + "/Developer/usr/bin/:" + env['ENV']['PATH']
env['CC'] = compiler_path + 'clang'
env['CXX'] = compiler_path + 'clang++'
env['AR'] = compiler_path + 'ar'
env['RANLIB'] = compiler_path + 'ranlib'
env.Append(CCFLAGS=['-std=c++14', '-arch', env['ios_arch'], '-isysroot', sdk_path])
env.Append(LINKFLAGS=[
'-arch',
env['ios_arch'],
'-Wl,-undefined,dynamic_lookup',
'-isysroot', sdk_path,
'-F' + sdk_path
])
if env['target'] == 'debug':
env.Append(CCFLAGS=['-Og', '-g'])
elif env['target'] == 'release':
env.Append(CCFLAGS=['-O3'])
elif target_platform == 'android':
# Verify NDK root
if not 'ANDROID_NDK_ROOT' in env:
raise ValueError("To build for Android, ANDROID_NDK_ROOT must be defined. Please set ANDROID_NDK_ROOT to the root folder of your Android NDK installation.")
# Validate API level
api_level = int(env['android_api_level'])
if target_arch in ['arm64v8', 'x86_64'] and api_level < 21:
print("WARN: 64-bit Android architectures require an API level of at least 21; setting android_api_level=21")
env['android_api_level'] = '21'
api_level = 21
# Setup toolchain
toolchain = env['ANDROID_NDK_ROOT'] + "/toolchains/llvm/prebuilt/"
if host_platform == "Windows":
toolchain += "windows"
import platform as pltfm
if pltfm.machine().endswith("64"):
toolchain += "-x86_64"
elif host_platform == "Linux":
toolchain += "linux-x86_64"
elif host_platform == "Darwin":
toolchain += "darwin-x86_64"
# Get architecture info
arch_info_table = {
"armv7" : {
"march":"armv7-a", "target":"armv7a-linux-androideabi", "tool_path":"arm-linux-androideabi", "compiler_path":"armv7a-linux-androideabi",
"ccflags" : ['-mfpu=neon']
},
"arm64v8" : {
"march":"armv8-a", "target":"aarch64-linux-android", "tool_path":"aarch64-linux-android", "compiler_path":"aarch64-linux-android",
"ccflags" : []
},
"x86" : {
"march":"i686", "target":"i686-linux-android", "tool_path":"i686-linux-android", "compiler_path":"i686-linux-android",
"ccflags" : ['-mstackrealign']
},
"x86_64" : {"march":"x86-64", "target":"x86_64-linux-android", "tool_path":"x86_64-linux-android", "compiler_path":"x86_64-linux-android",
"ccflags" : []
}
}
arch_info = arch_info_table[target_arch]
# Setup tools
env['CC'] = toolchain + "/bin/clang"
env['CXX'] = toolchain + "/bin/clang++"
env.Append(CCFLAGS=['--target=' + arch_info['target'] + env['android_api_level'], '-march=' + arch_info['march'], '-fPIC'])
env.Append(CCFLAGS=arch_info['ccflags'])
env.Append(LINKFLAGS=['--target=' + arch_info['target'] + env['android_api_level'], '-march=' + arch_info['march']])
if env['target'] == 'debug':
env.Append(CCFLAGS=['-Og', '-g'])
elif env['target'] == 'release':
env.Append(CCFLAGS=['-O3'])
target_compat = "template_" + env["target"]
env["suffix"] = ".{}.{}.{}".format(env["platform"], target_compat, env["arch_suffix"])
env["debug_symbols"] = False
# Some windows specific hacks.
if env["platform"] == "windows":
if sys.platform not in ["win32", "msys"]:
# Set missing CC for MinGW from upstream build module.
if env["bits"] == "64":
env["CC"] = "x86_64-w64-mingw32-gcc"
elif env["bits"] == "32":
env["CC"] = "i686-w64-mingw32-gcc"
elif not env["use_mingw"]:
# Mark as MSVC build (would have failed to build the library otherwise).
env["is_msvc"] = True
elif env["godot_version"] == "4.0":
env = SConscript("godot-cpp-4.0/SConstruct").Clone()
else:
print("No valid target platform selected.")
sys.exit(1)
env = SConscript("godot-cpp/SConstruct").Clone()
# Godot CPP bindings
env.Append(CPPPATH=[godot_headers])
env.Append(CPPPATH=[godot_cpp_headers, godot_cpp_headers + '/core', godot_cpp_headers + '/gen'])
env.Append(LIBPATH=[godot_cpp_lib_dir])
env.Append(LIBS=['%sgodot-cpp.%s.%s.%s%s' % (lib_prefix, target_platform, target, target_arch, ".simulator" if env["ios_simulator"] else "")])
# Should probably go to upstream godot-cpp.
# We let SCons build its default ENV as it includes OS-specific things which we don't
# want to have to pull in manually.
# Then we prepend PATH to make it take precedence, while preserving SCons' own entries.
env.PrependENVPath("PATH", os.getenv("PATH"))
env.PrependENVPath("PKG_CONFIG_PATH", os.getenv("PKG_CONFIG_PATH"))
if "TERM" in os.environ: # Used for colored output.
env["ENV"]["TERM"] = os.environ["TERM"]
# WebRTC stuff
webrtc_dir = "webrtc"
lib_name = 'libwebrtc_full'
lib_path = os.path.join(webrtc_dir, target_platform)
# Patch mingw SHLIBSUFFIX.
if env["platform"] == "windows" and env["use_mingw"]:
env["SHLIBSUFFIX"] = ".dll"
lib_path += {'32': '/x86',
'64': '/x64',
'armv7': '/arm',
'arm64v8': '/arm64',
'arm64': '/arm64',
'x86': '/x86',
'x86_64': '/x64'}[target_arch]
# Patch OSXCross config.
if env["platform"] == "macos" and os.environ.get("OSXCROSS_ROOT", ""):
env["SHLIBSUFFIX"] = ".dylib"
if env["macos_deployment_target"] != "default":
env["ENV"]["MACOSX_DEPLOYMENT_TARGET"] = env["macos_deployment_target"]
if target == 'debug':
lib_path += '/Debug'
# Patch linux flags to statically link libgcc and libstdc++
if env["platform"] == "linux":
env.Append(
LINKFLAGS=[
"-Wl,--no-undefined",
"-static-libgcc",
"-static-libstdc++",
]
)
# And add some linux dependencies.
env.Append(LIBS=["pthread", "dl"])
opts.Update(env)
target = env["target"]
if env["godot_version"] == "3":
result_path = os.path.join("bin", "gdnative", "webrtc" if env["target"] == "release" else "webrtc_debug")
elif env["godot_version"] == "4.0":
result_path = os.path.join("bin", "extension-4.0", "webrtc")
else:
lib_path += '/Release'
env.Append(CPPPATH=[webrtc_dir + "/include", webrtc_dir + "/include/third_party/abseil-cpp"])
if target_platform == "linux":
env.Append(LIBS=[lib_name, "atomic"])
env.Append(LIBPATH=[lib_path])
#env.Append(CCFLAGS=["-std=c++11"])
env.Append(CCFLAGS=["-DWEBRTC_POSIX", "-DWEBRTC_LINUX"])
env.Append(CCFLAGS=["-DRTC_UNUSED=''", "-DNO_RETURN=''"])
elif target_platform == "windows":
# Mostly VisualStudio
if env["CC"] == "cl":
env.Append(CCFLAGS=["/DWEBRTC_WIN", "/DWIN32_LEAN_AND_MEAN", "/DNOMINMAX", "/DRTC_UNUSED=", "/DNO_RETURN="])
env.Append(LINKFLAGS=[p + env["LIBSUFFIX"] for p in ["secur32", "advapi32", "winmm", lib_name]])
env.Append(LIBPATH=[lib_path])
# Mostly "gcc"
else:
env.Append(CCFLAGS=["-DWINVER=0x0603", "-D_WIN32_WINNT=0x0603", "-DWEBRTC_WIN", "-DWIN32_LEAN_AND_MEAN", "-DNOMINMAX", "-DRTC_UNUSED=", "-DNO_RETURN="])
env.Append(LINKFLAGS=[p + env["LIBSUFFIX"] for p in ["secur32", "advapi32", "winmm", lib_name]])
env.Append(LIBPATH=[lib_path])
elif target_platform == "osx":
env.Append(LIBS=[lib_name])
env.Append(LIBPATH=[lib_path])
env.Append(CCFLAGS=["-DWEBRTC_POSIX", "-DWEBRTC_MAC"])
env.Append(CCFLAGS=["-DRTC_UNUSED=''", "-DNO_RETURN=''"])
elif target_platform == 'ios':
env.Append(LIBS=[lib_name])
env.Append(LIBPATH=[lib_path])
env.Append(CCFLAGS=["-DWEBRTC_POSIX", "-DWEBRTC_MAC", "-DWEBRTC_IOS"])
env.Append(CCFLAGS=["-DRTC_UNUSED=''", "-DNO_RETURN=''"])
elif target_platform == "android":
env.Append(LIBS=['log'])
env.Append(LIBS=[lib_name])
env.Append(LIBPATH=[lib_path])
env.Append(CCFLAGS=["-DWEBRTC_POSIX", "-DWEBRTC_LINUX", "-DWEBRTC_ANDROID"])
env.Append(CCFLAGS=["-DRTC_UNUSED=''", "-DNO_RETURN=''"])
if target_arch == 'arm64v8':
env.Append(CCFLAGS=["-DWEBRTC_ARCH_ARM64", "-DWEBRTC_HAS_NEON"])
elif target_arch == 'armv7':
env.Append(CCFLAGS=["-DWEBRTC_ARCH_ARM", "-DWEBRTC_ARCH_ARM_V7", "-DWEBRTC_HAS_NEON"])
result_path = os.path.join("bin", "extension-4.1", "webrtc")
# Our includes and sources
env.Append(CPPPATH=['src/'])
env.Append(CPPPATH=["src/"])
env.Append(CPPDEFINES=["RTC_STATIC"])
sources = []
add_sources(sources, 'src/', 'cpp')
add_sources(sources, 'src/net/', 'cpp')
sources.append(
[
"src/WebRTCLibDataChannel.cpp",
"src/WebRTCLibPeerConnection.cpp",
]
)
if env["godot_version"] == "3":
env.Append(CPPDEFINES=["GDNATIVE_WEBRTC"])
sources.append("src/init_gdnative.cpp")
add_sources(sources, "src/net/", "cpp")
else:
sources.append("src/init_gdextension.cpp")
if env["godot_version"] == "4.0":
env.Append(CPPDEFINES=["GDEXTENSION_WEBRTC_40"])
# Suffix
suffix = '.%s.%s' % (target, target_arch)
env["SHOBJSUFFIX"] = suffix + env["SHOBJSUFFIX"]
# Add our build tools
for tool in ["openssl", "cmake", "rtc"]:
env.Tool(tool, toolpath=["tools"])
ssl = env.OpenSSL()
rtc = env.BuildLibDataChannel(ssl)
# Forces building our sources after OpenSSL and libdatachannel.
# This is because OpenSSL headers are generated by their build system and SCons doesn't know about them.
# Note: This might not be necessary in this specific case since our sources doesn't include OpenSSL headers directly,
# but it's better to be safe in case of indirect inclusions by one of our other dependencies.
env.Depends(sources, ssl + rtc)
# Make the shared library
result_name = 'webrtc_native.%s.%s.%s' % (target_platform, target, target_arch) + env["SHLIBSUFFIX"]
library = env.SharedLibrary(target=os.path.join(result_path, result_name), source=sources)
result_name = "libwebrtc_native{}{}".format(env["suffix"], env["SHLIBSUFFIX"])
library = env.SharedLibrary(target=os.path.join(result_path, "lib", result_name), source=sources)
Default(library)
# GDNativeLibrary
gdnlib = 'webrtc'
if target != 'release':
gdnlib += '_debug'
Default(env.GDNativeLibBuilder([os.path.join('bin', gdnlib, gdnlib + '.tres')], ['misc/gdnlib.tres']))
if env["godot_version"] == "3":
gdnlib = "webrtc" if target != "debug" else "webrtc_debug"
ext = ".tres"
extfile = env.Substfile(
os.path.join(result_path, gdnlib + ext),
"misc/webrtc" + ext,
SUBST_DICT={
"{GDNATIVE_PATH}": gdnlib,
"{TARGET}": "template_" + env["target"],
},
)
else:
extfile = env.Substfile(
os.path.join(result_path, "webrtc.gdextension"),
"misc/webrtc.gdextension",
SUBST_DICT={"{GODOT_VERSION}": env["godot_version"]},
)
Default(extfile)

1
godot-cpp-3.x Submodule

Submodule godot-cpp-3.x added at 7c09b5484d

1
godot-cpp-4.0 Submodule

Submodule godot-cpp-4.0 added at 9d1c396c54

View File

@@ -1,28 +0,0 @@
[gd_resource type="GDNativeLibrary" format=2]
[resource]
singleton = true
reloadable = false
entry/OSX.64 = "res://{GDNATIVE_PATH}/lib/libwebrtc_native.osx.{TARGET}.64.dylib"
entry/OSX.arm64 = "res://{GDNATIVE_PATH}/lib/libwebrtc_native.osx.{TARGET}.arm64.dylib"
entry/Windows.64 = "res://{GDNATIVE_PATH}/lib/webrtc_native.windows.{TARGET}.64.dll"
entry/Windows.32 = "res://{GDNATIVE_PATH}/lib/webrtc_native.windows.{TARGET}.32.dll"
entry/X11.64 = "res://{GDNATIVE_PATH}/lib/libwebrtc_native.linux.{TARGET}.64.so"
entry/X11.32 = "res://{GDNATIVE_PATH}/lib/libwebrtc_native.linux.{TARGET}.32.so"
entry/Server.64 = "res://{GDNATIVE_PATH}/lib/libwebrtc_native.linux.{TARGET}.64.so"
entry/Server.32 = "res://{GDNATIVE_PATH}/lib/libwebrtc_native.linux.{TARGET}.32.so"
entry/Android.armeabi-v7a = "res://{GDNATIVE_PATH}/lib/libwebrtc_native.android.{TARGET}.armv7.so"
entry/Android.arm64-v8a = "res://{GDNATIVE_PATH}/lib/libwebrtc_native.android.{TARGET}.arm64v8.so"
entry/Android.x64 = "res://{GDNATIVE_PATH}/lib/libwebrtc_native.android.{TARGET}.x86_64.so"
entry/Android.x86 = "res://{GDNATIVE_PATH}/lib/libwebrtc_native.android.{TARGET}.x86.so"
entry/iOS.armv7 = "res://{GDNATIVE_PATH}/lib/libwebrtc_native.ios.{TARGET}.armv7.dylib"
entry/iOS.arm64 = "res://{GDNATIVE_PATH}/lib/libwebrtc_native.ios.{TARGET}.arm64.dylib"
entry/iOS.x86_64 = "res://{GDNATIVE_PATH}/lib/libwebrtc_native.ios.{TARGET}.x86_64.dylib"
dependency/Windows.64 = [ ]
dependency/Windows.32 = [ ]
dependency/X11.64 = [ ]
dependency/X11.32 = [ ]
dependency/Server.64 = [ ]
dependency/Server.32 = [ ]
dependency/Android.armeabi-v7a = [ ]
dependency/Android.arm64-v8a = [ ]

View File

@@ -0,0 +1,29 @@
diff --git a/godot-cpp-4.0/SConstruct b/godot-cpp-4.0/SConstruct
index 27ee137..32b425e 100644
--- a/godot-cpp-4.0/SConstruct
+++ b/godot-cpp-4.0/SConstruct
@@ -54,6 +54,8 @@ else:
# Default tools with no platform defaults to gnu toolchain.
# We apply platform specific toolchains via our custom tools.
env = Environment(tools=["default"], PLATFORM="")
+# Allows us to use Godot buildroot toolchain
+env.PrependENVPath("PATH", os.getenv("PATH"))
# Default num_jobs to local cpu count if not user specified.
# SCons has a peculiarity where user-specified options won't be overridden
diff --git a/godot-cpp-3.x/SConstruct b/godot-cpp-3.x/SConstruct
index f653d54..6f40377 100644
--- a/godot-cpp-3.x/SConstruct
+++ b/godot-cpp-3.x/SConstruct
@@ -194,6 +194,9 @@ if host_platform == "windows" and env["platform"] != "android":
opts.Update(env)
+# Allows us to use Godot buildroot toolchain
+env.PrependENVPath("PATH", os.getenv("PATH"))
+
# Require C++14
if host_platform == "windows" and env["platform"] == "windows" and not env["use_mingw"]:
# MSVC

26
misc/scripts/black_format.sh Executable file
View File

@@ -0,0 +1,26 @@
#!/usr/bin/env bash
# This script runs black on all Python files in the repo.
set -uo pipefail
# Apply black.
echo -e "Formatting Python files..."
PY_FILES=$(git ls-files -- '*SConstruct' '*SCsub' '*.py' ':!:.git/*' ':!:thirdparty/*')
black -l 120 $PY_FILES
diff=$(git diff --color)
# If no diff has been generated all is OK, clean up, and exit.
if [ -z "$diff" ] ; then
printf "\e[1;32m*** Files in this commit comply with the black style rules.\e[0m\n"
exit 0
fi
# A diff has been created, notify the user, clean up, and exit.
printf "\n\e[1;33m*** The following changes must be made to comply with the formatting rules:\e[0m\n\n"
# Perl commands replace trailing spaces with `·` and tabs with `<TAB>`.
printf "$diff\n" | perl -pe 's/(.*[^ ])( +)(\e\[m)$/my $spaces="·" x length($2); sprintf("$1$spaces$3")/ge' | perl -pe 's/(.*[^\t])(\t+)(\e\[m)$/my $tabs="<TAB>" x length($2); sprintf("$1$tabs$3")/ge'
printf "\n\e[1;91m*** Please fix your commit(s) with 'git commit --amend' or 'git rebase -i <hash>'\e[0m\n"
exit 1

53
misc/scripts/clang_format.sh Executable file
View File

@@ -0,0 +1,53 @@
#!/usr/bin/env bash
# This script runs clang-format and fixes copyright headers on all relevant files in the repo.
# This is the primary script responsible for fixing style violations.
set -uo pipefail
if [ $# -eq 0 ]; then
# Loop through all code files tracked by Git.
files=$(git ls-files -- '*.c' '*.h' '*.cpp' '*.hpp' '*.cc' '*.hh' '*.cxx' '*.m' '*.mm' '*.inc' '*.java' '*.glsl' \
':!:.git/*' ':!:thirdparty/*' ':!:*/thirdparty/*' ':!:platform/android/java/lib/src/com/google/*' \
':!:*-so_wrap.*' ':!:tests/python_build/*')
else
# $1 should be a file listing file paths to process. Used in CI.
files=$(cat "$1" | grep -v "thirdparty/" | grep -E "\.(c|h|cpp|hpp|cc|hh|cxx|m|mm|inc|java|glsl)$" | grep -v "platform/android/java/lib/src/com/google/" | grep -v "\-so_wrap\." | grep -v "tests/python_build/")
fi
if [ ! -z "$files" ]; then
clang-format --Wno-error=unknown -i $files
fi
# Fix copyright headers, but not all files get them.
for f in $files; do
if [[ "$f" == *"inc" ]]; then
continue
elif [[ "$f" == *"glsl" ]]; then
continue
elif [[ "$f" == "platform/android/java/lib/src/org/godotengine/godot/gl/GLSurfaceView"* ]]; then
continue
elif [[ "$f" == "platform/android/java/lib/src/org/godotengine/godot/gl/EGLLogWrapper"* ]]; then
continue
elif [[ "$f" == "platform/android/java/lib/src/org/godotengine/godot/utils/ProcessPhoenix"* ]]; then
continue
fi
python misc/scripts/copyright_headers.py "$f"
done
diff=$(git diff --color)
# If no diff has been generated all is OK, clean up, and exit.
if [ -z "$diff" ] ; then
printf "\e[1;32m*** Files in this commit comply with the clang-format style rules.\e[0m\n"
exit 0
fi
# A diff has been created, notify the user, clean up, and exit.
printf "\n\e[1;33m*** The following changes must be made to comply with the formatting rules:\e[0m\n\n"
# Perl commands replace trailing spaces with `·` and tabs with `<TAB>`.
printf "$diff\n" | perl -pe 's/(.*[^ ])( +)(\e\[m)$/my $spaces="·" x length($2); sprintf("$1$spaces$3")/ge' | perl -pe 's/(.*[^\t])(\t+)(\e\[m)$/my $tabs="<TAB>" x length($2); sprintf("$1$tabs$3")/ge'
printf "\n\e[1;91m*** Please fix your commit(s) with 'git commit --amend' or 'git rebase -i <hash>'\e[0m\n"
exit 1

View File

@@ -0,0 +1,95 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
header = """\
/**************************************************************************/
/* $filename */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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. */
/**************************************************************************/
"""
fname = sys.argv[1]
# Handle replacing $filename with actual filename and keep alignment
fsingle = fname.strip()
if fsingle.find("/") != -1:
fsingle = fsingle[fsingle.rfind("/") + 1 :]
rep_fl = "$filename"
rep_fi = fsingle
len_fl = len(rep_fl)
len_fi = len(rep_fi)
# Pad with spaces to keep alignment
if len_fi < len_fl:
for x in range(len_fl - len_fi):
rep_fi += " "
elif len_fl < len_fi:
for x in range(len_fi - len_fl):
rep_fl += " "
if header.find(rep_fl) != -1:
text = header.replace(rep_fl, rep_fi)
else:
text = header.replace("$filename", fsingle)
text += "\n"
# We now have the proper header, so we want to ignore the one in the original file
# and potentially empty lines and badly formatted lines, while keeping comments that
# come after the header, and then keep everything non-header unchanged.
# To do so, we skip empty lines that may be at the top in a first pass.
# In a second pass, we skip all consecutive comment lines starting with "/*",
# then we can append the rest (step 2).
fileread = open(fname.strip(), "r")
line = fileread.readline()
header_done = False
while line.strip() == "": # Skip empty lines at the top
line = fileread.readline()
if line.find("/**********") == -1: # Godot header starts this way
# Maybe starting with a non-Godot comment, abort header magic
header_done = True
while not header_done: # Handle header now
if line.find("/*") != 0: # No more starting with a comment
header_done = True
if line.strip() != "":
text += line
line = fileread.readline()
while line != "": # Dump everything until EOF
text += line
line = fileread.readline()
fileread.close()
# Write
filewrite = open(fname.strip(), "w")
filewrite.write(text)
filewrite.close()

89
misc/scripts/file_format.sh Executable file
View File

@@ -0,0 +1,89 @@
#!/usr/bin/env bash
# This script ensures proper POSIX text file formatting and a few other things.
# This is supplementary to clang_format.sh and black_format.sh, but should be
# run before them.
# We need dos2unix and isutf8.
if [ ! -x "$(command -v dos2unix)" -o ! -x "$(command -v isutf8)" ]; then
printf "Install 'dos2unix' and 'isutf8' (moreutils package) to use this script.\n"
exit 1
fi
set -uo pipefail
if [ $# -eq 0 ]; then
# Loop through all code files tracked by Git.
mapfile -d '' files < <(git grep -zIl '')
else
# $1 should be a file listing file paths to process. Used in CI.
mapfile -d ' ' < <(cat "$1")
fi
for f in "${files[@]}"; do
# Exclude some types of files.
if [[ "$f" == *"csproj" ]]; then
continue
elif [[ "$f" == *"sln" ]]; then
continue
elif [[ "$f" == *".bat" ]]; then
continue
elif [[ "$f" == *".out" ]]; then
# GDScript integration testing files.
continue
elif [[ "$f" == *"patch" ]]; then
continue
elif [[ "$f" == *"pot" ]]; then
continue
elif [[ "$f" == *"po" ]]; then
continue
elif [[ "$f" == "thirdparty/"* ]]; then
continue
elif [[ "$f" == *"/thirdparty/"* ]]; then
continue
elif [[ "$f" == "platform/android/java/lib/src/com/google"* ]]; then
continue
elif [[ "$f" == *"-so_wrap."* ]]; then
continue
elif [[ "$f" == *".test.txt" ]]; then
continue
fi
# Ensure that files are UTF-8 formatted.
isutf8 "$f" >> utf8-validation.txt 2>&1
# Ensure that files have LF line endings and do not contain a BOM.
dos2unix "$f" 2> /dev/null
# Remove trailing space characters and ensures that files end
# with newline characters. -l option handles newlines conveniently.
perl -i -ple 's/\s*$//g' "$f"
done
diff=$(git diff --color)
if [ ! -s utf8-validation.txt ] && [ -z "$diff" ] ; then
# If no UTF-8 violations were collected (the file is empty) and
# no diff has been generated all is OK, clean up, and exit.
printf "\e[1;32m*** Files in this commit comply with the file formatting rules.\e[0m\n"
rm -f utf8-validation.txt
exit 0
fi
if [ -s utf8-validation.txt ]
then
# If the file has content and is not empty, violations
# detected, notify the user, clean up, and exit.
printf "\n\e[1;33m*** The following files contain invalid UTF-8 character sequences:\e[0m\n\n"
cat utf8-validation.txt
fi
rm -f utf8-validation.txt
if [ ! -z "$diff" ]
then
# A diff has been created, notify the user, clean up, and exit.
printf "\n\e[1;33m*** The following changes must be made to comply with the formatting rules:\e[0m\n\n"
# Perl commands replace trailing spaces with `·` and tabs with `<TAB>`.
printf "$diff\n" | perl -pe 's/(.*[^ ])( +)(\e\[m)$/my $spaces="·" x length($2); sprintf("$1$spaces$3")/ge' | perl -pe 's/(.*[^\t])(\t+)(\e\[m)$/my $tabs="<TAB>" x length($2); sprintf("$1$tabs$3")/ge'
fi
printf "\n\e[1;91m*** Please fix your commit(s) with 'git commit --amend' or 'git rebase -i <hash>'\e[0m\n"
exit 1

33
misc/scripts/package_release.sh Executable file
View File

@@ -0,0 +1,33 @@
#!/bin/bash
set -e
set -x
ARTIFACTS=${ARTIFACTS:-"artifacts"}
DESTINATION=${DESTIONATION:-"release"}
VERSION=${VERSION:-"extension"}
TYPE=${TYPE:-"webrtc"}
mkdir -p ${DESTINATION}
ls -R ${DESTINATION}
ls -R ${ARTIFACTS}
DESTDIR="${DESTINATION}/${VERSION}/${TYPE}"
mkdir -p ${DESTDIR}/lib
find "${ARTIFACTS}" -wholename "*/${VERSION}/${TYPE}/lib/*" | xargs cp -t "${DESTDIR}/lib/"
find "${ARTIFACTS}" -wholename "*/LICENSE*" | xargs cp -t "${DESTDIR}/"
if [ $VERSION = "gdnative" ]; then
find "${ARTIFACTS}" -wholename "*/${VERSION}/${TYPE}/${TYPE}.tres" | head -n 1 | xargs cp -t "${DESTDIR}/"
else
find "${ARTIFACTS}" -wholename "*/${VERSION}/${TYPE}/${TYPE}.gdextension" | head -n 1 | xargs cp -t "${DESTDIR}/"
fi
CURDIR=$(pwd)
cd "${DESTINATION}/${VERSION}"
zip -r ../godot-${VERSION}-${TYPE}.zip ${TYPE}
cd "$CURDIR"
ls -R ${DESTINATION}

30
misc/webrtc.gdextension Normal file
View File

@@ -0,0 +1,30 @@
[configuration]
entry_symbol = "webrtc_extension_init"
compatibility_minimum = {GODOT_VERSION}
[libraries]
linux.debug.x86_64 = "res://webrtc/lib/libwebrtc_native.linux.template_debug.x86_64.so"
linux.debug.x86_32 = "res://webrtc/lib/libwebrtc_native.linux.template_debug.x86_32.so"
linux.debug.arm64 = "res://webrtc/lib/libwebrtc_native.linux.template_debug.arm64.so"
linux.debug.arm32 = "res://webrtc/lib/libwebrtc_native.linux.template_debug.arm32.so"
macos.debug = "res://webrtc/lib/libwebrtc_native.macos.template_debug.universal.dylib"
windows.debug.x86_64 = "res://webrtc/lib/libwebrtc_native.windows.template_debug.x86_64.dll"
windows.debug.x86_32 = "res://webrtc/lib/libwebrtc_native.windows.template_debug.x86_32.dll"
android.debug.arm64 = "res://webrtc/lib/libwebrtc_native.android.template_debug.arm64.so"
android.debug.x86_64 = "res://webrtc/lib/libwebrtc_native.android.template_debug.x86_64.so"
ios.debug.arm64 = "res://webrtc/lib/libwebrtc_native.ios.template_debug.arm64.dylib"
ios.debug.x86_64 = "res://webrtc/lib/libwebrtc_native.ios.template_debug.x86_64.simulator.dylib"
linux.release.x86_64 = "res://webrtc/lib/libwebrtc_native.linux.template_release.x86_64.so"
linux.release.x86_32 = "res://webrtc/lib/libwebrtc_native.linux.template_release.x86_32.so"
linux.release.arm64 = "res://webrtc/lib/libwebrtc_native.linux.template_release.arm64.so"
linux.release.arm32 = "res://webrtc/lib/libwebrtc_native.linux.template_release.arm32.so"
macos.release = "res://webrtc/lib/libwebrtc_native.macos.template_release.universal.dylib"
windows.release.x86_64 = "res://webrtc/lib/libwebrtc_native.windows.template_release.x86_64.dll"
windows.release.x86_32 = "res://webrtc/lib/libwebrtc_native.windows.template_release.x86_32.dll"
android.release.arm64 = "res://webrtc/lib/libwebrtc_native.android.template_release.arm64.so"
android.release.x86_64 = "res://webrtc/lib/libwebrtc_native.android.template_release.x86_64.so"
ios.release.arm64 = "res://webrtc/lib/libwebrtc_native.ios.template_release.arm64.dylib"
ios.release.x86_64 = "res://webrtc/lib/libwebrtc_native.ios.template_release.x86_64.simulator.dylib"

17
misc/webrtc.tres Normal file
View File

@@ -0,0 +1,17 @@
[gd_resource type="GDNativeLibrary" format=2]
[resource]
singleton = true
reloadable = false
entry/OSX.64 = "res://{GDNATIVE_PATH}/lib/libwebrtc_native.macos.{TARGET}.universal.dylib"
entry/Windows.64 = "res://{GDNATIVE_PATH}/lib/libwebrtc_native.windows.{TARGET}.x86_64.dll"
entry/Windows.32 = "res://{GDNATIVE_PATH}/lib/libwebrtc_native.windows.{TARGET}.x86_32.dll"
entry/X11.64 = "res://{GDNATIVE_PATH}/lib/libwebrtc_native.linux.{TARGET}.x86_64.so"
entry/X11.32 = "res://{GDNATIVE_PATH}/lib/libwebrtc_native.linux.{TARGET}.x86_32.so"
entry/Server.64 = "res://{GDNATIVE_PATH}/lib/libwebrtc_native.linux.{TARGET}.x86_64.so"
entry/Server.32 = "res://{GDNATIVE_PATH}/lib/libwebrtc_native.linux.{TARGET}.x86_32.so"
entry/Android.arm64-v8a = "res://{GDNATIVE_PATH}/lib/libwebrtc_native.android.{TARGET}.arm64.so"
entry/Android.x64 = "res://{GDNATIVE_PATH}/lib/libwebrtc_native.android.{TARGET}.x86_64.so"
entry/iOS.armv7 = "res://{GDNATIVE_PATH}/lib/libwebrtc_native.ios.{TARGET}.armv32.dylib"
entry/iOS.arm64 = "res://{GDNATIVE_PATH}/lib/libwebrtc_native.ios.{TARGET}.arm64.dylib"
entry/iOS.x86_64 = "res://{GDNATIVE_PATH}/lib/libwebrtc_native.ios.{TARGET}.x86_64.simulator.dylib"

View File

@@ -1,133 +1,184 @@
/**************************************************************************/
/* WebRTCLibDataChannel.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "WebRTCLibDataChannel.hpp"
#ifdef GDNATIVE_WEBRTC
#include "GDNativeLibrary.hpp"
#include "NativeScript.hpp"
#define ERR_UNAVAILABLE Error::ERR_UNAVAILABLE
#define FAILED Error::FAILED
#define ERR_INVALID_PARAMETER Error::ERR_INVALID_PARAMETER
#define OK Error::OK
#endif
#include <stdio.h>
#include <string.h>
#include <cstring>
using namespace godot;
using namespace godot_webrtc;
// Channel observer
WebRTCLibDataChannel::ChannelObserver::ChannelObserver(WebRTCLibDataChannel *parent) {
this->parent = parent;
}
void WebRTCLibDataChannel::ChannelObserver::OnMessage(const webrtc::DataBuffer &buffer) {
parent->queue_packet(buffer.data.data<uint8_t>(), buffer.data.size());
}
void WebRTCLibDataChannel::ChannelObserver::OnStateChange() {
}
void WebRTCLibDataChannel::ChannelObserver::OnBufferedAmountChange(uint64_t previous_amount) {
}
// DataChannel
WebRTCLibDataChannel *WebRTCLibDataChannel::new_data_channel(rtc::scoped_refptr<webrtc::DataChannelInterface> p_channel) {
WebRTCLibDataChannel *WebRTCLibDataChannel::new_data_channel(std::shared_ptr<rtc::DataChannel> p_channel, bool p_negotiated) {
// Invalid channel result in NULL return
ERR_FAIL_COND_V(p_channel.get() == nullptr, NULL);
ERR_FAIL_COND_V(!p_channel, nullptr);
#ifdef GDNATIVE_WEBRTC
// Instance a WebRTCDataChannelGDNative object
godot::WebRTCDataChannelGDNative *out = godot::WebRTCDataChannelGDNative::_new();
// Set our implementation as it's script
godot::NativeScript *script = godot::NativeScript::_new();
script->set_library(godot::detail::get_wrapper<godot::GDNativeLibrary>((godot_object *)godot::gdnlib));
WebRTCDataChannelGDNative *native = WebRTCDataChannelGDNative::_new();
// Set our implementation as its script
NativeScript *script = NativeScript::_new();
script->set_library(detail::get_wrapper<GDNativeLibrary>((godot_object *)gdnlib));
script->set_class_name("WebRTCLibDataChannel");
out->set_script(script);
// Bind the data channel to the ScriptInstance userdata (our script)
WebRTCLibDataChannel *tmp = out->cast_to<WebRTCLibDataChannel>(out);
tmp->bind_channel(p_channel);
return tmp;
native->set_script(script);
WebRTCLibDataChannel *out = native->cast_to<WebRTCLibDataChannel>(native);
#else
WebRTCLibDataChannel *out = memnew(WebRTCLibDataChannel);
#endif
// Bind the library data channel to our object.
out->bind_channel(p_channel, p_negotiated);
return out;
}
void WebRTCLibDataChannel::bind_channel(rtc::scoped_refptr<webrtc::DataChannelInterface> p_channel) {
ERR_FAIL_COND(p_channel.get() == nullptr);
void WebRTCLibDataChannel::bind_channel(std::shared_ptr<rtc::DataChannel> p_channel, bool p_negotiated) {
ERR_FAIL_COND(!p_channel);
channel = p_channel;
label = p_channel->label();
protocol = p_channel->protocol();
channel->RegisterObserver(&observer);
negotiated = p_negotiated;
// Binding this should be fine as long as we call close when going out of scope.
p_channel->onMessage([this](auto message) {
if (std::holds_alternative<rtc::string>(message)) {
rtc::string str = std::get<rtc::string>(message);
queue_packet(reinterpret_cast<const uint8_t *>(str.c_str()), str.size(), true);
} else if (std::holds_alternative<rtc::binary>(message)) {
rtc::binary bin = std::get<rtc::binary>(message);
queue_packet(reinterpret_cast<const uint8_t *>(&bin[0]), bin.size(), false);
} else {
ERR_PRINT("Message parsing bug. Unknown message type.");
}
});
p_channel->onOpen([this]() {
channel_state = STATE_OPEN;
});
p_channel->onClosed([this]() {
channel_state = STATE_CLOSED;
});
p_channel->onError([](auto error) {
ERR_PRINT("Channel Error: " + String(std::string(error).c_str()));
});
}
void WebRTCLibDataChannel::queue_packet(const uint8_t *data, uint32_t size) {
void WebRTCLibDataChannel::queue_packet(const uint8_t *data, uint32_t size, bool p_is_string) {
mutex->lock();
godot::PoolByteArray packet;
std::vector<uint8_t> packet;
packet.resize(size);
{
godot::PoolByteArray::Write w = packet.write();
memcpy(w.ptr(), data, size);
}
packet_queue.push(packet);
memcpy(&packet[0], data, size);
packet_queue.push(QueuedPacket(packet, p_is_string));
mutex->unlock();
}
void WebRTCLibDataChannel::set_write_mode(godot_int mode) {
void WebRTCLibDataChannel::_set_write_mode(WriteMode p_mode) {
ERR_FAIL_COND(p_mode != WRITE_MODE_TEXT && p_mode != WRITE_MODE_BINARY);
write_mode = p_mode;
}
godot_int WebRTCLibDataChannel::get_write_mode() const {
return 0;
WebRTCDataChannel::WriteMode WebRTCLibDataChannel::_get_write_mode() const {
return write_mode;
}
bool WebRTCLibDataChannel::was_string_packet() const {
return false;
bool WebRTCLibDataChannel::_was_string_packet() const {
return current_packet.second;
}
WebRTCLibDataChannel::ChannelState WebRTCLibDataChannel::get_ready_state() const {
ERR_FAIL_COND_V(channel.get() == nullptr, STATE_CLOSED);
return (ChannelState)channel->state();
WebRTCDataChannel::ChannelState WebRTCLibDataChannel::_get_ready_state() const {
ERR_FAIL_COND_V(!channel, STATE_CLOSED);
return channel_state;
}
const char *WebRTCLibDataChannel::get_label() const {
ERR_FAIL_COND_V(channel.get() == nullptr, "");
return label.c_str();
String WebRTCLibDataChannel::_get_label() const {
ERR_FAIL_COND_V(!channel, "");
return channel->label().c_str();
}
bool WebRTCLibDataChannel::is_ordered() const {
ERR_FAIL_COND_V(channel.get() == nullptr, false);
return channel->ordered();
bool WebRTCLibDataChannel::_is_ordered() const {
ERR_FAIL_COND_V(!channel, false);
return channel->reliability().unordered == false;
}
int WebRTCLibDataChannel::get_id() const {
ERR_FAIL_COND_V(channel.get() == nullptr, -1);
return channel->id();
int32_t WebRTCLibDataChannel::_get_id() const {
ERR_FAIL_COND_V(!channel, -1);
return channel->id().value_or(-1);
}
int WebRTCLibDataChannel::get_max_packet_life_time() const {
ERR_FAIL_COND_V(channel.get() == nullptr, 0);
return channel->maxRetransmitTime();
int32_t WebRTCLibDataChannel::_get_max_packet_life_time() const {
ERR_FAIL_COND_V(!channel, 0);
return channel->reliability().type == rtc::Reliability::Type::Timed ? std::get<std::chrono::milliseconds>(channel->reliability().rexmit).count() : -1;
}
int WebRTCLibDataChannel::get_max_retransmits() const {
ERR_FAIL_COND_V(channel.get() == nullptr, 0);
return channel->maxRetransmits();
int32_t WebRTCLibDataChannel::_get_max_retransmits() const {
ERR_FAIL_COND_V(!channel, 0);
return channel->reliability().type == rtc::Reliability::Type::Rexmit ? std::get<int>(channel->reliability().rexmit) : -1;
}
const char *WebRTCLibDataChannel::get_protocol() const {
ERR_FAIL_COND_V(channel.get() == nullptr, "");
return protocol.c_str();
String WebRTCLibDataChannel::_get_protocol() const {
ERR_FAIL_COND_V(!channel, "");
return channel->protocol().c_str();
}
bool WebRTCLibDataChannel::is_negotiated() const {
ERR_FAIL_COND_V(channel.get() == nullptr, false);
return channel->negotiated();
bool WebRTCLibDataChannel::_is_negotiated() const {
ERR_FAIL_COND_V(!channel, false);
return negotiated;
}
godot_error WebRTCLibDataChannel::poll() {
return GODOT_OK;
int32_t WebRTCLibDataChannel::_get_buffered_amount() const {
ERR_FAIL_COND_V(!channel, 0);
return channel->bufferedAmount();
}
void WebRTCLibDataChannel::close() {
if(channel.get() != nullptr) {
channel->Close();
channel->UnregisterObserver();
Error WebRTCLibDataChannel::_poll() {
return OK;
}
void WebRTCLibDataChannel::_close() try {
if (channel) {
channel->close();
}
} catch (...) {
}
godot_error WebRTCLibDataChannel::get_packet(const uint8_t **r_buffer, int *r_len) {
ERR_FAIL_COND_V(packet_queue.empty(), GODOT_ERR_UNAVAILABLE);
Error WebRTCLibDataChannel::_get_packet(const uint8_t **r_buffer, int32_t *r_len) {
ERR_FAIL_COND_V(packet_queue.empty(), ERR_UNAVAILABLE);
mutex->lock();
@@ -135,46 +186,46 @@ godot_error WebRTCLibDataChannel::get_packet(const uint8_t **r_buffer, int *r_le
current_packet = packet_queue.front();
packet_queue.pop();
// Set out buffer and size (buffer will be gone at next get_packet or close)
*r_buffer = current_packet.read().ptr();
*r_len = current_packet.size();
*r_buffer = &current_packet.first[0];
*r_len = current_packet.first.size();
mutex->unlock();
return GODOT_OK;
return OK;
}
godot_error WebRTCLibDataChannel::put_packet(const uint8_t *p_buffer, int p_len) {
ERR_FAIL_COND_V(channel.get() == nullptr, GODOT_ERR_UNAVAILABLE);
webrtc::DataBuffer webrtc_buffer(rtc::CopyOnWriteBuffer(p_buffer, p_len), true);
ERR_FAIL_COND_V(!channel->Send(webrtc_buffer), GODOT_FAILED);
return GODOT_OK;
Error WebRTCLibDataChannel::_put_packet(const uint8_t *p_buffer, int32_t p_len) try {
ERR_FAIL_COND_V(!channel, FAILED);
ERR_FAIL_COND_V(channel->isClosed(), FAILED);
if (write_mode == WRITE_MODE_TEXT) {
std::string str(p_len, '\x00');
std::strncpy(str.data(), (const char *)p_buffer, p_len);
channel->send(str);
} else if (write_mode == WRITE_MODE_BINARY) {
channel->send(reinterpret_cast<const std::byte *>(p_buffer), p_len);
} else {
ERR_FAIL_V(ERR_INVALID_PARAMETER);
}
return OK;
} catch (const std::exception &e) {
ERR_PRINT(e.what());
ERR_FAIL_V(FAILED);
}
godot_int WebRTCLibDataChannel::get_available_packet_count() const {
int32_t WebRTCLibDataChannel::_get_available_packet_count() const {
return packet_queue.size();
}
godot_int WebRTCLibDataChannel::get_max_packet_size() const {
return 1200;
int32_t WebRTCLibDataChannel::_get_max_packet_size() const {
return 16384; // See RFC-8831 section 6.6: https://datatracker.ietf.org/doc/rfc8831/
}
void WebRTCLibDataChannel::_register_methods() {
}
void WebRTCLibDataChannel::_init() {
register_interface(&interface);
}
WebRTCLibDataChannel::WebRTCLibDataChannel() : observer(this) {
WebRTCLibDataChannel::WebRTCLibDataChannel() {
mutex = new std::mutex;
}
WebRTCLibDataChannel::~WebRTCLibDataChannel() {
close();
if (_owner) {
register_interface(NULL);
}
_close();
channel = nullptr;
delete mutex;
}

View File

@@ -1,71 +1,105 @@
/**************************************************************************/
/* WebRTCLibDataChannel.hpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef WEBRTC_DATA_CHANNEL_H
#define WEBRTC_DATA_CHANNEL_H
#ifdef GDNATIVE_WEBRTC
#include <Godot.hpp> // Godot.hpp must go first, or windows builds breaks
#include "api/peer_connection_interface.h" // interface for all things needed from WebRTC
#include "media/base/media_engine.h" // needed for CreateModularPeerConnectionFactory
#include "net/WebRTCDataChannelNative.hpp"
#include "PoolArrays.hpp"
#define WebRTCDataChannelExtension WebRTCDataChannelNative
#if !defined(GDCLASS)
#define GDCLASS(arg1, arg2) GODOT_CLASS(arg1, arg2)
#endif
#else
#include <godot_cpp/core/binder_common.hpp>
#include <godot_cpp/classes/global_constants_binds.hpp>
#include <godot_cpp/classes/web_rtc_data_channel_extension.hpp>
#endif
#include <mutex>
#include <queue>
#include <utility>
#include "rtc/rtc.hpp"
namespace godot_webrtc {
class WebRTCLibDataChannel : public WebRTCDataChannelNative {
GODOT_CLASS(WebRTCLibDataChannel, WebRTCDataChannelNative);
class WebRTCLibDataChannel : public godot::WebRTCDataChannelExtension {
GDCLASS(WebRTCLibDataChannel, WebRTCDataChannelExtension);
private:
class ChannelObserver : public webrtc::DataChannelObserver {
public:
WebRTCLibDataChannel *parent;
ChannelObserver(WebRTCLibDataChannel *parent);
void OnMessage(const webrtc::DataBuffer &buffer) override;
void OnStateChange() override; // UNUSED
void OnBufferedAmountChange(uint64_t previous_amount) override; // UNUSED
};
ChannelObserver observer;
rtc::scoped_refptr<webrtc::DataChannelInterface> channel;
using QueuedPacket = std::pair<std::vector<uint8_t>, bool>;
std::mutex *mutex;
std::queue<godot::PoolByteArray> packet_queue;
godot::PoolByteArray current_packet;
std::string label;
std::string protocol;
std::queue<QueuedPacket> packet_queue;
QueuedPacket current_packet;
std::shared_ptr<rtc::DataChannel> channel = nullptr;
WriteMode write_mode = WRITE_MODE_BINARY;
ChannelState channel_state = STATE_CONNECTING;
bool negotiated = false;
void queue_packet(const uint8_t *data, uint32_t size, bool p_is_string);
void bind_channel(std::shared_ptr<rtc::DataChannel> p_channel, bool p_negotiated);
protected:
static void _bind_methods() {}
public:
static WebRTCLibDataChannel *new_data_channel(rtc::scoped_refptr<webrtc::DataChannelInterface> p_channel);
static void _register_methods();
void _init();
void bind_channel(rtc::scoped_refptr<webrtc::DataChannelInterface> p_channel);
void queue_packet(const uint8_t *data, uint32_t size);
/* WebRTCDataChannel */
void set_write_mode(godot_int mode);
godot_int get_write_mode() const;
bool was_string_packet() const;
ChannelState get_ready_state() const;
const char *get_label() const;
bool is_ordered() const;
int get_id() const;
int get_max_packet_life_time() const;
int get_max_retransmits() const;
const char *get_protocol() const;
bool is_negotiated() const;
godot_error poll();
void close();
static WebRTCLibDataChannel *new_data_channel(std::shared_ptr<rtc::DataChannel> p_channel, bool p_negotiated);
/* PacketPeer */
virtual godot_error get_packet(const uint8_t **r_buffer, int *r_len);
virtual godot_error put_packet(const uint8_t *p_buffer, int p_len);
virtual godot_int get_available_packet_count() const;
virtual godot_int get_max_packet_size() const;
virtual godot::Error _get_packet(const uint8_t **r_buffer, int32_t *r_len) override;
virtual godot::Error _put_packet(const uint8_t *p_buffer, int32_t p_len) override;
virtual int32_t _get_available_packet_count() const override;
virtual int32_t _get_max_packet_size() const override;
/* WebRTCDataChannel */
godot::Error _poll() override;
void _close() override;
void _set_write_mode(WriteMode p_mode) override;
WriteMode _get_write_mode() const override;
bool _was_string_packet() const override;
ChannelState _get_ready_state() const override;
godot::String _get_label() const override;
bool _is_ordered() const override;
int32_t _get_id() const override;
int32_t _get_max_packet_life_time() const override;
int32_t _get_max_retransmits() const override;
godot::String _get_protocol() const override;
bool _is_negotiated() const override;
int32_t _get_buffered_amount() const override;
WebRTCLibDataChannel();
~WebRTCLibDataChannel();

View File

@@ -1,207 +1,259 @@
#include "WebRTCDataChannel.hpp"
#include "WebRTCDataChannelGDNative.hpp"
/**************************************************************************/
/* WebRTCLibPeerConnection.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 "WebRTCLibPeerConnection.hpp"
#include "WebRTCLibDataChannel.hpp"
using namespace godot;
using namespace godot_webrtc;
std::unique_ptr<rtc::Thread> WebRTCLibPeerConnection::signaling_thread = nullptr;
// PeerConnectionObserver
void WebRTCLibPeerConnection::GodotPCO::OnIceCandidate(const webrtc::IceCandidateInterface *candidate) {
godot::Dictionary candidateSDP;
godot::String candidateSdpMidName = candidate->sdp_mid().c_str();
int candidateSdpMlineIndexName = candidate->sdp_mline_index();
std::string sdp;
candidate->ToString(&sdp);
godot::String candidateSdpName = sdp.c_str();
parent->queue_signal("ice_candidate_created", 3, candidateSdpMidName, candidateSdpMlineIndexName, candidateSdpName);
}
// SetSessionDescriptionObserver
void WebRTCLibPeerConnection::GodotSSDO::OnSuccess() {
if (make_offer) {
make_offer = false;
parent->peer_connection->CreateAnswer(parent->ptr_csdo, webrtc::PeerConnectionInterface::RTCOfferAnswerOptions());
}
}
// CreateSessionDescriptionObserver
void WebRTCLibPeerConnection::GodotCSDO::OnSuccess(webrtc::SessionDescriptionInterface *desc) {
// serialize this offer and send it to the remote peer:
std::string sdp;
desc->ToString(&sdp);
parent->queue_signal("session_description_created", 2, desc->type().c_str(), sdp.c_str());
}
#ifdef GDNATIVE_WEBRTC
#define OK Error::OK
#define FAILED Error::FAILED
#define ERR_UNCONFIGURED Error::ERR_UNCONFIGURED
#define ERR_INVALID_PARAMETER Error::ERR_INVALID_PARAMETER
#endif
void WebRTCLibPeerConnection::initialize_signaling() {
if (signaling_thread.get() == nullptr) {
signaling_thread = rtc::Thread::Create();
}
signaling_thread->Start();
#ifdef DEBUG_ENABLED
rtc::InitLogger(rtc::LogLevel::Debug);
#endif
}
void WebRTCLibPeerConnection::deinitialize_signaling() {
if (signaling_thread.get() != nullptr) {
signaling_thread->Stop();
}
}
godot_error _parse_ice_server(webrtc::PeerConnectionInterface::RTCConfiguration &r_config, godot::Dictionary p_server) {
godot::Variant v;
webrtc::PeerConnectionInterface::IceServer ice_server;
godot::String url;
ERR_FAIL_COND_V(!p_server.has("urls"), GODOT_ERR_INVALID_PARAMETER);
Error WebRTCLibPeerConnection::_parse_ice_server(rtc::Configuration &r_config, Dictionary p_server) {
ERR_FAIL_COND_V(!p_server.has("urls"), ERR_INVALID_PARAMETER);
// Parse mandatory URL
v = p_server["urls"];
if (v.get_type() == godot::Variant::STRING) {
url = v;
ice_server.urls.push_back(url.utf8().get_data());
} else if (v.get_type() == godot::Variant::ARRAY) {
godot::Array names = v;
for (int j = 0; j < names.size(); j++) {
v = names[j];
ERR_FAIL_COND_V(v.get_type() != godot::Variant::STRING, GODOT_ERR_INVALID_PARAMETER);
url = v;
ice_server.urls.push_back(url.utf8().get_data());
}
Array urls;
Variant urls_var = p_server["urls"];
if (urls_var.get_type() == Variant::STRING) {
urls.push_back(urls_var);
} else if (urls_var.get_type() == Variant::ARRAY) {
urls = urls_var;
} else {
ERR_FAIL_V(GODOT_ERR_INVALID_PARAMETER);
ERR_FAIL_V(ERR_INVALID_PARAMETER);
}
// Parse credentials (only meaningful for TURN, only support password)
if (p_server.has("username") && (v = p_server["username"]) && v.get_type() == godot::Variant::STRING) {
ice_server.username = (v.operator godot::String()).utf8().get_data();
String username;
String credential;
if (p_server.has("username") && p_server["username"].get_type() == Variant::STRING) {
username = p_server["username"];
}
if (p_server.has("credential") && (v = p_server["credential"]) && v.get_type() == godot::Variant::STRING) {
ice_server.password = (v.operator godot::String()).utf8().get_data();
if (p_server.has("credential") && p_server["credential"].get_type() == Variant::STRING) {
credential = p_server["credential"];
}
r_config.servers.push_back(ice_server);
return GODOT_OK;
for (int i = 0; i < urls.size(); i++) {
rtc::IceServer srv(urls[i].operator String().utf8().get_data());
srv.username = username.utf8().get_data();
srv.password = credential.utf8().get_data();
r_config.iceServers.push_back(srv);
}
return OK;
}
godot_error _parse_channel_config(webrtc::DataChannelInit &r_config, godot::Dictionary p_dict) {
godot::Variant v;
#define _SET_N(PROP, PNAME, TYPE) if (p_dict.has(#PROP)) { v = p_dict[#PROP]; if(v.get_type() == godot::Variant::TYPE) r_config.PNAME = v; }
#define _SET(PROP, TYPE) _SET_N(PROP, PROP, TYPE)
_SET(negotiated, BOOL);
_SET(id, INT);
_SET_N(maxPacketLifeTime, maxRetransmitTime, INT);
_SET(maxRetransmits, INT);
_SET(ordered, BOOL);
#undef _SET
if (p_dict.has("protocol") && (v = p_dict["protocol"]) && v.get_type() == godot::Variant::STRING) {
r_config.protocol = v.operator godot::String().utf8().get_data();
Error WebRTCLibPeerConnection::_parse_channel_config(rtc::DataChannelInit &r_config, const Dictionary &p_dict) {
Variant nil;
Variant v;
if (p_dict.has("negotiated")) {
r_config.negotiated = p_dict["negotiated"].operator bool();
}
// ID makes sense only when negotiated is true (and must be set in that case)
ERR_FAIL_COND_V(r_config.negotiated ? r_config.id == -1 : r_config.id != -1, GODOT_ERR_INVALID_PARAMETER);
// Only one of maxRetransmits and maxRetransmitTime can be set on a channel.
ERR_FAIL_COND_V(r_config.maxRetransmits && r_config.maxRetransmitTime, GODOT_ERR_INVALID_PARAMETER);
return GODOT_OK;
if (p_dict.has("id")) {
r_config.id = uint16_t(p_dict["id"].operator int32_t());
}
// If negotiated it must have an ID, and ID only makes sense when negotiated.
ERR_FAIL_COND_V(r_config.negotiated != r_config.id.has_value(), ERR_INVALID_PARAMETER);
// Channels cannot be both time-constrained and retry-constrained.
ERR_FAIL_COND_V(p_dict.has("maxPacketLifeTime") && p_dict.has("maxRetransmits"), ERR_INVALID_PARAMETER);
if (p_dict.has("maxPacketLifeTime")) {
r_config.reliability.type = rtc::Reliability::Type::Timed;
r_config.reliability.rexmit = std::chrono::milliseconds(p_dict["maxPacketLifeTime"].operator int32_t());
} else if (p_dict.has("maxRetransmits")) {
r_config.reliability.type = rtc::Reliability::Type::Rexmit;
r_config.reliability.rexmit = p_dict["maxRetransmits"].operator int32_t();
}
if (p_dict.has("ordered") && p_dict["ordered"].operator bool() == false) {
r_config.reliability.unordered = true;
}
if (p_dict.has("protocol")) {
r_config.protocol = p_dict["protocol"].operator String().utf8().get_data();
}
return OK;
}
WebRTCLibPeerConnection::ConnectionState WebRTCLibPeerConnection::get_connection_state() const {
ERR_FAIL_COND_V(peer_connection.get() == nullptr, STATE_CLOSED);
WebRTCPeerConnection::ConnectionState WebRTCLibPeerConnection::_get_connection_state() const {
ERR_FAIL_COND_V(peer_connection == nullptr, STATE_CLOSED);
webrtc::PeerConnectionInterface::IceConnectionState state = peer_connection->ice_connection_state();
switch(state) {
case webrtc::PeerConnectionInterface::kIceConnectionNew:
rtc::PeerConnection::State state = peer_connection->state();
switch (state) {
case rtc::PeerConnection::State::New:
return STATE_NEW;
case webrtc::PeerConnectionInterface::kIceConnectionChecking:
case rtc::PeerConnection::State::Connecting:
return STATE_CONNECTING;
case webrtc::PeerConnectionInterface::kIceConnectionConnected:
case rtc::PeerConnection::State::Connected:
return STATE_CONNECTED;
case webrtc::PeerConnectionInterface::kIceConnectionCompleted:
return STATE_CONNECTED;
case webrtc::PeerConnectionInterface::kIceConnectionFailed:
return STATE_FAILED;
case webrtc::PeerConnectionInterface::kIceConnectionDisconnected:
case rtc::PeerConnection::State::Disconnected:
return STATE_DISCONNECTED;
case webrtc::PeerConnectionInterface::kIceConnectionClosed:
return STATE_CLOSED;
case rtc::PeerConnection::State::Failed:
return STATE_FAILED;
default:
return STATE_CLOSED;
}
}
godot_error WebRTCLibPeerConnection::initialize(const godot_dictionary *p_config) {
webrtc::PeerConnectionInterface::RTCConfiguration config;
godot::Dictionary d = *(godot::Dictionary *)p_config;
godot::Variant v;
if (d.has("iceServers") && (v = d["iceServers"]) && v.get_type() == godot::Variant::ARRAY) {
godot::Array servers = v;
WebRTCLibPeerConnection::GatheringState WebRTCLibPeerConnection::_get_gathering_state() const {
ERR_FAIL_COND_V(peer_connection == nullptr, GATHERING_STATE_NEW);
rtc::PeerConnection::GatheringState state = peer_connection->gatheringState();
switch (state) {
case rtc::PeerConnection::GatheringState::New:
return GATHERING_STATE_NEW;
case rtc::PeerConnection::GatheringState::InProgress:
return GATHERING_STATE_GATHERING;
case rtc::PeerConnection::GatheringState::Complete:
return GATHERING_STATE_COMPLETE;
default:
return GATHERING_STATE_NEW;
}
}
WebRTCLibPeerConnection::SignalingState WebRTCLibPeerConnection::_get_signaling_state() const {
ERR_FAIL_COND_V(peer_connection == nullptr, SIGNALING_STATE_CLOSED);
rtc::PeerConnection::SignalingState state = peer_connection->signalingState();
switch (state) {
case rtc::PeerConnection::SignalingState::Stable:
return SIGNALING_STATE_STABLE;
case rtc::PeerConnection::SignalingState::HaveLocalOffer:
return SIGNALING_STATE_HAVE_LOCAL_OFFER;
case rtc::PeerConnection::SignalingState::HaveRemoteOffer:
return SIGNALING_STATE_HAVE_REMOTE_OFFER;
case rtc::PeerConnection::SignalingState::HaveLocalPranswer:
return SIGNALING_STATE_HAVE_LOCAL_PRANSWER;
case rtc::PeerConnection::SignalingState::HaveRemotePranswer:
return SIGNALING_STATE_HAVE_REMOTE_PRANSWER;
default:
return SIGNALING_STATE_CLOSED;
}
}
Error WebRTCLibPeerConnection::_initialize(const Dictionary &p_config) {
rtc::Configuration config = {};
if (p_config.has("iceServers") && p_config["iceServers"].get_type() == Variant::ARRAY) {
Array servers = p_config["iceServers"];
for (int i = 0; i < servers.size(); i++) {
v = servers[i];
ERR_FAIL_COND_V(v.get_type() != godot::Variant::DICTIONARY, GODOT_ERR_INVALID_PARAMETER);
godot_error err;
godot::Dictionary server = v;
err = _parse_ice_server(config, server);
ERR_FAIL_COND_V(err != GODOT_OK, err);
ERR_FAIL_COND_V(servers[i].get_type() != Variant::DICTIONARY, ERR_INVALID_PARAMETER);
Dictionary server = servers[i];
Error err = _parse_ice_server(config, server);
ERR_FAIL_COND_V(err != OK, FAILED);
}
}
return _create_pc(config);
}
godot_object *WebRTCLibPeerConnection::create_data_channel(const char *p_channel, const godot_dictionary *p_channel_config) {
ERR_FAIL_COND_V(peer_connection.get() == nullptr, NULL);
#if defined(GDNATIVE_WEBRTC) || defined(GDEXTENSION_WEBRTC_40)
Object *WebRTCLibPeerConnection::_create_data_channel(const String &p_channel, const Dictionary &p_channel_config) try {
#else
Ref<WebRTCDataChannel> WebRTCLibPeerConnection::_create_data_channel(const String &p_channel, const Dictionary &p_channel_config) try {
#endif
ERR_FAIL_COND_V(!peer_connection, nullptr);
// Read config from dictionary
webrtc::DataChannelInit config;
godot::Dictionary d = *(godot::Dictionary *)p_channel_config;
godot_error err = _parse_channel_config(config, d);
ERR_FAIL_COND_V(err != GODOT_OK, NULL);
rtc::DataChannelInit config;
WebRTCLibDataChannel *wrapper = WebRTCLibDataChannel::new_data_channel(peer_connection->CreateDataChannel(p_channel, &config));
ERR_FAIL_COND_V(wrapper == NULL, NULL);
return wrapper->_owner;
Error err = _parse_channel_config(config, p_channel_config);
ERR_FAIL_COND_V(err != OK, nullptr);
std::shared_ptr<rtc::DataChannel> ch = peer_connection->createDataChannel(p_channel.utf8().get_data(), config);
ERR_FAIL_COND_V(ch == nullptr, nullptr);
WebRTCLibDataChannel *wrapper = WebRTCLibDataChannel::new_data_channel(ch, ch->id().has_value());
ERR_FAIL_COND_V(wrapper == nullptr, nullptr);
return wrapper;
} catch (const std::exception &e) {
ERR_PRINT(e.what());
ERR_FAIL_V(nullptr);
}
godot_error WebRTCLibPeerConnection::create_offer() {
ERR_FAIL_COND_V(peer_connection.get() == nullptr, GODOT_ERR_UNCONFIGURED);
peer_connection->CreateOffer(ptr_csdo, webrtc::PeerConnectionInterface::RTCOfferAnswerOptions());
return GODOT_OK;
Error WebRTCLibPeerConnection::_create_offer() try {
ERR_FAIL_COND_V(!peer_connection, ERR_UNCONFIGURED);
ERR_FAIL_COND_V(_get_connection_state() != STATE_NEW, FAILED);
peer_connection->setLocalDescription(rtc::Description::Type::Offer);
return OK;
} catch (const std::exception &e) {
ERR_PRINT(e.what());
ERR_FAIL_V(FAILED);
}
#define _MAKE_DESC(TYPE, SDP) webrtc::CreateSessionDescription((godot::String(TYPE) == godot::String("offer") ? webrtc::SdpType::kOffer : webrtc::SdpType::kAnswer), SDP)
godot_error WebRTCLibPeerConnection::set_remote_description(const char *type, const char *sdp) {
ERR_FAIL_COND_V(peer_connection.get() == nullptr, GODOT_ERR_UNCONFIGURED);
std::unique_ptr<webrtc::SessionDescriptionInterface> desc = _MAKE_DESC(type, sdp);
if (desc->GetType() == webrtc::SdpType::kOffer) {
ptr_ssdo->make_offer = true;
Error WebRTCLibPeerConnection::_set_remote_description(const String &p_type, const String &p_sdp) try {
ERR_FAIL_COND_V(!peer_connection, ERR_UNCONFIGURED);
std::string sdp(p_sdp.utf8().get_data());
std::string type(p_type.utf8().get_data());
rtc::Description desc(sdp, type);
peer_connection->setRemoteDescription(desc);
// Automatically create the answer.
if (p_type == String("offer")) {
peer_connection->setLocalDescription(rtc::Description::Type::Answer);
}
peer_connection->SetRemoteDescription(ptr_ssdo, desc.release());
return GODOT_OK;
return OK;
} catch (const std::exception &e) {
ERR_PRINT(e.what());
ERR_FAIL_V(FAILED);
}
godot_error WebRTCLibPeerConnection::set_local_description(const char *type, const char *sdp) {
ERR_FAIL_COND_V(peer_connection.get() == nullptr, GODOT_ERR_UNCONFIGURED);
std::unique_ptr<webrtc::SessionDescriptionInterface> desc = _MAKE_DESC(type, sdp);
peer_connection->SetLocalDescription(ptr_ssdo, desc.release());
return GODOT_OK;
}
#undef _MAKE_DESC
godot_error WebRTCLibPeerConnection::add_ice_candidate(const char *sdpMidName, int sdpMlineIndexName, const char *sdpName) {
ERR_FAIL_COND_V(peer_connection.get() == nullptr, GODOT_ERR_UNCONFIGURED);
webrtc::SdpParseError *error = nullptr;
webrtc::IceCandidateInterface *candidate = webrtc::CreateIceCandidate(
sdpMidName,
sdpMlineIndexName,
sdpName,
error);
ERR_FAIL_COND_V(error || !candidate, GODOT_ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V(!peer_connection->AddIceCandidate(candidate), GODOT_FAILED);
return GODOT_OK;
Error WebRTCLibPeerConnection::_set_local_description(const String &p_type, const String &p_sdp) {
ERR_FAIL_COND_V(!peer_connection, ERR_UNCONFIGURED);
// XXX Library quirk. It doesn't seem possible to create offers/answers without setting the local description.
// Ignore this call for now to avoid crash (it's already set automatically!).
// peer_connection->setLocalDescription(p_type == String("offer") ? rtc::Description::Type::Offer : rtc::Description::Type::Answer);
return OK;
}
godot_error WebRTCLibPeerConnection::poll() {
ERR_FAIL_COND_V(peer_connection.get() == nullptr, GODOT_ERR_UNCONFIGURED);
#ifdef GDNATIVE_WEBRTC
Error WebRTCLibPeerConnection::_add_ice_candidate(const String &sdpMidName, int64_t sdpMlineIndexName, const String &sdpName) try {
#else
Error WebRTCLibPeerConnection::_add_ice_candidate(const String &sdpMidName, int32_t sdpMlineIndexName, const String &sdpName) try {
#endif
ERR_FAIL_COND_V(!peer_connection, ERR_UNCONFIGURED);
rtc::Candidate candidate(sdpName.utf8().get_data(), sdpMidName.utf8().get_data());
peer_connection->addRemoteCandidate(candidate);
return OK;
} catch (const std::exception &e) {
ERR_PRINT(e.what());
ERR_FAIL_V(FAILED);
}
Error WebRTCLibPeerConnection::_poll() {
ERR_FAIL_COND_V(!peer_connection, ERR_UNCONFIGURED);
while (!signal_queue.empty()) {
mutex_signal_queue->lock();
@@ -210,68 +262,83 @@ godot_error WebRTCLibPeerConnection::poll() {
mutex_signal_queue->unlock();
signal.emit(this);
}
return GODOT_OK;
return OK;
}
void WebRTCLibPeerConnection::close() {
if (peer_connection.get() != nullptr) {
peer_connection->Close();
void WebRTCLibPeerConnection::_close() {
if (peer_connection != nullptr) {
try {
peer_connection->close();
} catch (...) {
}
}
peer_connection = nullptr;
while(!signal_queue.empty()) {
while (!signal_queue.empty()) {
signal_queue.pop();
}
}
void WebRTCLibPeerConnection::_register_methods() {
}
void WebRTCLibPeerConnection::_init() {
#ifdef GDNATIVE_WEBRTC
register_interface(&interface);
// initialize variables:
#endif
mutex_signal_queue = new std::mutex;
// create a PeerConnectionFactoryInterface:
webrtc::PeerConnectionFactoryDependencies deps;
ERR_FAIL_COND(signaling_thread.get() == nullptr);
deps.signaling_thread = signaling_thread.get();
pc_factory = webrtc::CreateModularPeerConnectionFactory(std::move(deps));
// Create peer connection with default configuration.
webrtc::PeerConnectionInterface::RTCConfiguration config;
_create_pc(config);
_initialize(Dictionary());
}
godot_error WebRTCLibPeerConnection::_create_pc(webrtc::PeerConnectionInterface::RTCConfiguration &config) {
ERR_FAIL_COND_V(pc_factory.get() == nullptr, GODOT_ERR_BUG);
peer_connection = nullptr;
peer_connection = pc_factory->CreatePeerConnection(config, nullptr, nullptr, &pco);
if (peer_connection.get() == nullptr) { // PeerConnection couldn't be created. Fail the method call.
ERR_PRINT("PeerConnection could not be created");
return GODOT_FAILED;
}
return GODOT_OK;
Error WebRTCLibPeerConnection::_create_pc(rtc::Configuration &r_config) try {
// Prevents libdatachannel from automatically creating offers.
r_config.disableAutoNegotiation = true;
peer_connection = std::make_shared<rtc::PeerConnection>(r_config);
ERR_FAIL_COND_V(!peer_connection, FAILED);
// Binding this should be fine as long as we call close when going out of scope.
peer_connection->onLocalDescription([this](rtc::Description description) {
String type = description.type() == rtc::Description::Type::Offer ? "offer" : "answer";
queue_signal("session_description_created", 2, type, String(std::string(description).c_str()));
});
peer_connection->onLocalCandidate([this](rtc::Candidate candidate) {
queue_signal("ice_candidate_created", 3, String(candidate.mid().c_str()), 0, String(candidate.candidate().c_str()));
});
peer_connection->onDataChannel([this](std::shared_ptr<rtc::DataChannel> channel) {
queue_signal("data_channel_received", 1, WebRTCLibDataChannel::new_data_channel(channel, false));
});
/*
peer_connection->onStateChange([](rtc::PeerConnection::State state) {
std::cout << "[State: " << state << "]" << std::endl;
});
peer_connection->onGatheringStateChange([](rtc::PeerConnection::GatheringState state) {
std::cout << "[Gathering State: " << state << "]" << std::endl;
});
*/
return OK;
} catch (const std::exception &e) {
ERR_PRINT(e.what());
ERR_FAIL_V(FAILED);
}
WebRTCLibPeerConnection::WebRTCLibPeerConnection() :
pco(this),
ptr_csdo(new rtc::RefCountedObject<GodotCSDO>(this)),
ptr_ssdo(new rtc::RefCountedObject<GodotSSDO>(this)) {
WebRTCLibPeerConnection::WebRTCLibPeerConnection() {
#ifndef GDNATIVE_WEBRTC
_init();
#endif
}
WebRTCLibPeerConnection::~WebRTCLibPeerConnection() {
#ifdef GDNATIVE_WEBRTC
if (_owner) {
register_interface(NULL);
register_interface(nullptr);
}
close();
#endif
_close();
delete mutex_signal_queue;
}
void WebRTCLibPeerConnection::queue_signal(godot::String p_name, int p_argc, const godot::Variant &p_arg1, const godot::Variant &p_arg2, const godot::Variant &p_arg3) {
void WebRTCLibPeerConnection::queue_signal(String p_name, int p_argc, const Variant &p_arg1, const Variant &p_arg2, const Variant &p_arg3) {
mutex_signal_queue->lock();
const godot::Variant argv[3] = { p_arg1, p_arg2, p_arg3 };
const Variant argv[3] = { p_arg1, p_arg2, p_arg3 };
signal_queue.push(Signal(p_name, p_argc, argv));
mutex_signal_queue->unlock();
}

View File

@@ -1,102 +1,109 @@
/**************************************************************************/
/* WebRTCLibPeerConnection.hpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef WEBRTC_PEER_H
#define WEBRTC_PEER_H
#ifdef GDNATIVE_WEBRTC
#include <Godot.hpp> // Godot.hpp must go first, or windows builds breaks
#include "api/peer_connection_interface.h" // interface for all things needed from WebRTC
#include "media/base/media_engine.h" // needed for CreateModularPeerConnectionFactory
#include <mutex>
#include "net/WebRTCPeerConnectionNative.hpp"
#define WebRTCPeerConnectionExtension WebRTCPeerConnectionNative
#if !defined(GDCLASS)
#define GDCLASS(arg1, arg2) GODOT_CLASS(arg1, arg2)
#endif
#else
#include <godot_cpp/core/binder_common.hpp>
#include <godot_cpp/classes/global_constants_binds.hpp>
#include <godot_cpp/classes/web_rtc_peer_connection_extension.hpp>
#endif
#include "rtc/rtc.hpp"
#include <mutex>
#include <queue>
namespace godot_webrtc {
class WebRTCLibPeerConnection : public WebRTCPeerConnectionNative {
GODOT_CLASS(WebRTCLibPeerConnection, WebRTCPeerConnectionNative);
class WebRTCLibPeerConnection : public godot::WebRTCPeerConnectionExtension {
GDCLASS(WebRTCLibPeerConnection, WebRTCPeerConnectionExtension);
private:
godot_error _create_pc(webrtc::PeerConnectionInterface::RTCConfiguration &config);
std::shared_ptr<rtc::PeerConnection> peer_connection = nullptr;
godot::Array candidates;
godot::Error _create_pc(rtc::Configuration &r_config);
godot::Error _parse_ice_server(rtc::Configuration &r_config, godot::Dictionary p_server);
godot::Error _parse_channel_config(rtc::DataChannelInit &r_config, const godot::Dictionary &p_dict);
protected:
static void _bind_methods() {}
static std::unique_ptr<rtc::Thread> signaling_thread;
public:
static void _register_methods();
static void _register_methods() {}
static void initialize_signaling();
static void deinitialize_signaling();
void _init();
ConnectionState get_connection_state() const;
ConnectionState _get_connection_state() const override;
GatheringState _get_gathering_state() const override;
SignalingState _get_signaling_state() const override;
godot_error initialize(const godot_dictionary *p_config);
godot_object *create_data_channel(const char *p_channel, const godot_dictionary *p_channel_config);
godot_error create_offer();
godot_error set_remote_description(const char *type, const char *sdp);
godot_error set_local_description(const char *type, const char *sdp);
godot_error add_ice_candidate(const char *sdpMidName, int sdpMlineIndexName, const char *sdpName);
godot_error poll();
void close();
godot::Error _initialize(const godot::Dictionary &p_config) override;
#if defined(GDNATIVE_WEBRTC) || defined(GDEXTENSION_WEBRTC_40)
godot::Object *_create_data_channel(const godot::String &p_channel, const godot::Dictionary &p_channel_config) override;
#else
godot::Ref<godot::WebRTCDataChannel> _create_data_channel(const godot::String &p_channel, const godot::Dictionary &p_channel_config) override;
#endif
godot::Error _create_offer() override;
godot::Error _set_remote_description(const godot::String &type, const godot::String &sdp) override;
godot::Error _set_local_description(const godot::String &type, const godot::String &sdp) override;
#ifdef GDNATIVE_WEBRTC
godot::Error _add_ice_candidate(const godot::String &sdpMidName, int64_t sdpMlineIndexName, const godot::String &sdpName) override;
#else
godot::Error _add_ice_candidate(const godot::String &sdpMidName, int32_t sdpMlineIndexName, const godot::String &sdpName) override;
#endif
godot::Error _poll() override;
void _close() override;
WebRTCLibPeerConnection();
~WebRTCLibPeerConnection();
/* helper functions */
private:
void queue_signal(godot::String p_name, int p_argc, const godot::Variant &p_arg1 = godot::Variant(), const godot::Variant &p_arg2 = godot::Variant(), const godot::Variant &p_arg3 = godot::Variant());
void queue_packet(uint8_t *, int);
/** PeerConnectionObserver callback functions **/
class GodotPCO : public webrtc::PeerConnectionObserver {
public:
WebRTCLibPeerConnection *parent;
GodotPCO(WebRTCLibPeerConnection *p_parent) {
parent = p_parent;
}
void OnIceCandidate(const webrtc::IceCandidateInterface *candidate) override;
void OnSignalingChange(webrtc::PeerConnectionInterface::SignalingState new_state) override {}
void OnAddStream(rtc::scoped_refptr<webrtc::MediaStreamInterface> stream) override {}
void OnRemoveStream(rtc::scoped_refptr<webrtc::MediaStreamInterface> stream) override {}
void OnDataChannel(rtc::scoped_refptr<webrtc::DataChannelInterface> data_channel) override {}
void OnRenegotiationNeeded() override {}
void OnIceConnectionChange(webrtc::PeerConnectionInterface::IceConnectionState new_state) override {}
void OnIceGatheringChange(webrtc::PeerConnectionInterface::IceGatheringState new_state) override {}
};
/** CreateSessionDescriptionObserver callback functions **/
class GodotCSDO : public webrtc::CreateSessionDescriptionObserver {
public:
WebRTCLibPeerConnection *parent = nullptr;
GodotCSDO(WebRTCLibPeerConnection *p_parent) {
parent = p_parent;
}
void OnSuccess(webrtc::SessionDescriptionInterface *desc) override;
void OnFailure(webrtc::RTCError error) override {
ERR_PRINT(godot::String(error.message()));
}
};
/** SetSessionDescriptionObserver callback functions **/
class GodotSSDO : public webrtc::SetSessionDescriptionObserver {
public:
WebRTCLibPeerConnection *parent = nullptr;
bool make_offer = false;
GodotSSDO(WebRTCLibPeerConnection *p_parent) {
parent = p_parent;
}
void OnSuccess() override;
void OnFailure(webrtc::RTCError error) override {
make_offer = false;
ERR_PRINT(godot::String(error.message()));
}
};
class Signal {
godot::String method;
godot::Variant argv[3];
int argc = 0;
public:
Signal(godot::String p_method, int p_argc, const godot::Variant *p_argv) {
method = p_method;
@@ -119,15 +126,10 @@ private:
}
};
GodotPCO pco;
rtc::scoped_refptr<GodotSSDO> ptr_ssdo;
rtc::scoped_refptr<GodotCSDO> ptr_csdo;
std::mutex *mutex_signal_queue = nullptr;
std::queue<Signal> signal_queue;
rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> pc_factory;
rtc::scoped_refptr<webrtc::PeerConnectionInterface> peer_connection;
void queue_signal(godot::String p_name, int p_argc, const godot::Variant &p_arg1 = godot::Variant(), const godot::Variant &p_arg2 = godot::Variant(), const godot::Variant &p_arg3 = godot::Variant());
};
} // namespace godot_webrtc

82
src/init_gdextension.cpp Normal file
View File

@@ -0,0 +1,82 @@
/**************************************************************************/
/* init_gdextension.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 <gdextension_interface.h>
#include <godot_cpp/core/class_db.hpp>
#include <godot_cpp/core/defs.hpp>
#include <godot_cpp/godot.hpp>
#include "WebRTCLibDataChannel.hpp"
#include "WebRTCLibPeerConnection.hpp"
#ifdef _WIN32
// See upstream godot-cpp GH-771.
#undef GDN_EXPORT
#define GDN_EXPORT __declspec(dllexport)
#endif
using namespace godot;
using namespace godot_webrtc;
void register_webrtc_extension_types(ModuleInitializationLevel p_level) {
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
return;
}
WebRTCLibPeerConnection::initialize_signaling();
godot::ClassDB::register_class<WebRTCLibDataChannel>();
godot::ClassDB::register_class<WebRTCLibPeerConnection>();
WebRTCPeerConnection::set_default_extension("WebRTCLibPeerConnection");
}
void unregister_webrtc_extension_types(ModuleInitializationLevel p_level) {
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
return;
}
WebRTCLibPeerConnection::deinitialize_signaling();
}
extern "C" {
#ifdef GDEXTENSION_WEBRTC_40
GDExtensionBool GDE_EXPORT webrtc_extension_init(const GDExtensionInterface *p_interface, const GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization) {
#else
GDExtensionBool GDE_EXPORT webrtc_extension_init(const GDExtensionInterfaceGetProcAddress p_interface, const GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization) {
#endif
GDExtensionBinding::InitObject init_obj(p_interface, p_library, r_initialization);
init_obj.register_initializer(register_webrtc_extension_types);
init_obj.register_terminator(unregister_webrtc_extension_types);
init_obj.set_minimum_library_initialization_level(MODULE_INITIALIZATION_LEVEL_SCENE);
return init_obj.init();
}
}

View File

@@ -1,9 +1,45 @@
/**************************************************************************/
/* init_gdnative.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "WebRTCLibDataChannel.hpp"
#include "WebRTCLibPeerConnection.hpp"
#include "net/WebRTCPeerConnectionNative.hpp"
#include <gdnative_api_struct.gen.h>
#include <net/godot_net.h>
#ifdef _WIN32
// See upstream godot GH-62173.
#undef GDN_EXPORT
#define GDN_EXPORT __declspec(dllexport)
#endif
/* Singleton */
static bool _singleton = false;
static const godot_object *_singleton_lib = NULL;
@@ -34,21 +70,21 @@ godot_error create_peer_connection_wp(godot_object *out) {
_singleton_api->godot_string_destroy(&s);
// Bind script to Object
const void *args3[] = { (void *)script };
const void *args3[] = { (void *)script };
_singleton_api->godot_method_bind_ptrcall(_set_script_mb, out, args3, nullptr);
return GODOT_OK;
}
godot_net_webrtc_library library = {
{3, 2},
{ 3, 2 },
&unregistered,
&create_peer_connection_wp,
NULL,
};
extern "C" void GDN_EXPORT godot_gdnative_singleton() {
if (WebRTCPeerConnectionNative::_net_api) {
if (godot::WebRTCPeerConnectionNative::_net_api) {
ERR_FAIL_COND(!godot::gdnlib);
_singleton_lib = godot::gdnlib;
ERR_FAIL_COND(!godot::api);
@@ -62,7 +98,7 @@ extern "C" void GDN_EXPORT godot_gdnative_singleton() {
_set_library_mb = godot::api->godot_method_bind_get_method("NativeScript", "set_library");
ERR_FAIL_COND(!_set_library_mb);
// If registration is successful _singleton will be set to true
_singleton = WebRTCPeerConnectionNative::_net_api->godot_net_set_webrtc_library(&library) == GODOT_OK;
_singleton = godot::WebRTCPeerConnectionNative::_net_api->godot_net_set_webrtc_library(&library) == GODOT_OK;
if (!_singleton)
ERR_PRINT("Failed initializing webrtc singleton library");
}
@@ -72,7 +108,6 @@ extern "C" void GDN_EXPORT godot_gdnative_singleton() {
extern "C" void GDN_EXPORT godot_gdnative_init(godot_gdnative_init_options *o) {
const godot_gdnative_core_api_struct *api = o->api_struct;
for (int i = 0; i < api->num_extensions; i++) {
if (api->extensions[i]->type != GDNATIVE_EXT_NET)
continue;
@@ -82,7 +117,7 @@ extern "C" void GDN_EXPORT godot_gdnative_init(godot_gdnative_init_options *o) {
break;
if (net_api->next->version.major == 3 && net_api->next->version.minor == 2) {
WebRTCPeerConnectionNative::_net_api = (const godot_gdnative_ext_net_3_2_api_struct *)net_api->next;
godot::WebRTCPeerConnectionNative::_net_api = (const godot_gdnative_ext_net_3_2_api_struct *)net_api->next;
}
}
@@ -92,7 +127,7 @@ extern "C" void GDN_EXPORT godot_gdnative_init(godot_gdnative_init_options *o) {
extern "C" void GDN_EXPORT godot_gdnative_terminate(godot_gdnative_terminate_options *o) {
if (_singleton) { // If we are the active singleton, unregister
WebRTCPeerConnectionNative::_net_api->godot_net_set_webrtc_library(NULL);
godot::WebRTCPeerConnectionNative::_net_api->godot_net_set_webrtc_library(NULL);
}
godot_webrtc::WebRTCLibPeerConnection::deinitialize_signaling();
godot::Godot::gdnative_terminate(o);

View File

@@ -1,6 +1,38 @@
/**************************************************************************/
/* WebRTCDataChannelNative.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 "WebRTCDataChannelNative.hpp"
#include "net/WebRTCPeerConnectionNative.hpp"
using namespace godot;
void WebRTCDataChannelNative::register_interface(const godot_net_webrtc_data_channel *p_interface) {
ERR_FAIL_COND(!WebRTCPeerConnectionNative::_net_api);
WebRTCPeerConnectionNative::_net_api->godot_net_bind_webrtc_data_channel(_owner, p_interface);
@@ -24,69 +56,73 @@ WebRTCDataChannelNative::~WebRTCDataChannelNative() {
* and you could use void *user for any kind of state struct pointer you have.
*/
godot_error get_packet_wdc(void *user, const uint8_t **r_buffer, int *r_len) {
return ((WebRTCDataChannelNative *)user)->get_packet(r_buffer, r_len);
return (godot_error)(((WebRTCDataChannelNative *)user)->_get_packet(r_buffer, r_len));
}
godot_error put_packet_wdc(void *user, const uint8_t *p_buffer, int p_len) {
return ((WebRTCDataChannelNative *)user)->put_packet(p_buffer, p_len);
return (godot_error)(((WebRTCDataChannelNative *)user)->_put_packet(p_buffer, p_len));
}
godot_int get_available_packet_count_wdc(const void *user) {
return ((WebRTCDataChannelNative *)user)->get_available_packet_count();
return ((WebRTCDataChannelNative *)user)->_get_available_packet_count();
}
godot_int get_max_packet_size_wdc(const void *user) {
return ((WebRTCDataChannelNative *)user)->get_max_packet_size();
return ((WebRTCDataChannelNative *)user)->_get_max_packet_size();
}
void set_write_mode_wdc(void *user, godot_int write_mode) {
((WebRTCDataChannelNative *)user)->set_write_mode(write_mode);
((WebRTCDataChannelNative *)user)->_set_write_mode((godot::WebRTCDataChannel::WriteMode)write_mode);
}
godot_int get_write_mode_wdc(const void *user) {
return ((WebRTCDataChannelNative *)user)->get_write_mode();
return ((WebRTCDataChannelNative *)user)->_get_write_mode();
}
bool was_string_packet_wdc(const void *user) {
return ((WebRTCDataChannelNative *)user)->was_string_packet();
return ((WebRTCDataChannelNative *)user)->_was_string_packet();
}
godot_int get_ready_state_wdc(const void *user) {
return (godot_int)(((WebRTCDataChannelNative *)user)->get_ready_state());
return (godot_int)(((WebRTCDataChannelNative *)user)->_get_ready_state());
}
const char *get_label_wdc(const void *user) {
return ((WebRTCDataChannelNative *)user)->get_label();
return ((WebRTCDataChannelNative *)user)->_get_label().utf8().get_data();
}
bool is_ordered_wdc(const void *user) {
return ((WebRTCDataChannelNative *)user)->is_ordered();
return ((WebRTCDataChannelNative *)user)->_is_ordered();
}
int get_id_wdc(const void *user) {
return ((WebRTCDataChannelNative *)user)->get_id();
return ((WebRTCDataChannelNative *)user)->_get_id();
}
int get_max_packet_life_time_wdc(const void *user) {
return ((WebRTCDataChannelNative *)user)->get_max_packet_life_time();
return ((WebRTCDataChannelNative *)user)->_get_max_packet_life_time();
}
int get_max_retransmits_wdc(const void *user) {
return ((WebRTCDataChannelNative *)user)->get_max_retransmits();
return ((WebRTCDataChannelNative *)user)->_get_max_retransmits();
}
const char *get_protocol_wdc(const void *user) {
return ((WebRTCDataChannelNative *)user)->get_protocol();
return ((WebRTCDataChannelNative *)user)->_get_protocol().utf8().get_data();
}
bool is_negotiated_wdc(const void *user) {
return ((WebRTCDataChannelNative *)user)->is_negotiated();
return ((WebRTCDataChannelNative *)user)->_is_negotiated();
}
int get_buffered_amount_wdc(const void *user) {
return ((WebRTCDataChannelNative *)user)->_get_buffered_amount();
}
godot_error poll_wdc(void *user) {
return ((WebRTCDataChannelNative *)user)->poll();
return (godot_error)(((WebRTCDataChannelNative *)user)->_poll());
}
void close_wdc(void *user) {
((WebRTCDataChannelNative *)user)->close();
((WebRTCDataChannelNative *)user)->_close();
}

View File

@@ -1,3 +1,33 @@
/**************************************************************************/
/* WebRTCDataChannelNative.hpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef WEBRTC_DATA_CHANNEL_NATIVE
#define WEBRTC_DATA_CHANNEL_NATIVE
@@ -24,13 +54,32 @@ int get_max_packet_life_time_wdc(const void *);
int get_max_retransmits_wdc(const void *);
const char *get_protocol_wdc(const void *);
bool is_negotiated_wdc(const void *);
int get_buffered_amount_wdc(const void *);
godot_error poll_wdc(void *);
void close_wdc(void *);
#if GODOT_NET_WEBRTC_API_MAJOR == 3 && GODOT_NET_WEBRTC_API_MINOR < 4
extern "C" {
/* Extensions to WebRTCDataChannel */
typedef struct {
int (*get_buffered_amount)(const void *);
void *next; /* For extension? */
} godot_net_webrtc_data_channel_ext;
}
#endif
namespace godot {
class WebRTCDataChannelNative : public godot::WebRTCDataChannelGDNative {
GODOT_CLASS(WebRTCDataChannelNative, godot::WebRTCDataChannelGDNative);
protected:
godot_net_webrtc_data_channel_ext interface_ext = {
&get_buffered_amount_wdc,
NULL,
};
godot_net_webrtc_data_channel interface = {
{ 3, 1 },
this,
@@ -54,7 +103,7 @@ protected:
&poll_wdc,
&close_wdc,
NULL,
&interface_ext,
};
public:
@@ -63,29 +112,32 @@ public:
void _init();
void register_interface(const godot_net_webrtc_data_channel *interface);
virtual void set_write_mode(godot_int mode) = 0;
virtual godot_int get_write_mode() const = 0;
virtual bool was_string_packet() const = 0;
virtual 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 const char *get_label() const = 0;
virtual bool is_ordered() const = 0;
virtual int get_id() const = 0;
virtual int get_max_packet_life_time() const = 0;
virtual int get_max_retransmits() const = 0;
virtual const char *get_protocol() const = 0;
virtual bool is_negotiated() const = 0;
virtual ChannelState _get_ready_state() const = 0;
virtual godot::String _get_label() const = 0;
virtual bool _is_ordered() const = 0;
virtual int32_t _get_id() const = 0;
virtual int32_t _get_max_packet_life_time() const = 0;
virtual int32_t _get_max_retransmits() const = 0;
virtual godot::String _get_protocol() const = 0;
virtual bool _is_negotiated() const = 0;
virtual int32_t _get_buffered_amount() const = 0;
virtual godot_error poll() = 0;
virtual void close() = 0;
virtual godot::Error _poll() = 0;
virtual void _close() = 0;
/* PacketPeer */
virtual godot_error get_packet(const uint8_t **r_buffer, int *r_len) = 0;
virtual godot_error put_packet(const uint8_t *p_buffer, int p_len) = 0;
virtual godot_int get_available_packet_count() const = 0;
virtual godot_int get_max_packet_size() const = 0;
virtual godot::Error _get_packet(const uint8_t **r_buffer, int32_t *r_len) = 0;
virtual godot::Error _put_packet(const uint8_t *p_buffer, int32_t p_len) = 0;
virtual int32_t _get_available_packet_count() const = 0;
virtual int32_t _get_max_packet_size() const = 0;
~WebRTCDataChannelNative();
};
}; // namespace godot
#endif // WEBRTC_DATA_CHANNEL_NATIVE

View File

@@ -1,5 +1,37 @@
/**************************************************************************/
/* WebRTCPeerConnectionNative.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 "WebRTCPeerConnectionNative.hpp"
using namespace godot;
const godot_gdnative_ext_net_3_2_api_struct *WebRTCPeerConnectionNative::_net_api = NULL;
void WebRTCPeerConnectionNative::register_interface(const godot_net_webrtc_peer_connection *p_interface) {
@@ -25,19 +57,23 @@ WebRTCPeerConnectionNative::~WebRTCPeerConnectionNative() {
* and you could use void *user for any kind of state struct pointer you have.
*/
godot_int get_connection_state_wp(const void *user) {
return (godot_int)((WebRTCPeerConnectionNative *)user)->get_connection_state();
return (godot_int)((WebRTCPeerConnectionNative *)user)->_get_connection_state();
}
godot_error initialize_wp(void *user, const godot_dictionary *p_config) {
return ((WebRTCPeerConnectionNative *)user)->initialize(p_config);
return (godot_error)(((WebRTCPeerConnectionNative *)user)->_initialize(*(Dictionary *)p_config));
}
godot_object *create_data_channel_wp(void *user, const char *p_channel, const godot_dictionary *p_channel_config) {
return ((WebRTCPeerConnectionNative *)user)->create_data_channel(p_channel, p_channel_config);
Object *ptr = ((WebRTCPeerConnectionNative *)user)->_create_data_channel(p_channel, *(Dictionary *)p_channel_config);
if (ptr) {
return ptr->_owner;
}
return nullptr;
}
godot_error create_offer_wp(void *user) {
return ((WebRTCPeerConnectionNative *)user)->create_offer();
return (godot_error)(((WebRTCPeerConnectionNative *)user)->_create_offer());
}
godot_error create_answer_wp(void *user) {
@@ -45,21 +81,21 @@ godot_error create_answer_wp(void *user) {
}
godot_error set_remote_description_wp(void *user, const char *type, const char *sdp) {
return ((WebRTCPeerConnectionNative *)user)->set_remote_description(type, sdp);
return (godot_error)(((WebRTCPeerConnectionNative *)user)->_set_remote_description(type, sdp));
}
godot_error set_local_description_wp(void *user, const char *type, const char *sdp) {
return ((WebRTCPeerConnectionNative *)user)->set_local_description(type, sdp);
return (godot_error)(((WebRTCPeerConnectionNative *)user)->_set_local_description(type, sdp));
}
godot_error add_ice_candidate_wp(void *user, const char *sdpMidName, int sdpMlineIndexName, const char *sdpName) {
return ((WebRTCPeerConnectionNative *)user)->add_ice_candidate(sdpMidName, sdpMlineIndexName, sdpName);
return (godot_error)(((WebRTCPeerConnectionNative *)user)->_add_ice_candidate(sdpMidName, sdpMlineIndexName, sdpName));
}
godot_error poll_wp(void *user) {
return ((WebRTCPeerConnectionNative *)user)->poll();
return (godot_error)((WebRTCPeerConnectionNative *)user)->_poll();
}
void close_wp(void *user) {
((WebRTCPeerConnectionNative *)user)->close();
((WebRTCPeerConnectionNative *)user)->_close();
}

View File

@@ -1,3 +1,33 @@
/**************************************************************************/
/* WebRTCPeerConnectionNative.hpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef WEBRTC_PEER_NATIVE
#define WEBRTC_PEER_NATIVE
@@ -20,6 +50,8 @@ godot_error add_ice_candidate_wp(void *, const char *, int, const char *);
godot_error poll_wp(void *);
void close_wp(void *);
namespace godot {
class WebRTCPeerConnectionNative : public godot::WebRTCPeerConnectionGDNative {
GODOT_CLASS(WebRTCPeerConnectionNative, godot::WebRTCPeerConnectionGDNative);
@@ -43,24 +75,43 @@ protected:
};
public:
enum GatheringState {
GATHERING_STATE_NEW,
GATHERING_STATE_GATHERING,
GATHERING_STATE_COMPLETE,
};
enum SignalingState {
SIGNALING_STATE_STABLE,
SIGNALING_STATE_HAVE_LOCAL_OFFER,
SIGNALING_STATE_HAVE_REMOTE_OFFER,
SIGNALING_STATE_HAVE_LOCAL_PRANSWER,
SIGNALING_STATE_HAVE_REMOTE_PRANSWER,
SIGNALING_STATE_CLOSED,
};
static void _register_methods();
static const godot_gdnative_ext_net_3_2_api_struct *_net_api;
void _init();
void register_interface(const godot_net_webrtc_peer_connection *interface);
virtual ConnectionState get_connection_state() const = 0;
virtual ConnectionState _get_connection_state() const = 0;
virtual GatheringState _get_gathering_state() const = 0;
virtual SignalingState _get_signaling_state() const = 0;
virtual godot_error initialize(const godot_dictionary *p_config) = 0;
virtual godot_object *create_data_channel(const char *p_channel, const godot_dictionary *p_channel_config) = 0;
virtual godot_error create_offer() = 0;
virtual godot_error set_remote_description(const char *type, const char *sdp) = 0;
virtual godot_error set_local_description(const char *type, const char *sdp) = 0;
virtual godot_error add_ice_candidate(const char *sdpMidName, int sdpMlineIndexName, const char *sdpName) = 0;
virtual godot_error poll() = 0;
virtual void close() = 0;
virtual godot::Error _initialize(const godot::Dictionary &p_config) = 0;
virtual godot::Object *_create_data_channel(const godot::String &p_channel, const godot::Dictionary &p_channel_config) = 0;
virtual godot::Error _create_offer() = 0;
virtual godot::Error _set_remote_description(const godot::String &type, const godot::String &sdp) = 0;
virtual godot::Error _set_local_description(const godot::String &type, const godot::String &sdp) = 0;
virtual godot::Error _add_ice_candidate(const godot::String &sdpMidName, int64_t sdpMlineIndexName, const godot::String &sdpName) = 0;
virtual godot::Error _poll() = 0;
virtual void _close() = 0;
~WebRTCPeerConnectionNative();
};
}; // namespace godot
#endif // WEBRTC_PEER_NATIVE

82
thirdparty/README.md vendored Normal file
View File

@@ -0,0 +1,82 @@
# Third party libraries
Please keep categories (`##` level) listed alphabetically and matching their
respective folder names. Use two empty lines to separate categories for
readability.
## json
- Upstream: https://github.com/nlohmann/json
- Version: 3.10.5 (4f8fba14066156b73f1189a2b8bd568bde5284c5, 2022)
- License: MIT
Module location:
- thirdparty/libdatachannel/deps/json
## libdatachannel
- Upstream: https://github.com/paullouisageneau/libdatachannel
- Version: 0.18.5 (0522acdd3dd6af9451a1aa4cd47647172f879a5f, 2023)
- License: MPL 2.0
Module location:
- thirdparty/libdatachannel
# libjuice
- Upstream: https://github.com/paullouisageneau/libjuice
- Version: 1.2.3 (8c23cc88c6d41e5ccbc44ea0ad3d79b22cf02361, 2023)
- License: MPL 2.0
Module location:
- thirdparty/libdatachannel/deps/libjuice
## libsrtp
- Upstream: https://github.com/cisco/libsrtp
- Version: 2.5.0 (a566a9cfcd619e8327784aa7cff4a1276dc1e895, 2023)
- License: BSD-3-Clause
Module location:
- thirdparty/libdatachannel/deps/libsrtp
## openssl
- Upstream: git://git.openssl.org/openssl.git
- Version: 3.0.9 (de90e54bbe82e5be4fb9608b6f5c308bb837d355, 2023)
- License: Apache 2.0
Module location:
- thirdparty/openssl
## plog
- Upstream: https://github.com/SergiusTheBest/plog
- Version: git (d8461e9d473e59fbcc1f79eee021550dcf81e618, 2021)
- License: MPL 2.0
Module location:
- thirdparty/libdatachannel/deps/plog
## usrsctp
- Upstream: https://github.com/sctplab/usrsctp
- Version: git (7c31bd35c79ba67084ce029511193a19ceb97447, 2021)
- License: BSD-3-Clause
Module location:
- thirdparty/libdatachannel/deps/usrsctp

1
thirdparty/libdatachannel vendored Submodule

1
thirdparty/openssl vendored Submodule

Submodule thirdparty/openssl added at de90e54bbe

135
tools/cmake.py Normal file
View File

@@ -0,0 +1,135 @@
import os, sys
import SCons.Util
import SCons.Builder
import SCons.Action
def cmake_default_flags(env):
if env.get("cmake_default_flags", ""):
return SCons.Util.CLVar(env["cmake_default_flags"])
config = {}
if "CC" in env:
config["CMAKE_C_COMPILER"] = env["CC"]
if "CXX" in env:
config["CMAKE_CXX_COMPILER"] = env["CXX"]
if env["platform"] == "android":
api = env["android_api_level"]
abi = {
"arm64": "arm64-v8a",
"arm32": "armeabi-v7a",
"x86_32": "x86",
"x86_64": "x86_64",
}[env["arch"]]
config["CMAKE_SYSTEM_NAME"] = "Android"
config["CMAKE_SYSTEM_VERSION"] = api
config["CMAKE_ANDROID_ARCH_ABI"] = abi
config["ANDROID_ABI"] = abi
config["CMAKE_TOOLCHAIN_FILE"] = "%s/build/cmake/android.toolchain.cmake" % env.get(
"ANDROID_NDK_ROOT", os.environ.get("ANDROID_NDK_ROOT", "")
)
config["CMAKE_ANDROID_STL_TYPE"] = "c++_static"
elif env["platform"] == "linux":
linux_flags = {
"x86_64": "-m64",
"x86_32": "-m32",
}.get(env["arch"], "")
if linux_flags:
config["CMAKE_C_FLAGS"] = linux_flags
config["CMAKE_CXX_FLAGS"] = linux_flags
elif env["platform"] == "macos":
if env["arch"] == "universal":
config["CMAKE_OSX_ARCHITECTURES"] = '"x86_64;arm64"'
else:
config["CMAKE_OSX_ARCHITECTURES"] = env["arch"]
if env["macos_deployment_target"] != "default":
config["CMAKE_OSX_DEPLOYMENT_TARGET"] = env["macos_deployment_target"]
if env["platform"] == "macos" and sys.platform != "darwin" and "OSXCROSS_ROOT" in os.environ:
config["CMAKE_AR"] = env["AR"]
config["CMAKE_RANLIB"] = env["RANLIB"]
if env["arch"] == "universal":
flags = "-arch x86_64 -arch arm64"
else:
flags = "-arch " + env["arch"]
if env["macos_deployment_target"] != "default":
flags += " -mmacosx-version-min=" + env["macos_deployment_target"]
config["CMAKE_C_FLAGS"] = flags
config["CMAKE_CXX_FLAGS"] = flags
elif env["platform"] == "ios":
if env["arch"] == "universal":
raise ValueError("iOS architecture not supported: %s" % env["arch"])
config["CMAKE_SYSTEM_NAME"] = "iOS"
config["CMAKE_OSX_ARCHITECTURES"] = env["arch"]
if env.get("ios_min_version", "default") != "default":
config["CMAKE_OSX_DEPLOYMENT_TARGET"] = env["ios_min_version"]
if env["ios_simulator"]:
config["CMAKE_OSX_SYSROOT"] = "iphonesimulator"
elif env["platform"] == "windows":
config["CMAKE_SYSTEM_NAME"] = "Windows"
flags = ["-D%s=%s" % it for it in config.items()]
if env["CMAKEGENERATOR"]:
flags.extend(["-G", env["CMAKEGENERATOR"]])
elif env["platform"] == "windows":
if env.get("is_msvc", False):
flags.extend(["-G", "NMake Makefiles"])
elif sys.platform in ["win32", "msys", "cygwin"]:
flags.extend(["-G", "Ninja"])
else:
flags.extend(["-G", "Unix Makefiles"])
return flags
def cmake_emitter(target, source, env):
return [str(target[0]) + "/CMakeCache.txt"] + target[1:], [str(source[0]) + "/CMakeLists.txt"] + source[1:]
def cmake_generator(target, source, env, for_signature):
# Strip the -j option for signature to avoid rebuilding when num_jobs changes.
build = env["CMAKEBUILDCOM"].replace("-j$CMAKEBUILDJOBS", "") if for_signature else env["CMAKEBUILDCOM"]
return [
SCons.Action.Action("$CMAKECONFCOM", "$CMAKECONFCOMSTR"),
SCons.Action.Action(build, "$CMAKEBUILDCOMSTR"),
]
def cmake_build(env, target_dir, source_dir, cmake_outputs=[], cmake_targets=[], cmake_options=[], dependencies=[]):
cmake_env = env.Clone()
target = env.Dir("{}/{}/{}".format(target_dir, env["platform"], env["arch"]))
source = env.Dir(source_dir)
builder_targets = [target] + [str(target) + "/" + f for f in cmake_outputs]
builder_sources = [source] + dependencies
cmake_env.Append(CMAKECONFFLAGS=["-D%s=%s" % it for it in cmake_options.items()])
if len(cmake_targets) > 0:
cmake_env.Append(CMAKEBUILDFLAGS=["-t"] + [t for t in cmake_targets])
return cmake_env.CMake(builder_targets, builder_sources)
def options(opts):
opts.Add("cmake_default_flags", "Default CMake platform flags override, will be autodetected if not specified.", "")
def exists(env):
return True
def generate(env):
env["CMAKE"] = "cmake"
env["_cmake_default_flags"] = cmake_default_flags
env["CMAKEDEFAULTFLAGS"] = "${_cmake_default_flags(__env__)}"
env["CMAKEGENERATOR"] = ""
env["CMAKECONFFLAGS"] = SCons.Util.CLVar("")
env["CMAKECONFCOM"] = "$CMAKE -B ${TARGET.dir} $CMAKEDEFAULTFLAGS $CMAKECONFFLAGS ${SOURCE.dir}"
env["CMAKEBUILDJOBS"] = "${__env__.GetOption('num_jobs')}"
env["CMAKEBUILDFLAGS"] = SCons.Util.CLVar("")
env["CMAKEBUILDCOM"] = "$CMAKE --build ${TARGET.dir} $CMAKEBUILDFLAGS -j$CMAKEBUILDJOBS"
env["BUILDERS"]["CMake"] = SCons.Builder.Builder(generator=cmake_generator, emitter=cmake_emitter)
env.AddMethod(cmake_build, "CMakeBuild")

286
tools/openssl.py Normal file
View File

@@ -0,0 +1,286 @@
import os, sys
import SCons.Util
import SCons.Builder
import SCons.Action
from SCons.Defaults import Mkdir
from SCons.Variables import PathVariable, BoolVariable
def ssl_platform_target(env):
targets = {}
platform = env["platform"]
if platform == "linux":
targets = {
"x86_32": "linux-x86",
"x86_64": "linux-x86_64",
"arm64": "linux-aarch64",
"arm32": "linux-armv4",
"rv64": "linux64-riscv64",
}
elif platform == "android":
targets = {
"arm64": "android-arm64",
"arm32": "android-arm",
"x86_32": "android-x86",
"x86_64": "android-x86_64",
}
elif platform == "macos":
targets = {
"x86_64": "darwin64-x86_64",
"arm64": "darwin64-arm64",
}
elif platform == "ios":
if env["ios_simulator"]:
targets = {
"x86_64": "iossimulator-xcrun",
"arm64": "iossimulator-xcrun",
}
else:
targets = {
"arm64": "ios64-xcrun",
"arm32": "ios-xcrun",
}
elif platform == "windows":
if env.get("is_msvc", False):
targets = {
"x86_32": "VC-WIN32",
"x86_64": "VC-WIN64A",
}
else:
targets = {
"x86_32": "mingw",
"x86_64": "mingw64",
}
arch = env["arch"]
target = targets.get(arch, "")
if target == "":
raise ValueError("Architecture '%s' not supported for platform: '%s'" % (arch, platform))
return target
def ssl_platform_options(env):
ssl_config_options = [
"no-ssl2",
"no-ssl3",
"no-weak-ssl-ciphers",
"no-legacy",
"no-shared",
"no-tests",
]
if env["platform"] == "windows":
ssl_config_options.append("enable-capieng")
return ssl_config_options
def ssl_platform_flags(env):
args = []
if env["platform"] == "android":
if env.get("android_api_level", ""):
api = int(env["android_api_level"])
args.append("-D__ANDROID_API__=%s" % api)
elif env["platform"] == "macos":
# OSXCross toolchain setup.
if sys.platform != "darwin" and "OSXCROSS_ROOT" in os.environ:
for k in ["CC", "CXX", "AR", "AS", "RANLIB"]:
args.append("%s=%s" % (k, env[k]))
elif env["platform"] == "windows":
is_win_host = sys.platform in ["win32", "msys", "cygwin"]
if not (is_win_host or env.get("is_msvc", False)):
mingw_prefixes = {
"x86_32": "--cross-compile-prefix=i686-w64-mingw32-",
"x86_64": "--cross-compile-prefix=x86_64-w64-mingw32-",
}
args.append(mingw_prefixes[env["arch"]])
return args
def ssl_configure_args(env):
if env.get("openssl_configure_options", ""):
opts = SCons.Util.CLVar(env["openssl_configure_options"])
else:
opts = ssl_platform_options(env)
if env.get("openssl_configure_target", ""):
target = [env["openssl_configure_target"]]
else:
target = [ssl_platform_target(env)]
if env.get("openssl_configure_flags", ""):
flags = SCons.Util.CLVar(env["openssl_configure_flags"])
else:
flags = ssl_platform_flags(env)
return opts + target + flags
def ssl_emitter(target, source, env):
return env["SSL_LIBS"], [env.File(env["SSL_SOURCE"] + "/Configure"), env.File(env["SSL_SOURCE"] + "/VERSION.dat")]
def build_openssl(env, jobs=None):
if env["SSL_EXTERNAL"]:
# Setup the env to use the provided libraries, and return them without building.
env.Prepend(CPPPATH=[env["SSL_INCLUDE"]])
env.Prepend(LIBPATH=[env["SSL_BUILD"]])
if env["platform"] == "windows":
env.PrependUnique(LIBS=["crypt32", "ws2_32", "advapi32", "user32"])
env.Prepend(LIBS=env["SSL_LIBS"])
return [env["SSL_CRYPTO_LIBRARY"], env["SSL_LIBRARY"]]
if jobs is None:
jobs = int(env.GetOption("num_jobs"))
# Since the OpenSSL build system does not support macOS universal binaries, we first need to build the two libraries
# separately, then we join them together using lipo.
if env["platform"] == "macos" and env["arch"] == "universal":
build_envs = {
"x86_64": env.Clone(),
"arm64": env.Clone(),
}
arch_ssl = []
for arch in build_envs:
benv = build_envs[arch]
benv["arch"] = arch
generate(benv)
benv["SSLBUILDJOBS"] = max([1, int(jobs / len(build_envs))])
ssl = benv.OpenSSLBuilder()
arch_ssl.extend(ssl)
benv.NoCache(ssl) # Needs refactoring to properly cache generated headers.
# x86_64 and arm64 includes are equivalent.
env["SSL_INCLUDE"] = build_envs["arm64"]["SSL_INCLUDE"]
# Join libraries using lipo.
lipo_action = "lipo $SOURCES -create -output $TARGET"
ssl_libs = list(map(lambda arch: build_envs[arch]["SSL_LIBRARY"], build_envs))
ssl_crypto_libs = list(map(lambda arch: build_envs[arch]["SSL_CRYPTO_LIBRARY"], build_envs))
ssl = env.Command(env["SSL_LIBRARY"], ssl_libs, lipo_action)
ssl += env.Command(env["SSL_CRYPTO_LIBRARY"], ssl_crypto_libs, lipo_action)
env.Depends(ssl, arch_ssl)
else:
benv = env.Clone()
benv["SSLBUILDJOBS"] = jobs
ssl = benv.OpenSSLBuilder()
benv.NoCache(ssl) # Needs refactoring to properly cache generated headers.
# Setup the environment to use the freshly built openssl.
env.Prepend(CPPPATH=[env["SSL_INCLUDE"]])
env.Prepend(LIBPATH=[env["SSL_BUILD"]])
if env["platform"] == "windows":
env.PrependUnique(LIBS=["crypt32", "ws2_32", "advapi32", "user32"])
env.Prepend(LIBS=env["SSL_LIBS"])
return ssl
def ssl_generator(target, source, env, for_signature):
# Strip the -j option for signature to avoid rebuilding when num_jobs changes.
build = env["SSLBUILDCOM"].replace("-j$SSLBUILDJOBS", "") if for_signature else env["SSLBUILDCOM"]
return [
Mkdir("$SSL_BUILD"),
Mkdir("$SSL_INSTALL"),
SCons.Action.Action("$SSLCONFIGCOM", "$SSLCONFIGCOMSTR"),
SCons.Action.Action(build, "$SSLBUILDCOMSTR"),
]
def options(opts):
opts.Add(PathVariable("openssl_source", "Path to the openssl sources.", "thirdparty/openssl"))
opts.Add("openssl_build", "Destination path of the openssl build.", "bin/thirdparty/openssl")
opts.Add(
"openssl_configure_options",
"OpenSSL configure options override. Will use a reasonable default if not specified.",
"",
)
opts.Add(
"openssl_configure_target", "OpenSSL configure target override, will be autodetected if not specified.", ""
)
opts.Add(
"openssl_configure_flags",
"OpenSSL configure compiler flags override. Will be autodetected if not specified.",
"",
)
opts.Add(
"openssl_external_crypto",
'An external libcrypto static library (e.g. "/usr/lib/x86_64-linux-gnu/libcrypto.a"). If not provided, OpenSSL will be built from source.',
"",
)
opts.Add(
"openssl_external_ssl",
'An external libssl static library (e.g. "/usr/lib/x86_64-linux-gnu/libssl.a"). If not provided, OpenSSL will be built from source.',
"",
)
opts.Add(
"openssl_external_include",
'An external OpenSSL "include" folder (e.g. "/usr/include/openssl").',
"",
)
def exists(env):
return True
def generate(env):
env.AddMethod(build_openssl, "OpenSSL")
# Check if the user specified infos about external OpenSSL files.
external_opts = ["openssl_external_crypto", "openssl_external_ssl", "openssl_external_include"]
is_set = lambda k: env.get(k, "") != ""
if any(map(is_set, external_opts)):
# Need provide the whole (crypto, ssl, include) triple to proceed.
if not all(map(is_set, external_opts)):
print('Error: The options "%s" must all be set to use a external library.' % '", "'.join(external_opts))
sys.exit(255)
env["SSL_CRYPTO_LIBRARY"] = env.File("${openssl_external_crypto}")
env["SSL_LIBRARY"] = env.File("${openssl_external_ssl}")
env["SSL_BUILD"] = env.Dir("${SSL_LIBRARY.dir}").abspath
env["SSL_INSTALL"] = env.Dir("${SSL_LIBRARY.dir}").abspath
env["SSL_INCLUDE"] = env.Dir("${openssl_external_include}").abspath
env["SSL_LIBS"] = [env["SSL_LIBRARY"], env["SSL_CRYPTO_LIBRARY"]]
env["SSL_EXTERNAL"] = True
return
# We will need to build our own OpenSSL library.
env["SSL_EXTERNAL"] = False
# Android needs the NDK in ENV, and proper PATH setup.
if env["platform"] == "android" and env["ENV"].get("ANDROID_NDK_ROOT", "") == "":
cc_path = os.path.dirname(env["CC"])
if cc_path and cc_path not in env["ENV"]:
env.PrependENVPath("PATH", cc_path)
if "ANDROID_NDK_ROOT" not in env["ENV"]:
env["ENV"]["ANDROID_NDK_ROOT"] = env.get("ANDROID_NDK_ROOT", os.environ.get("ANDROID_NDK_ROOT", ""))
env["SSL_SOURCE"] = env.Dir(env["openssl_source"]).abspath
env["SSL_BUILD"] = env.Dir(env["openssl_build"] + "/{}/{}".format(env["platform"], env["arch"])).abspath
env["SSL_INSTALL"] = env.Dir(env["SSL_BUILD"] + "/dest").abspath
env["SSL_INCLUDE"] = env.Dir(env["SSL_INSTALL"] + "/include").abspath
lib_ext = ".lib" if env.get("is_msvc", False) else ".a"
env["SSL_LIBRARY"] = env.File(env["SSL_BUILD"] + "/libssl" + lib_ext)
env["SSL_CRYPTO_LIBRARY"] = env.File(env["SSL_BUILD"] + "/libcrypto" + lib_ext)
env["SSL_LIBS"] = [env["SSL_LIBRARY"], env["SSL_CRYPTO_LIBRARY"]]
# Configure action
env["PERL"] = env.get("PERL", "perl")
env["_ssl_configure_args"] = ssl_configure_args
env["SSLPLATFORMCONFIG"] = "${_ssl_configure_args(__env__)}"
env["SSLCONFFLAGS"] = SCons.Util.CLVar("")
# fmt: off
env["SSLCONFIGCOM"] = 'cd ${TARGET.dir} && $PERL -- ${SOURCE.abspath} --prefix="${SSL_INSTALL}" --openssldir="${SSL_INSTALL}" $SSLPLATFORMCONFIG $SSLCONFFLAGS'
# fmt: on
# Build action
env["SSLBUILDJOBS"] = "${__env__.GetOption('num_jobs')}"
# fmt: off
env["SSLBUILDCOM"] = "make -j$SSLBUILDJOBS -C ${TARGET.dir} && make -j$SSLBUILDJOBS -C ${TARGET.dir} install_sw install_ssldirs"
# fmt: on
# Windows MSVC needs to build using NMake
if env["platform"] == "windows" and env.get("is_msvc", False):
env["SSLBUILDCOM"] = "cd ${TARGET.dir} && nmake install_sw install_ssldirs"
env["BUILDERS"]["OpenSSLBuilder"] = SCons.Builder.Builder(generator=ssl_generator, emitter=ssl_emitter)
env.AddMethod(build_openssl, "OpenSSL")

51
tools/rtc.py Normal file
View File

@@ -0,0 +1,51 @@
import os
def build_library(env, ssl):
rtc_config = {
"CMAKE_BUILD_TYPE": "RelWithDebInfo" if env["debug_symbols"] else "Release",
"USE_NICE": 0,
"NO_WEBSOCKET": 1,
"NO_EXAMPLES": 1,
"NO_TESTS": 1,
"BUILD_WITH_WARNINGS": "0", # Disables werror in libsrtp.
"OPENSSL_USE_STATIC_LIBS": 1,
"OPENSSL_INCLUDE_DIR": env["SSL_INCLUDE"],
"OPENSSL_SSL_LIBRARY": env["SSL_LIBRARY"],
"OPENSSL_CRYPTO_LIBRARY": env["SSL_CRYPTO_LIBRARY"],
"OPENSSL_ROOT_DIR": env["SSL_INSTALL"],
}
is_msvc = env.get("is_msvc", False)
lib_ext = ".lib" if is_msvc else ".a"
lib_prefix = "" if is_msvc else "lib"
rtc_libs = [
"{}datachannel-static{}".format(lib_prefix, lib_ext),
"deps/libjuice/{}juice-static{}".format(lib_prefix, lib_ext),
"deps/libsrtp/{}srtp2{}".format(lib_prefix, lib_ext),
"deps/usrsctp/usrsctplib/{}usrsctp{}".format(lib_prefix, lib_ext),
]
# Build libdatachannel
rtc = env.CMakeBuild(
"#bin/thirdparty/libdatachannel/",
"#thirdparty/libdatachannel",
cmake_options=rtc_config,
cmake_outputs=rtc_libs,
cmake_targets=["datachannel-static"],
dependencies=ssl,
)
# Configure env.
if env["platform"] == "windows":
env.PrependUnique(LIBS=["iphlpapi", "bcrypt"])
env.Prepend(LIBS=list(filter(lambda f: str(f).endswith(lib_ext), rtc)))
env.Append(CPPPATH=["#thirdparty/libdatachannel/include"])
return rtc
def exists(env):
return "CMake" in env
def generate(env):
env.AddMethod(build_library, "BuildLibDataChannel")