mirror of
https://github.com/godotengine/webrtc-native.git
synced 2026-01-01 05:48:15 +03:00
Compare commits
187 Commits
0.2
...
1.0.8-stab
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
93e11a7343 | ||
|
|
ba46b25c00 | ||
|
|
31fd88dbf5 | ||
|
|
ea8b37fe29 | ||
|
|
cb1ef2e59c | ||
|
|
038bac82d6 | ||
|
|
effada6b45 | ||
|
|
26bc56f934 | ||
|
|
44ee53715d | ||
|
|
0b89ed885d | ||
|
|
bf8f6e4581 | ||
|
|
1443d02c8d | ||
|
|
431df320c4 | ||
|
|
762f7cc5d2 | ||
|
|
66a9c6bab3 | ||
|
|
e391109df2 | ||
|
|
762365d20a | ||
|
|
34ef1043ee | ||
|
|
7141bc487e | ||
|
|
9520b23a4c | ||
|
|
cdb4673f48 | ||
|
|
5b4221462b | ||
|
|
86d080b328 | ||
|
|
1831677f63 | ||
|
|
fa28efa51d | ||
|
|
6e33e43f36 | ||
|
|
81239d820d | ||
|
|
b0efc17d3b | ||
|
|
ec0ededcde | ||
|
|
308db19120 | ||
|
|
724910c734 | ||
|
|
7a4e27e5f0 | ||
|
|
d768508435 | ||
|
|
fb2c9c3687 | ||
|
|
cf23e5e740 | ||
|
|
668d0250a7 | ||
|
|
121ed5664d | ||
|
|
67a378a667 | ||
|
|
023c42d3b3 | ||
|
|
6d96092f88 | ||
|
|
77969f68d9 | ||
|
|
a9d8ea2a1c | ||
|
|
6e2262b6c3 | ||
|
|
cb2be8723a | ||
|
|
d278661d76 | ||
|
|
552d696e0a | ||
|
|
6f4d8f5238 | ||
|
|
8040565b0e | ||
|
|
38c83f667d | ||
|
|
1de32aa9ea | ||
|
|
ed3771ced0 | ||
|
|
ac3bdb3613 | ||
|
|
931a7551f5 | ||
|
|
0771084b54 | ||
|
|
ae0dd0626a | ||
|
|
0be6b671e5 | ||
|
|
d96b43b7ee | ||
|
|
ec8cd5c0e4 | ||
|
|
b03099f7b4 | ||
|
|
85efdfd6ce | ||
|
|
32ae1d1195 | ||
|
|
54c8586235 | ||
|
|
f19011f2fb | ||
|
|
86c27ec7ef | ||
|
|
f2ee596bd9 | ||
|
|
61299ca4b7 | ||
|
|
df643250f5 | ||
|
|
45549e020f | ||
|
|
ee40730c20 | ||
|
|
8f7cb77f34 | ||
|
|
eb65d88cd4 | ||
|
|
e8de07dbb1 | ||
|
|
e34000653b | ||
|
|
826a736176 | ||
|
|
b7098e7496 | ||
|
|
6de604ffee | ||
|
|
f0af5f9982 | ||
|
|
fbe4e06b9f | ||
|
|
9a9fc0953b | ||
|
|
c6b6f7e18c | ||
|
|
00f952bcf1 | ||
|
|
d7032f7b85 | ||
|
|
c9a1efc7a0 | ||
|
|
5bc4b79435 | ||
|
|
b7b76dddab | ||
|
|
0b1c55ed83 | ||
|
|
093ac7d489 | ||
|
|
84e9d6dd37 | ||
|
|
a49a2b03e1 | ||
|
|
656d3a9964 | ||
|
|
2bc2a5d162 | ||
|
|
7176344056 | ||
|
|
7d260b1b32 | ||
|
|
0c10a7f3e3 | ||
|
|
40962dbe19 | ||
|
|
bdd9d50745 | ||
|
|
5348407de9 | ||
|
|
5002991511 | ||
|
|
0fc992e0d5 | ||
|
|
fbadff454c | ||
|
|
61a6d25c47 | ||
|
|
dfaad6f5ba | ||
|
|
35bdd5efa7 | ||
|
|
90aaa0b82e | ||
|
|
16f311844b | ||
|
|
dfb34df36e | ||
|
|
9715e73ae4 | ||
|
|
2e9a25bb39 | ||
|
|
6067addd96 | ||
|
|
a3fbd33464 | ||
|
|
d697901f81 | ||
|
|
3eb7d0aa3b | ||
|
|
ecec40f59e | ||
|
|
37a289addf | ||
|
|
1436024f59 | ||
|
|
690b31e7dd | ||
|
|
9b0a5d8b46 | ||
|
|
1769730ef0 | ||
|
|
04898f2714 | ||
|
|
d7fc6cde3b | ||
|
|
1009e8bb1c | ||
|
|
5fd359f674 | ||
|
|
822e0532c2 | ||
|
|
d8cbd14a28 | ||
|
|
6e52fce986 | ||
|
|
a93af67d75 | ||
|
|
22ee6435a1 | ||
|
|
b5d8a72ef8 | ||
|
|
2ad1bf1716 | ||
|
|
e683c79938 | ||
|
|
426ca6cc8e | ||
|
|
9b53ef3325 | ||
|
|
e41d2903ad | ||
|
|
f315912d85 | ||
|
|
62ab2e59f8 | ||
|
|
a2fc27f646 | ||
|
|
b2654cc2bd | ||
|
|
e19b370126 | ||
|
|
8c18112f5d | ||
|
|
c37cc530e7 | ||
|
|
13ab33af36 | ||
|
|
3bdf6cdc13 | ||
|
|
072ba5c1d0 | ||
|
|
7cb6d6c846 | ||
|
|
c0b31562f5 | ||
|
|
69f92fa26c | ||
|
|
d06e536d12 | ||
|
|
68a892d9f3 | ||
|
|
72b337e32c | ||
|
|
eeabf0a844 | ||
|
|
04fbae6ce3 | ||
|
|
ce3f086ec4 | ||
|
|
00ac03c8e7 | ||
|
|
fa5296a4e4 | ||
|
|
189c353264 | ||
|
|
e44c42fde8 | ||
|
|
524fdde8f2 | ||
|
|
673a4c1a1c | ||
|
|
cf98eb2e7a | ||
|
|
7b92ab2a7b | ||
|
|
e120cc7ed6 | ||
|
|
da20ebf397 | ||
|
|
3711ad23f6 | ||
|
|
001be78500 | ||
|
|
416ea27305 | ||
|
|
65bb4cb9ae | ||
|
|
3014c3099f | ||
|
|
c1c7ae5081 | ||
|
|
9e287f7cee | ||
|
|
a374cf4510 | ||
|
|
9ee98ff0e9 | ||
|
|
f26a1d8e83 | ||
|
|
7a62fe467b | ||
|
|
74f2c78db5 | ||
|
|
db6d416eba | ||
|
|
5f9e74f2fb | ||
|
|
bd8e139ccc | ||
|
|
61e45cb083 | ||
|
|
6983019cab | ||
|
|
54cbe83c56 | ||
|
|
20f8f89c2c | ||
|
|
4b22741255 | ||
|
|
5769d8b2de | ||
|
|
423454086e | ||
|
|
599ed98f6c | ||
|
|
f5ebac4519 | ||
|
|
3e64a42b14 |
199
.clang-format
Normal file
199
.clang-format
Normal 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
64
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal 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
6
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal 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.
|
||||
22
.github/actions/godot-cache/action.yml
vendored
Normal file
22
.github/actions/godot-cache/action.yml
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
name: Setup Godot build cache
|
||||
description: Setup Godot build cache.
|
||||
inputs:
|
||||
cache-name:
|
||||
description: The cache base name (job name by default).
|
||||
default: "${{github.job}}"
|
||||
scons-cache:
|
||||
description: The scons cache path.
|
||||
default: "${{github.workspace}}/.scons-cache/"
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
# Upload cache on completion and check it out now
|
||||
- name: Load .scons_cache directory
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{inputs.scons-cache}}
|
||||
key: ${{inputs.cache-name}}-${{env.GODOT_BASE_BRANCH}}-${{github.ref}}-${{github.sha}}
|
||||
restore-keys: |
|
||||
${{inputs.cache-name}}-${{env.GODOT_BASE_BRANCH}}-${{github.ref}}-${{github.sha}}
|
||||
${{inputs.cache-name}}-${{env.GODOT_BASE_BRANCH}}-${{github.ref}}
|
||||
${{inputs.cache-name}}-${{env.GODOT_BASE_BRANCH}}
|
||||
287
.github/workflows/build_release.yml
vendored
Normal file
287
.github/workflows/build_release.yml
vendored
Normal file
@@ -0,0 +1,287 @@
|
||||
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@v4
|
||||
|
||||
- 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_64'
|
||||
gdnative_flags: 'android_arch=x86_64'
|
||||
sconsflags: ''
|
||||
os: 'ubuntu-20.04'
|
||||
cache-name: android-x86_64
|
||||
- platform: android
|
||||
arch: 'arm64'
|
||||
gdnative_flags: 'android_arch=arm64v8'
|
||||
sconsflags: ''
|
||||
os: 'ubuntu-20.04'
|
||||
cache-name: android-arm64
|
||||
|
||||
# iOS
|
||||
- platform: ios
|
||||
arch: 'x86_64'
|
||||
gdnative_flags: 'ios_arch=x86_64'
|
||||
sconsflags: 'ios_simulator=true'
|
||||
os: 'macos-latest'
|
||||
cache-name: ios-x86_64-simulator
|
||||
- platform: ios
|
||||
arch: 'arm64'
|
||||
gdnative_flags: 'ios_arch=arm64'
|
||||
sconsflags: ''
|
||||
os: 'macos-latest'
|
||||
cache-name: ios-arm64
|
||||
|
||||
# Linux
|
||||
- platform: linux
|
||||
arch: 'x86_32'
|
||||
buildroot: 'i686-godot-linux-gnu_sdk-buildroot'
|
||||
gdnative_flags: 'bits=32'
|
||||
sconsflags: ''
|
||||
os: 'ubuntu-20.04'
|
||||
cache-name: linux-x86_32
|
||||
- platform: linux
|
||||
arch: 'x86_64'
|
||||
buildroot: 'x86_64-godot-linux-gnu_sdk-buildroot'
|
||||
gdnative_flags: 'bits=64'
|
||||
sconsflags: ''
|
||||
os: 'ubuntu-20.04'
|
||||
cache-name: linux-x86_64
|
||||
- platform: linux
|
||||
arch: 'arm32'
|
||||
buildroot: 'arm-godot-linux-gnueabihf_sdk-buildroot'
|
||||
gdnative_flags: 'bits=32'
|
||||
sconsflags: ''
|
||||
os: 'ubuntu-20.04'
|
||||
cache-name: linux-arm32
|
||||
- platform: linux
|
||||
arch: 'arm64'
|
||||
buildroot: 'aarch64-godot-linux-gnu_sdk-buildroot'
|
||||
gdnative_flags: 'bits=64'
|
||||
sconsflags: ''
|
||||
os: 'ubuntu-20.04'
|
||||
cache-name: linux-arm64
|
||||
|
||||
# macOS
|
||||
- platform: macos
|
||||
arch: 'universal'
|
||||
gdnative_flags: 'macos_arch=universal bits=64'
|
||||
sconsflags: ''
|
||||
os: 'macos-latest'
|
||||
cache-name: macos-universal
|
||||
|
||||
# Windows
|
||||
- platform: windows
|
||||
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: 'x86_64'
|
||||
gdnative_flags: 'bits=64'
|
||||
sconsflags: 'use_mingw=yes'
|
||||
os: 'ubuntu-20.04'
|
||||
msvc_arch: amd64
|
||||
cache-name: win-x86_64
|
||||
|
||||
env:
|
||||
SCONS_CACHE: ${{ github.workspace }}/.scons-cache/
|
||||
SCONSFLAGS: ${{ matrix.sconsflags }} platform=${{ matrix.platform }} arch=${{ matrix.arch }} build_profile=build_profile.json --jobs=2
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Setup Godot build cache
|
||||
uses: ./.github/actions/godot-cache
|
||||
with:
|
||||
cache-name: ${{ matrix.cache-name }}
|
||||
continue-on-error: true
|
||||
|
||||
- name: Install Windows build dependencies
|
||||
if: ${{ matrix.platform == 'windows' }}
|
||||
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: Install Linux build dependencies
|
||||
if: ${{ matrix.platform == 'linux' }}
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install build-essential gcc-multilib g++-multilib wget
|
||||
|
||||
- name: Setup Linux buildroot toolchain cache
|
||||
if: ${{ matrix.platform == 'linux' }}
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
${{ matrix.buildroot }}.tar.bz2
|
||||
key: linux-${{ matrix.buildroot }}-buildroot
|
||||
|
||||
- name: Set up Python 3.x
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.x'
|
||||
architecture: 'x64'
|
||||
|
||||
- name: Configuring Python packages
|
||||
run: |
|
||||
python -c "import sys; print(sys.version)"
|
||||
python -m pip install scons
|
||||
|
||||
- name: Setup Linux toolchains
|
||||
if: ${{ matrix.platform == 'linux' }}
|
||||
run: |
|
||||
if [ ! -f ${{ matrix.buildroot }}.tar.bz2 ]; then
|
||||
wget https://downloads.tuxfamily.org/godotengine/toolchains/linux/${{ matrix.buildroot }}.tar.bz2
|
||||
fi
|
||||
tar -xjf ${{ matrix.buildroot }}.tar.bz2
|
||||
${{ matrix.buildroot }}/relocate-sdk.sh
|
||||
echo "$GITHUB_WORKSPACE/${{ matrix.buildroot }}/bin" >> $GITHUB_PATH
|
||||
echo "PKG_CONFIG=$GITHUB_WORKSPACE/${{ matrix.buildroot }}/share/pkgconfig/" >> $GITHUB_ENV
|
||||
patch -p1 < misc/patches/scons_path.diff
|
||||
patch -p1 < misc/patches/gdnantive_arm_warnings.diff
|
||||
|
||||
- name: Patch godot-cpp to support build profile.
|
||||
run: |
|
||||
patch -p1 < misc/patches/build_profile.diff
|
||||
patch -p1 < misc/patches/build_profile_4.0.diff
|
||||
patch -p1 < misc/patches/build_profile_3.x.diff
|
||||
|
||||
- name: Print tools versions
|
||||
run: |
|
||||
python --version
|
||||
scons --version
|
||||
cmake --version
|
||||
|
||||
- name: Compile Extension (4.1+) - template_debug - ${{ matrix.platform }} - ${{ matrix.arch }}
|
||||
run: |
|
||||
scons target=template_debug godot_version=4.1
|
||||
|
||||
- name: Compile Extension (4.1+) - template_release - ${{ matrix.platform }} - ${{ matrix.arch }}
|
||||
run: |
|
||||
scons target=template_release godot_version=4.1
|
||||
|
||||
- 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@v4
|
||||
with:
|
||||
name: ${{ github.job }}-${{ matrix.platform }}-${{ matrix.arch }}
|
||||
path: |
|
||||
bin/
|
||||
!bin/thirdparty/
|
||||
|
||||
package:
|
||||
name: 📦 Package
|
||||
needs: build
|
||||
runs-on: "ubuntu-latest"
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- uses: actions/download-artifact@v4
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
ls -R release
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: godot-webrtc-extension-4.1
|
||||
path: release/*-extension-4.1-*.zip
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: godot-webrtc-extension-4.0
|
||||
path: release/*-extension-4.0-*.zip
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: godot-webrtc-gdnative
|
||||
path: release/*-gdnative-*.zip
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -4,3 +4,6 @@ bin/*
|
||||
*.lib
|
||||
.sconsign.dblite
|
||||
*.obj
|
||||
*.swp
|
||||
__pycache__/*
|
||||
*.pyc
|
||||
|
||||
15
.gitmodules
vendored
Normal file
15
.gitmodules
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
[submodule "godot-cpp"]
|
||||
path = 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
|
||||
54
README.md
54
README.md
@@ -0,0 +1,54 @@
|
||||
# GDNative WebRTC plugin for Godot
|
||||
|
||||
## Getting Started
|
||||
|
||||
| **Download latest binary version** | [**GitHub**](https://github.com/godotengine/webrtc-native/releases) |
|
||||
| --- | --- |
|
||||
|
||||
### Compiling
|
||||
|
||||
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
|
||||
```
|
||||
|
||||
If you already checked out the branch use the following commands to update the dependencies:
|
||||
|
||||
```
|
||||
$ git submodule update --init --recursive
|
||||
```
|
||||
|
||||
### Compiling the extension.
|
||||
|
||||
To build the GDExtension version of the plugin (Godot 4.1+) run the following command from the `webrtc-native` folder:
|
||||
|
||||
```
|
||||
$ scons platform=<your platform>
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
351
SConstruct
351
SConstruct
@@ -1,161 +1,258 @@
|
||||
#!python
|
||||
|
||||
import os, sys, platform, json
|
||||
import os, sys, platform, json, subprocess
|
||||
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 replace_flags(flags, replaces):
|
||||
for k, v in replaces.items():
|
||||
if k not in flags:
|
||||
continue
|
||||
if v is None:
|
||||
flags.remove(k)
|
||||
else:
|
||||
flags[flags.index(k)] = v
|
||||
|
||||
|
||||
def validate_godotcpp_dir(key, val, env):
|
||||
normalized = val if os.path.isabs(val) else os.path.join(env.Dir("#").abspath, val)
|
||||
if not os.path.isdir(normalized):
|
||||
raise UserError("GDExtension directory ('%s') does not exist: %s" % (key, val))
|
||||
|
||||
|
||||
env = Environment()
|
||||
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')))
|
||||
|
||||
# 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.Add(
|
||||
PathVariable(
|
||||
"godot_cpp",
|
||||
"Path to the directory containing Godot CPP folder",
|
||||
None,
|
||||
validate_godotcpp_dir,
|
||||
)
|
||||
)
|
||||
opts.Update(env)
|
||||
|
||||
target = env['target']
|
||||
# Minimum target platform versions.
|
||||
if "ios_min_version" not in ARGUMENTS:
|
||||
ARGUMENTS["ios_min_version"] = "12.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"
|
||||
|
||||
host_platform = platform.system()
|
||||
target_platform = ARGUMENTS.get('p', ARGUMENTS.get('platform', 'linux'))
|
||||
target_arch = ARGUMENTS.get('a', ARGUMENTS.get('arch', '64'))
|
||||
# Local dependency paths, adapt them to your setup
|
||||
godot_headers = ARGUMENTS.get('headers', '../godot_headers')
|
||||
godot_cpp_headers = ARGUMENTS.get('godot_cpp_headers', '../godot-cpp/include')
|
||||
godot_cpp_lib_dir = ARGUMENTS.get('godot_cpp_lib_dir', 'lib/godot-cpp')
|
||||
result_path = 'bin'
|
||||
result_name = 'webrtc_native'
|
||||
# Recent godot-cpp versions disables exceptions by default, but libdatachannel requires them.
|
||||
ARGUMENTS["disable_exceptions"] = "no"
|
||||
|
||||
# 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
|
||||
if env["godot_version"] == "3":
|
||||
if "platform" in ARGUMENTS and ARGUMENTS["platform"] == "macos":
|
||||
ARGUMENTS["platform"] = "osx" # compatibility with old osx name
|
||||
|
||||
if target_platform == 'linux':
|
||||
result_name += '.linux.' + target + '.' + target_arch
|
||||
sconstruct = env.get("godot_cpp", "godot-cpp-3.x") + "/SConstruct"
|
||||
cpp_env = SConscript(sconstruct)
|
||||
|
||||
env['CXX']='g++'
|
||||
# Patch base env
|
||||
replace_flags(
|
||||
cpp_env["CCFLAGS"],
|
||||
{
|
||||
"-mios-simulator-version-min=10.0": "-mios-simulator-version-min=12.0",
|
||||
"-miphoneos-version-min=10.0": "-miphoneos-version-min=12.0",
|
||||
"/std:c++14": "/std:c++17",
|
||||
"-std=c++14": "-std=c++17",
|
||||
},
|
||||
)
|
||||
|
||||
# LLVM
|
||||
if env['use_llvm']:
|
||||
if ('clang++' not in os.path.basename(env['CXX'])):
|
||||
env['CC'] = 'clang'
|
||||
env["CXX"] = "clang++"
|
||||
env["LINK"] = "clang++"
|
||||
env = cpp_env.Clone()
|
||||
|
||||
if (env["target"] == "debug"):
|
||||
env.Prepend(CCFLAGS=['-g3'])
|
||||
env.Append(LINKFLAGS=['-rdynamic'])
|
||||
else:
|
||||
env.Prepend(CCFLAGS=['-O3'])
|
||||
if env["target"] == "debug":
|
||||
env.Append(CPPDEFINES=["DEBUG_ENABLED"])
|
||||
|
||||
env.Append(CCFLAGS=['-fPIC', '-std=c++11'])
|
||||
if env["platform"] == "windows" and env["use_mingw"]:
|
||||
env.Append(LINKFLAGS=["-static-libgcc"])
|
||||
|
||||
if target_arch == '32':
|
||||
env.Append(CCFLAGS = [ '-m32' ])
|
||||
env.Append(LINKFLAGS = [ '-m32' ])
|
||||
elif target_arch == '64':
|
||||
env.Append(CCFLAGS = [ '-m64' ])
|
||||
env.Append(LINKFLAGS = [ '-m64' ])
|
||||
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".
|
||||
|
||||
elif 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')
|
||||
if env["platform"] == "ios":
|
||||
env["ios_min_version"] = "12.0"
|
||||
|
||||
result_name += '.windows.' + target + '.' + target_arch
|
||||
# Normalize suffix
|
||||
if env["platform"] in ["windows", "linux"]:
|
||||
env["arch"] = ARGUMENTS.get("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"]
|
||||
|
||||
if host_platform == 'Windows':
|
||||
#result_name += '.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++'
|
||||
|
||||
env.Append(CCFLAGS = [ '-g', '-O3', '-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'
|
||||
result_name += '.osx.' + target + '.' + target_arch
|
||||
|
||||
env.Append(CCFLAGS = [ '-g','-O3', '-std=c++14', '-arch', 'x86_64' ])
|
||||
env.Append(LINKFLAGS = [ '-arch', 'x86_64', '-framework', 'Cocoa', '-Wl,-undefined,dynamic_lookup' ])
|
||||
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
|
||||
# Some linux specific hacks to allow cross-compiling for non-x86 machines.
|
||||
if env["platform"] == "linux" and env["arch"] not in ("x86_32", "x86_64"):
|
||||
for flags in (env["CCFLAGS"], env["LINKFLAGS"], cpp_env["CCFLAGS"], cpp_env["LINKFLAGS"]):
|
||||
replace_flags(flags, {"-m32": None, "-m64": None})
|
||||
elif env["godot_version"] == "4.0":
|
||||
sconstruct = env.get("godot_cpp", "godot-cpp-4.0") + "/SConstruct"
|
||||
cpp_env = SConscript(sconstruct)
|
||||
env = cpp_env.Clone()
|
||||
else:
|
||||
print("No valid target platform selected.")
|
||||
sys.exit(1)
|
||||
sconstruct = env.get("godot_cpp", "godot-cpp") + "/SConstruct"
|
||||
cpp_env = SConscript(sconstruct)
|
||||
env = cpp_env.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 + '/' + target])
|
||||
env.Append(LIBS=['godot-cpp'])
|
||||
if cpp_env.get("is_msvc", False):
|
||||
# Make sure we don't build with static cpp on MSVC (default in recent godot-cpp versions).
|
||||
replace_flags(env["CCFLAGS"], {"/MT": "/MD"})
|
||||
replace_flags(cpp_env["CCFLAGS"], {"/MT": "/MD"})
|
||||
|
||||
# WebRTC stuff
|
||||
webrtc_dir = "lib/webrtc"
|
||||
lib_name = 'libwebrtc_full'
|
||||
lib_path = webrtc_dir + '/lib/' + target_platform
|
||||
# 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"]
|
||||
|
||||
if target_arch == '64':
|
||||
lib_path += '/x64'
|
||||
elif target_arch == '32':
|
||||
lib_path += '/x86'
|
||||
# Patch mingw SHLIBSUFFIX.
|
||||
if env["platform"] == "windows" and env["use_mingw"]:
|
||||
env["SHLIBSUFFIX"] = ".dll"
|
||||
|
||||
if target == 'debug':
|
||||
lib_path += '/Debug'
|
||||
# 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"]
|
||||
|
||||
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"])
|
||||
|
||||
if target_platform == "linux":
|
||||
env.Append(LIBS=[lib_name])
|
||||
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])
|
||||
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"])
|
||||
|
||||
# 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)
|
||||
|
||||
# We want to statically link against libstdc++ on Linux to maximize compatibility, but we must restrict the exported
|
||||
# symbols using a GCC version script, or we might end up overriding symbols from other libraries.
|
||||
# Using "-fvisibility=hidden" will not work, since libstdc++ explicitly exports its symbols.
|
||||
symbols_file = None
|
||||
if env["platform"] == "linux" or (
|
||||
env["platform"] == "windows" and env.get("use_mingw", False) and not env.get("use_llvm", False)
|
||||
):
|
||||
if env["godot_version"] == "3":
|
||||
symbols_file = env.File("misc/gcc/symbols-gdnative.map")
|
||||
else:
|
||||
symbols_file = env.File("misc/gcc/symbols-extension.map")
|
||||
env.Append(
|
||||
LINKFLAGS=[
|
||||
"-Wl,--no-undefined,--version-script=" + symbols_file.abspath,
|
||||
"-static-libgcc",
|
||||
"-static-libstdc++",
|
||||
]
|
||||
)
|
||||
env.Depends(sources, symbols_file)
|
||||
|
||||
# Make the shared library
|
||||
library = env.SharedLibrary(target=os.path.join(result_path, result_name), source=sources)
|
||||
result_name = "libwebrtc_native{}{}".format(env["suffix"], env["SHLIBSUFFIX"])
|
||||
if env["godot_version"] != "3" and env["platform"] == "macos":
|
||||
framework_path = os.path.join(
|
||||
result_path, "lib", "libwebrtc_native.macos.{}.{}.framework".format(env["target"], env["arch"])
|
||||
)
|
||||
library_file = env.SharedLibrary(target=os.path.join(framework_path, result_name), source=sources)
|
||||
plist_file = env.Substfile(
|
||||
os.path.join(framework_path, "Resources", "Info.plist"),
|
||||
"misc/dist/macos/Info.plist",
|
||||
SUBST_DICT={"{LIBRARY_NAME}": result_name, "{DISPLAY_NAME}": "libwebrtc_native" + env["suffix"]},
|
||||
)
|
||||
library = [library_file, plist_file]
|
||||
else:
|
||||
library = env.SharedLibrary(target=os.path.join(result_path, "lib", result_name), source=sources)
|
||||
|
||||
Default(library)
|
||||
|
||||
# GDNativeLibrary
|
||||
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)
|
||||
|
||||
11
build_profile.json
Normal file
11
build_profile.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"enabled_classes": [
|
||||
"WebRTCDataChannelExtension",
|
||||
"WebRTCPeerConnectionExtension",
|
||||
"WebRTCDataChannelGDNative",
|
||||
"WebRTCPeerConnectionGDNative",
|
||||
"NativeScript",
|
||||
"GDNativeLibrary",
|
||||
"Window"
|
||||
]
|
||||
}
|
||||
1
godot-cpp
Submodule
1
godot-cpp
Submodule
Submodule godot-cpp added at d627942b64
1
godot-cpp-3.x
Submodule
1
godot-cpp-3.x
Submodule
Submodule godot-cpp-3.x added at 7c09b5484d
1
godot-cpp-4.0
Submodule
1
godot-cpp-4.0
Submodule
Submodule godot-cpp-4.0 added at 9d1c396c54
2
lib/godot-cpp/release/.gitignore
vendored
2
lib/godot-cpp/release/.gitignore
vendored
@@ -1,2 +0,0 @@
|
||||
*
|
||||
!.gitignore
|
||||
1
lib/webrtc/.gitignore
vendored
1
lib/webrtc/.gitignore
vendored
@@ -1 +0,0 @@
|
||||
include/
|
||||
2
lib/webrtc/lib/linux/.gitignore
vendored
2
lib/webrtc/lib/linux/.gitignore
vendored
@@ -1,2 +0,0 @@
|
||||
*
|
||||
!.gitignore
|
||||
2
lib/webrtc/lib/windows/.gitignore
vendored
2
lib/webrtc/lib/windows/.gitignore
vendored
@@ -1,2 +0,0 @@
|
||||
*
|
||||
!.gitignore
|
||||
28
misc/dist/macos/Info.plist
vendored
Normal file
28
misc/dist/macos/Info.plist
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>{LIBRARY_NAME}</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.godotengine.webrtc-native</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>{DISPLAY_NAME}</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>webrtc_native</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0.0</string>
|
||||
<key>CFBundleSupportedPlatforms</key>
|
||||
<array>
|
||||
<string>MacOSX</string>
|
||||
</array>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.0.0</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>11.0</string>
|
||||
</dict>
|
||||
</plist>
|
||||
6
misc/gcc/symbols-extension.map
Normal file
6
misc/gcc/symbols-extension.map
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
global:
|
||||
webrtc_extension_init;
|
||||
local:
|
||||
*;
|
||||
};
|
||||
9
misc/gcc/symbols-gdnative.map
Normal file
9
misc/gcc/symbols-gdnative.map
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
global:
|
||||
godot_gdnative_singleton;
|
||||
godot_gdnative_init;
|
||||
godot_gdnative_terminate;
|
||||
godot_nativescript_init;
|
||||
local:
|
||||
*;
|
||||
};
|
||||
238
misc/patches/build_profile.diff
Normal file
238
misc/patches/build_profile.diff
Normal file
@@ -0,0 +1,238 @@
|
||||
diff --git a/godot-cpp/SConstruct b/godot-cpp/SConstruct
|
||||
index 42f8fc0..9d59d1f 100644
|
||||
--- a/godot-cpp/SConstruct
|
||||
+++ b/godot-cpp/SConstruct
|
||||
@@ -121,6 +121,14 @@ opts.Add(
|
||||
BoolVariable("generate_bindings", "Force GDExtension API bindings generation. Auto-detected by default.", False)
|
||||
)
|
||||
opts.Add(BoolVariable("generate_template_get_node", "Generate a template version of the Node class's get_node.", True))
|
||||
+opts.Add(
|
||||
+ PathVariable(
|
||||
+ "build_profile",
|
||||
+ "Path to a file containing a feature build profile",
|
||||
+ default=env.get("build_profile", None),
|
||||
+ validator=lambda key, val, env: os.path.isfile(normalize_path(val)),
|
||||
+ )
|
||||
+)
|
||||
|
||||
opts.Add(BoolVariable("build_library", "Build the godot-cpp library.", True))
|
||||
opts.Add(EnumVariable("precision", "Set the floating-point precision level", "single", ("single", "double")))
|
||||
diff --git a/godot-cpp/binding_generator.py b/godot-cpp/binding_generator.py
|
||||
index d04c698..41cf29b 100644
|
||||
--- a/godot-cpp/binding_generator.py
|
||||
+++ b/godot-cpp/binding_generator.py
|
||||
@@ -70,12 +70,14 @@ def generate_wrappers(target):
|
||||
f.write(txt)
|
||||
|
||||
|
||||
-def get_file_list(api_filepath, output_dir, headers=False, sources=False):
|
||||
+def get_file_list(api_filepath, output_dir, headers=False, sources=False, profile_filepath=""):
|
||||
api = {}
|
||||
files = []
|
||||
with open(api_filepath, encoding="utf-8") as api_file:
|
||||
api = json.load(api_file)
|
||||
|
||||
+ build_profile = parse_build_profile(profile_filepath, api)
|
||||
+
|
||||
core_gen_folder = Path(output_dir) / "gen" / "include" / "godot_cpp" / "core"
|
||||
include_gen_folder = Path(output_dir) / "gen" / "include" / "godot_cpp"
|
||||
source_gen_folder = Path(output_dir) / "gen" / "src"
|
||||
@@ -104,7 +106,7 @@ def get_file_list(api_filepath, output_dir, headers=False, sources=False):
|
||||
source_filename = source_gen_folder / "classes" / (camel_to_snake(engine_class["name"]) + ".cpp")
|
||||
if headers:
|
||||
files.append(str(header_filename.as_posix()))
|
||||
- if sources:
|
||||
+ if sources and is_class_included(engine_class["name"], build_profile):
|
||||
files.append(str(source_filename.as_posix()))
|
||||
|
||||
for native_struct in api["native_structures"]:
|
||||
@@ -134,14 +136,107 @@ def get_file_list(api_filepath, output_dir, headers=False, sources=False):
|
||||
return files
|
||||
|
||||
|
||||
-def print_file_list(api_filepath, output_dir, headers=False, sources=False):
|
||||
+def print_file_list(api_filepath, output_dir, headers=False, sources=False, profile_filepath=""):
|
||||
end = ";"
|
||||
- for f in get_file_list(api_filepath, output_dir, headers, sources):
|
||||
+ for f in get_file_list(api_filepath, output_dir, headers, sources, profile_filepath):
|
||||
print(f, end=end)
|
||||
|
||||
|
||||
+def parse_build_profile(profile_filepath, api):
|
||||
+ if profile_filepath == "":
|
||||
+ return {}
|
||||
+ print("Using feature build profile: " + profile_filepath)
|
||||
+
|
||||
+ with open(profile_filepath, encoding="utf-8") as profile_file:
|
||||
+ profile = json.load(profile_file)
|
||||
+
|
||||
+ api_dict = {}
|
||||
+ parents = {}
|
||||
+ children = {}
|
||||
+ for engine_class in api["classes"]:
|
||||
+ api_dict[engine_class["name"]] = engine_class
|
||||
+ parent = engine_class.get("inherits", "")
|
||||
+ child = engine_class["name"]
|
||||
+ parents[child] = parent
|
||||
+ if parent == "":
|
||||
+ continue
|
||||
+ children[parent] = children.get(parent, [])
|
||||
+ children[parent].append(child)
|
||||
+
|
||||
+ # Parse methods dependencies
|
||||
+ deps = {}
|
||||
+ reverse_deps = {}
|
||||
+ for name, engine_class in api_dict.items():
|
||||
+ ref_cls = set()
|
||||
+ for method in engine_class.get("methods", []):
|
||||
+ rtype = method.get("return_value", {}).get("type", "")
|
||||
+ args = [a["type"] for a in method.get("arguments", [])]
|
||||
+ if rtype in api_dict:
|
||||
+ ref_cls.add(rtype)
|
||||
+ elif is_enum(rtype) and get_enum_class(rtype) in api_dict:
|
||||
+ ref_cls.add(get_enum_class(rtype))
|
||||
+ for arg in args:
|
||||
+ if arg in api_dict:
|
||||
+ ref_cls.add(arg)
|
||||
+ elif is_enum(arg) and get_enum_class(arg) in api_dict:
|
||||
+ ref_cls.add(get_enum_class(arg))
|
||||
+ deps[engine_class["name"]] = set(filter(lambda x: x != name, ref_cls))
|
||||
+ for acls in ref_cls:
|
||||
+ if acls == name:
|
||||
+ continue
|
||||
+ reverse_deps[acls] = reverse_deps.get(acls, set())
|
||||
+ reverse_deps[acls].add(name)
|
||||
+
|
||||
+ included = []
|
||||
+ front = list(profile.get("enabled_classes", []))
|
||||
+ if front:
|
||||
+ # These must always be included
|
||||
+ front.append("WorkerThreadPool")
|
||||
+ front.append("ClassDB")
|
||||
+ front.append("ClassDBSingleton")
|
||||
+ while front:
|
||||
+ cls = front.pop()
|
||||
+ if cls in included:
|
||||
+ continue
|
||||
+ included.append(cls)
|
||||
+ parent = parents.get(cls, "")
|
||||
+ if parent:
|
||||
+ front.append(parent)
|
||||
+ for rcls in deps.get(cls, set()):
|
||||
+ if rcls in included or rcls in front:
|
||||
+ continue
|
||||
+ front.append(rcls)
|
||||
+
|
||||
+ excluded = []
|
||||
+ front = list(profile.get("disabled_classes", []))
|
||||
+ while front:
|
||||
+ cls = front.pop()
|
||||
+ if cls in excluded:
|
||||
+ continue
|
||||
+ excluded.append(cls)
|
||||
+ front += children.get(cls, [])
|
||||
+ for rcls in reverse_deps.get(cls, set()):
|
||||
+ if rcls in excluded or rcls in front:
|
||||
+ continue
|
||||
+ front.append(rcls)
|
||||
+
|
||||
+ if included and excluded:
|
||||
+ print(
|
||||
+ "WARNING: Cannot specify both 'enabled_classes' and 'disabled_classes' in build profile. 'disabled_classes' will be ignored."
|
||||
+ )
|
||||
+
|
||||
+ return {
|
||||
+ "enabled_classes": included,
|
||||
+ "disabled_classes": excluded,
|
||||
+ }
|
||||
+
|
||||
+
|
||||
def scons_emit_files(target, source, env):
|
||||
- files = [env.File(f) for f in get_file_list(str(source[0]), target[0].abspath, True, True)]
|
||||
+ profile_filepath = env.get("build_profile", "")
|
||||
+ if profile_filepath and not Path(profile_filepath).is_absolute():
|
||||
+ profile_filepath = str((Path(env.Dir("#").abspath) / profile_filepath).as_posix())
|
||||
+
|
||||
+ files = [env.File(f) for f in get_file_list(str(source[0]), target[0].abspath, True, True, profile_filepath)]
|
||||
env.Clean(target, files)
|
||||
env["godot_cpp_gen_dir"] = target[0].abspath
|
||||
return files, source
|
||||
@@ -154,11 +249,12 @@ def scons_generate_bindings(target, source, env):
|
||||
"32" if "32" in env["arch"] else "64",
|
||||
env["precision"],
|
||||
env["godot_cpp_gen_dir"],
|
||||
+ env.get("build_profile", ""),
|
||||
)
|
||||
return None
|
||||
|
||||
|
||||
-def generate_bindings(api_filepath, use_template_get_node, bits="64", precision="single", output_dir="."):
|
||||
+def generate_bindings(api_filepath, use_template_get_node, bits="64", precision="single", output_dir=".", profile_filepath=""):
|
||||
api = None
|
||||
|
||||
target_dir = Path(output_dir) / "gen"
|
||||
@@ -175,7 +271,7 @@ def generate_bindings(api_filepath, use_template_get_node, bits="64", precision=
|
||||
generate_global_constants(api, target_dir)
|
||||
generate_global_constant_binds(api, target_dir)
|
||||
generate_builtin_bindings(api, target_dir, real_t + "_" + bits)
|
||||
- generate_engine_classes_bindings(api, target_dir, use_template_get_node)
|
||||
+ generate_engine_classes_bindings(api, target_dir, use_template_get_node, profile_filepath)
|
||||
generate_utility_functions(api, target_dir)
|
||||
|
||||
|
||||
@@ -1023,7 +1119,7 @@ def generate_builtin_class_source(builtin_api, size, used_classes, fully_used_cl
|
||||
return "\n".join(result)
|
||||
|
||||
|
||||
-def generate_engine_classes_bindings(api, output_dir, use_template_get_node):
|
||||
+def generate_engine_classes_bindings(api, output_dir, use_template_get_node, profile_filepath=""):
|
||||
global engine_classes
|
||||
global singletons
|
||||
global native_structures
|
||||
@@ -1161,7 +1257,7 @@ def generate_engine_classes_bindings(api, output_dir, use_template_get_node):
|
||||
|
||||
register_engine_classes_filename = Path(output_dir) / "src" / "register_engine_classes.cpp"
|
||||
with register_engine_classes_filename.open("w+", encoding="utf-8") as source_file:
|
||||
- source_file.write(generate_register_engine_classes_source(api))
|
||||
+ source_file.write(generate_register_engine_classes_source(api, profile_filepath))
|
||||
|
||||
for native_struct in api["native_structures"]:
|
||||
struct_name = native_struct["name"]
|
||||
@@ -1585,12 +1681,14 @@ def generate_engine_class_source(class_api, used_classes, fully_used_classes, us
|
||||
return "\n".join(result)
|
||||
|
||||
|
||||
-def generate_register_engine_classes_source(api):
|
||||
+def generate_register_engine_classes_source(api, profile_filepath=""):
|
||||
includes = []
|
||||
registrations = []
|
||||
|
||||
+ build_profile = parse_build_profile(profile_filepath, api)
|
||||
+
|
||||
for class_api in api["classes"]:
|
||||
- if class_api["name"] == "ClassDB":
|
||||
+ if class_api["name"] == "ClassDB" or not is_class_included(class_api["name"], build_profile):
|
||||
continue
|
||||
|
||||
class_name = class_api["name"]
|
||||
@@ -2066,6 +2164,20 @@ def is_pod_type(type_name):
|
||||
]
|
||||
|
||||
|
||||
+def is_class_included(class_name, build_profile):
|
||||
+ """
|
||||
+ Check if an engine class should be included.
|
||||
+ This removes classes according to a build profile of enabled or disabled classes.
|
||||
+ """
|
||||
+ included = build_profile.get("enabled_classes", [])
|
||||
+ excluded = build_profile.get("disabled_classes", [])
|
||||
+ if included:
|
||||
+ return class_name in included
|
||||
+ if excluded:
|
||||
+ return class_name not in excluded
|
||||
+ return True
|
||||
+
|
||||
+
|
||||
def is_included_type(type_name):
|
||||
# Types which we already have implemented.
|
||||
return is_included_struct_type(type_name) or type_name in ["ObjectID"]
|
||||
196
misc/patches/build_profile_3.x.diff
Normal file
196
misc/patches/build_profile_3.x.diff
Normal file
@@ -0,0 +1,196 @@
|
||||
diff --git a/godot-cpp-3.x/SConstruct b/godot-cpp-3.x/SConstruct
|
||||
index f653d54..44f66a5 100644
|
||||
--- a/godot-cpp-3.x/SConstruct
|
||||
+++ b/godot-cpp-3.x/SConstruct
|
||||
@@ -170,6 +170,14 @@ opts.Add(
|
||||
True,
|
||||
)
|
||||
)
|
||||
+opts.Add(
|
||||
+ PathVariable(
|
||||
+ "build_profile",
|
||||
+ "Path to a file containing a feature build profile",
|
||||
+ default=env.get("build_profile", None),
|
||||
+ validator=lambda key, val, env: val if os.path.isabs(val) else os.path.join(env.Dir("#").abspath, val),
|
||||
+ )
|
||||
+)
|
||||
|
||||
opts.Add(BoolVariable("build_library", "Build the godot-cpp library.", True))
|
||||
|
||||
diff --git a/godot-cpp-3.x/binding_generator.py b/godot-cpp-3.x/binding_generator.py
|
||||
index da4bb61..e5bd040 100644
|
||||
--- a/godot-cpp-3.x/binding_generator.py
|
||||
+++ b/godot-cpp-3.x/binding_generator.py
|
||||
@@ -12,14 +12,115 @@ def correct_method_name(method_list):
|
||||
method["name"] = "get_node_internal"
|
||||
|
||||
|
||||
+def is_class_included(class_name, build_profile):
|
||||
+ """
|
||||
+ Check if an engine class should be included.
|
||||
+ This removes classes according to a build profile of enabled or disabled classes.
|
||||
+ """
|
||||
+ included = build_profile.get("enabled_classes", [])
|
||||
+ excluded = build_profile.get("disabled_classes", [])
|
||||
+ if included:
|
||||
+ return class_name in included
|
||||
+ if excluded:
|
||||
+ return class_name not in excluded
|
||||
+ return True
|
||||
+
|
||||
+
|
||||
+def parse_build_profile(profile_filepath, api):
|
||||
+ if profile_filepath == "":
|
||||
+ return {}
|
||||
+ print("Using feature build profile: " + profile_filepath)
|
||||
+
|
||||
+ with open(profile_filepath, encoding="utf-8") as profile_file:
|
||||
+ profile = json.load(profile_file)
|
||||
+
|
||||
+ api_dict = {}
|
||||
+ parents = {}
|
||||
+ children = {}
|
||||
+ for engine_class in api:
|
||||
+ api_dict[engine_class["name"]] = engine_class
|
||||
+ parent = engine_class.get("base_class", "")
|
||||
+ child = engine_class["name"]
|
||||
+ parents[child] = parent
|
||||
+ if parent == "":
|
||||
+ continue
|
||||
+ children[parent] = children.get(parent, [])
|
||||
+ children[parent].append(child)
|
||||
+
|
||||
+ # Parse methods dependencies
|
||||
+ deps = {}
|
||||
+ reverse_deps = {}
|
||||
+ for name, engine_class in api_dict.items():
|
||||
+ ref_cls = set()
|
||||
+ for method in engine_class.get("methods", []):
|
||||
+ rtype = method.get("return_value", {}).get("type", "")
|
||||
+ args = [a["type"] for a in method.get("arguments", [])]
|
||||
+ if rtype in api_dict:
|
||||
+ ref_cls.add(rtype)
|
||||
+ for arg in args:
|
||||
+ if arg in api_dict:
|
||||
+ ref_cls.add(arg)
|
||||
+ deps[engine_class["name"]] = set(filter(lambda x: x != name, ref_cls))
|
||||
+ for acls in ref_cls:
|
||||
+ if acls == name:
|
||||
+ continue
|
||||
+ reverse_deps[acls] = reverse_deps.get(acls, set())
|
||||
+ reverse_deps[acls].add(name)
|
||||
+
|
||||
+ included = []
|
||||
+ front = list(profile.get("enabled_classes", []))
|
||||
+ if front:
|
||||
+ # These must always be included
|
||||
+ front.append("ConfigFile")
|
||||
+ front.append("ClassDB")
|
||||
+ while front:
|
||||
+ cls = front.pop()
|
||||
+ if cls in included:
|
||||
+ continue
|
||||
+ included.append(cls)
|
||||
+ parent = parents.get(cls, "")
|
||||
+ if parent:
|
||||
+ front.append(parent)
|
||||
+ for rcls in deps.get(cls, set()):
|
||||
+ if rcls in included or rcls in front:
|
||||
+ continue
|
||||
+ front.append(rcls)
|
||||
+
|
||||
+ excluded = []
|
||||
+ front = list(profile.get("disabled_classes", []))
|
||||
+ while front:
|
||||
+ cls = front.pop()
|
||||
+ if cls in excluded:
|
||||
+ continue
|
||||
+ excluded.append(cls)
|
||||
+ front += children.get(cls, [])
|
||||
+ for rcls in reverse_deps.get(cls, set()):
|
||||
+ if rcls in excluded or rcls in front:
|
||||
+ continue
|
||||
+ front.append(rcls)
|
||||
+
|
||||
+ if included and excluded:
|
||||
+ print(
|
||||
+ "WARNING: Cannot specify both 'enabled_classes' and 'disabled_classes' in build profile. 'disabled_classes' will be ignored."
|
||||
+ )
|
||||
+
|
||||
+ return {
|
||||
+ "enabled_classes": included,
|
||||
+ "disabled_classes": excluded,
|
||||
+ }
|
||||
+
|
||||
+
|
||||
classes = []
|
||||
|
||||
|
||||
-def get_file_list(api_filepath, output_dir, headers=False, sources=False):
|
||||
+def get_file_list(api_filepath, output_dir, headers=False, sources=False, profile_filepath=""):
|
||||
global classes
|
||||
+
|
||||
files = []
|
||||
with open(api_filepath) as api_file:
|
||||
classes = json.load(api_file)
|
||||
+ build_profile = parse_build_profile(profile_filepath, classes)
|
||||
+
|
||||
include_gen_folder = Path(output_dir) / "include" / "gen"
|
||||
source_gen_folder = Path(output_dir) / "src" / "gen"
|
||||
for _class in classes:
|
||||
@@ -27,7 +128,7 @@ def get_file_list(api_filepath, output_dir, headers=False, sources=False):
|
||||
source_filename = source_gen_folder / (strip_name(_class["name"]) + ".cpp")
|
||||
if headers:
|
||||
files.append(str(header_filename.as_posix()))
|
||||
- if sources:
|
||||
+ if sources and is_class_included(_class["name"], build_profile):
|
||||
files.append(str(source_filename.as_posix()))
|
||||
icall_header_filename = include_gen_folder / "__icalls.hpp"
|
||||
register_types_filename = source_gen_folder / "__register_types.cpp"
|
||||
@@ -40,27 +141,32 @@ def get_file_list(api_filepath, output_dir, headers=False, sources=False):
|
||||
return files
|
||||
|
||||
|
||||
-def print_file_list(api_filepath, output_dir, headers=False, sources=False):
|
||||
- for f in get_file_list(api_filepath, output_dir, headers, sources):
|
||||
+def print_file_list(api_filepath, output_dir, headers=False, sources=False, profile_filepath=""):
|
||||
+ for f in get_file_list(api_filepath, output_dir, headers, sources, profile_filepath):
|
||||
print(f, end=";")
|
||||
|
||||
|
||||
def scons_emit_files(target, source, env):
|
||||
- files = [env.File(f) for f in get_file_list(str(source[0]), target[0].abspath, True, True)]
|
||||
+ profile_filepath = env.get("build_profile", "")
|
||||
+ if profile_filepath and not Path(profile_filepath).is_absolute():
|
||||
+ profile_filepath = str((Path(env.Dir("#").abspath) / profile_filepath).as_posix())
|
||||
+
|
||||
+ files = [env.File(f) for f in get_file_list(str(source[0]), target[0].abspath, True, True, profile_filepath)]
|
||||
env.Clean(target, files)
|
||||
env["godot_cpp_gen_dir"] = target[0].abspath
|
||||
return files, source
|
||||
|
||||
|
||||
def scons_generate_bindings(target, source, env):
|
||||
- generate_bindings(str(source[0]), env["generate_template_get_node"], env["godot_cpp_gen_dir"])
|
||||
+ generate_bindings(str(source[0]), env["generate_template_get_node"], env["godot_cpp_gen_dir"], env["build_profile"])
|
||||
return None
|
||||
|
||||
|
||||
-def generate_bindings(api_filepath, use_template_get_node, output_dir="."):
|
||||
+def generate_bindings(api_filepath, use_template_get_node, output_dir=".", profile_filepath=""):
|
||||
global classes
|
||||
with open(api_filepath) as api_file:
|
||||
classes = json.load(api_file)
|
||||
+ build_profile = parse_build_profile(profile_filepath, classes)
|
||||
|
||||
icalls = set()
|
||||
include_gen_folder = Path(output_dir) / "include" / "gen"
|
||||
@@ -97,7 +203,7 @@ def generate_bindings(api_filepath, use_template_get_node, output_dir="."):
|
||||
|
||||
init_method_bindings_filename = source_gen_folder / "__init_method_bindings.cpp"
|
||||
with init_method_bindings_filename.open("w+") as init_method_bindings_file:
|
||||
- init_method_bindings_file.write(generate_init_method_bindings(classes))
|
||||
+ init_method_bindings_file.write(generate_init_method_bindings(list(filter(lambda x: is_class_included(x["name"], build_profile), classes))))
|
||||
|
||||
|
||||
def is_reference_type(t):
|
||||
180
misc/patches/build_profile_4.0.diff
Normal file
180
misc/patches/build_profile_4.0.diff
Normal file
@@ -0,0 +1,180 @@
|
||||
diff --git a/godot-cpp-4.0/SConstruct b/godot-cpp-4.0/SConstruct
|
||||
index 27ee137..ec2af72 100644
|
||||
--- a/godot-cpp-4.0/SConstruct
|
||||
+++ b/godot-cpp-4.0/SConstruct
|
||||
@@ -119,6 +119,14 @@ opts.Add(
|
||||
opts.Add(
|
||||
BoolVariable("generate_bindings", "Force GDExtension API bindings generation. Auto-detected by default.", False)
|
||||
)
|
||||
+opts.Add(
|
||||
+ PathVariable(
|
||||
+ "build_profile",
|
||||
+ "Path to a file containing a feature build profile",
|
||||
+ default=env.get("build_profile", None),
|
||||
+ validator=lambda key, val, env: os.path.isfile(normalize_path(val)),
|
||||
+ )
|
||||
+)
|
||||
opts.Add(BoolVariable("generate_template_get_node", "Generate a template version of the Node class's get_node.", True))
|
||||
|
||||
opts.Add(BoolVariable("build_library", "Build the godot-cpp library.", True))
|
||||
diff --git a/godot-cpp-4.0/binding_generator.py b/godot-cpp-4.0/binding_generator.py
|
||||
index 7634942..7ab51a5 100644
|
||||
--- a/godot-cpp-4.0/binding_generator.py
|
||||
+++ b/godot-cpp-4.0/binding_generator.py
|
||||
@@ -70,12 +70,14 @@ def generate_wrappers(target):
|
||||
f.write(txt)
|
||||
|
||||
|
||||
-def get_file_list(api_filepath, output_dir, headers=False, sources=False):
|
||||
+def get_file_list(api_filepath, output_dir, headers=False, sources=False, profile_filepath=""):
|
||||
api = {}
|
||||
files = []
|
||||
with open(api_filepath) as api_file:
|
||||
api = json.load(api_file)
|
||||
|
||||
+ build_profile = parse_build_profile(profile_filepath, api)
|
||||
+
|
||||
core_gen_folder = Path(output_dir) / "gen" / "include" / "godot_cpp" / "core"
|
||||
include_gen_folder = Path(output_dir) / "gen" / "include" / "godot_cpp"
|
||||
source_gen_folder = Path(output_dir) / "gen" / "src"
|
||||
@@ -104,7 +106,7 @@ def get_file_list(api_filepath, output_dir, headers=False, sources=False):
|
||||
source_filename = source_gen_folder / "classes" / (camel_to_snake(engine_class["name"]) + ".cpp")
|
||||
if headers:
|
||||
files.append(str(header_filename.as_posix()))
|
||||
- if sources:
|
||||
+ if sources and is_class_included(engine_class["name"], build_profile):
|
||||
files.append(str(source_filename.as_posix()))
|
||||
|
||||
for native_struct in api["native_structures"]:
|
||||
@@ -132,14 +134,107 @@ def get_file_list(api_filepath, output_dir, headers=False, sources=False):
|
||||
return files
|
||||
|
||||
|
||||
-def print_file_list(api_filepath, output_dir, headers=False, sources=False):
|
||||
+def print_file_list(api_filepath, output_dir, headers=False, sources=False, profile_filepath=""):
|
||||
end = ";"
|
||||
- for f in get_file_list(api_filepath, output_dir, headers, sources):
|
||||
+ for f in get_file_list(api_filepath, output_dir, headers, sources, profile_filepath):
|
||||
print(f, end=end)
|
||||
|
||||
|
||||
+def parse_build_profile(profile_filepath, api):
|
||||
+ if profile_filepath == "":
|
||||
+ return {}
|
||||
+ print("Using feature build profile: " + profile_filepath)
|
||||
+
|
||||
+ with open(profile_filepath, encoding="utf-8") as profile_file:
|
||||
+ profile = json.load(profile_file)
|
||||
+
|
||||
+ api_dict = {}
|
||||
+ parents = {}
|
||||
+ children = {}
|
||||
+ for engine_class in api["classes"]:
|
||||
+ api_dict[engine_class["name"]] = engine_class
|
||||
+ parent = engine_class.get("inherits", "")
|
||||
+ child = engine_class["name"]
|
||||
+ parents[child] = parent
|
||||
+ if parent == "":
|
||||
+ continue
|
||||
+ children[parent] = children.get(parent, [])
|
||||
+ children[parent].append(child)
|
||||
+
|
||||
+ # Parse methods dependencies
|
||||
+ deps = {}
|
||||
+ reverse_deps = {}
|
||||
+ for name, engine_class in api_dict.items():
|
||||
+ ref_cls = set()
|
||||
+ for method in engine_class.get("methods", []):
|
||||
+ rtype = method.get("return_value", {}).get("type", "")
|
||||
+ args = [a["type"] for a in method.get("arguments", [])]
|
||||
+ if rtype in api_dict:
|
||||
+ ref_cls.add(rtype)
|
||||
+ elif is_enum(rtype) and get_enum_class(rtype) in api_dict:
|
||||
+ ref_cls.add(get_enum_class(rtype))
|
||||
+ for arg in args:
|
||||
+ if arg in api_dict:
|
||||
+ ref_cls.add(arg)
|
||||
+ elif is_enum(arg) and get_enum_class(arg) in api_dict:
|
||||
+ ref_cls.add(get_enum_class(arg))
|
||||
+ deps[engine_class["name"]] = set(filter(lambda x: x != name, ref_cls))
|
||||
+ for acls in ref_cls:
|
||||
+ if acls == name:
|
||||
+ continue
|
||||
+ reverse_deps[acls] = reverse_deps.get(acls, set())
|
||||
+ reverse_deps[acls].add(name)
|
||||
+
|
||||
+ included = []
|
||||
+ front = list(profile.get("enabled_classes", []))
|
||||
+ if front:
|
||||
+ # These must always be included
|
||||
+ front.append("WorkerThreadPool")
|
||||
+ front.append("ClassDB")
|
||||
+ front.append("ClassDBSingleton")
|
||||
+ while front:
|
||||
+ cls = front.pop()
|
||||
+ if cls in included:
|
||||
+ continue
|
||||
+ included.append(cls)
|
||||
+ parent = parents.get(cls, "")
|
||||
+ if parent:
|
||||
+ front.append(parent)
|
||||
+ for rcls in deps.get(cls, set()):
|
||||
+ if rcls in included or rcls in front:
|
||||
+ continue
|
||||
+ front.append(rcls)
|
||||
+
|
||||
+ excluded = []
|
||||
+ front = list(profile.get("disabled_classes", []))
|
||||
+ while front:
|
||||
+ cls = front.pop()
|
||||
+ if cls in excluded:
|
||||
+ continue
|
||||
+ excluded.append(cls)
|
||||
+ front += children.get(cls, [])
|
||||
+ for rcls in reverse_deps.get(cls, set()):
|
||||
+ if rcls in excluded or rcls in front:
|
||||
+ continue
|
||||
+ front.append(rcls)
|
||||
+
|
||||
+ if included and excluded:
|
||||
+ print(
|
||||
+ "WARNING: Cannot specify both 'enabled_classes' and 'disabled_classes' in build profile. 'disabled_classes' will be ignored."
|
||||
+ )
|
||||
+
|
||||
+ return {
|
||||
+ "enabled_classes": included,
|
||||
+ "disabled_classes": excluded,
|
||||
+ }
|
||||
+
|
||||
+
|
||||
def scons_emit_files(target, source, env):
|
||||
- files = [env.File(f) for f in get_file_list(str(source[0]), target[0].abspath, True, True)]
|
||||
+ profile_filepath = env.get("build_profile", "")
|
||||
+ if profile_filepath and not Path(profile_filepath).is_absolute():
|
||||
+ profile_filepath = str((Path(env.Dir("#").abspath) / profile_filepath).as_posix())
|
||||
+
|
||||
+ files = [env.File(f) for f in get_file_list(str(source[0]), target[0].abspath, True, True, profile_filepath)]
|
||||
env.Clean(target, files)
|
||||
env["godot_cpp_gen_dir"] = target[0].abspath
|
||||
return files, source
|
||||
@@ -1997,6 +2092,20 @@ def is_pod_type(type_name):
|
||||
]
|
||||
|
||||
|
||||
+def is_class_included(class_name, build_profile):
|
||||
+ """
|
||||
+ Check if an engine class should be included.
|
||||
+ This removes classes according to a build profile of enabled or disabled classes.
|
||||
+ """
|
||||
+ included = build_profile.get("enabled_classes", [])
|
||||
+ excluded = build_profile.get("disabled_classes", [])
|
||||
+ if included:
|
||||
+ return class_name in included
|
||||
+ if excluded:
|
||||
+ return class_name not in excluded
|
||||
+ return True
|
||||
+
|
||||
+
|
||||
def is_included_type(type_name):
|
||||
# Types which we already have implemented.
|
||||
return is_included_struct_type(type_name) or type_name in ["ObjectID"]
|
||||
34
misc/patches/gdnantive_arm_warnings.diff
Normal file
34
misc/patches/gdnantive_arm_warnings.diff
Normal file
@@ -0,0 +1,34 @@
|
||||
diff --git a/godot-cpp-3.x/godot-headers/gdnative/gdnative.h b/godot-cpp-3.x/godot-headers/gdnative/gdnative.h
|
||||
index c0573d21b5d7a..ec95c4c4ebfcc 100644
|
||||
--- a/godot-cpp-3.x/godot-headers/gdnative/gdnative.h
|
||||
+++ b/godot-cpp-3.x/godot-headers/gdnative/gdnative.h
|
||||
@@ -37,20 +37,24 @@ extern "C" {
|
||||
|
||||
#if defined(_WIN32) || defined(__ANDROID__)
|
||||
#define GDCALLINGCONV
|
||||
-#define GDAPI GDCALLINGCONV
|
||||
+
|
||||
#elif defined(__APPLE__)
|
||||
#include "TargetConditionals.h"
|
||||
#if TARGET_OS_IPHONE
|
||||
#define GDCALLINGCONV __attribute__((visibility("default")))
|
||||
-#define GDAPI GDCALLINGCONV
|
||||
#elif TARGET_OS_MAC
|
||||
#define GDCALLINGCONV __attribute__((sysv_abi))
|
||||
-#define GDAPI GDCALLINGCONV
|
||||
#endif
|
||||
-#else // !_WIN32 && !__APPLE__
|
||||
+
|
||||
+#else // Linux/BSD/Web
|
||||
+#if defined(__aarch64__) || defined(__arm__)
|
||||
+#define GDCALLINGCONV
|
||||
+#else
|
||||
#define GDCALLINGCONV __attribute__((sysv_abi))
|
||||
-#define GDAPI GDCALLINGCONV
|
||||
#endif
|
||||
+#endif
|
||||
+
|
||||
+#define GDAPI GDCALLINGCONV
|
||||
|
||||
// This is for libraries *using* the header, NOT GODOT EXPOSING STUFF!!
|
||||
#if !defined(GDN_EXPORT)
|
||||
29
misc/patches/scons_path.diff
Normal file
29
misc/patches/scons_path.diff
Normal 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
26
misc/scripts/black_format.sh
Executable 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
53
misc/scripts/clang_format.sh
Executable 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
|
||||
95
misc/scripts/copyright_headers.py
Executable file
95
misc/scripts/copyright_headers.py
Executable 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()
|
||||
91
misc/scripts/file_format.sh
Executable file
91
misc/scripts/file_format.sh
Executable file
@@ -0,0 +1,91 @@
|
||||
#!/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" == "misc/patches/"* ]]; 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
33
misc/scripts/package_release.sh
Executable 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}" -maxdepth 5 -wholename "*/${VERSION}/${TYPE}/lib/*" | xargs cp -r -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
30
misc/webrtc.gdextension
Normal file
@@ -0,0 +1,30 @@
|
||||
[configuration]
|
||||
|
||||
entry_symbol = "webrtc_extension_init"
|
||||
compatibility_minimum = {GODOT_VERSION}
|
||||
|
||||
[libraries]
|
||||
|
||||
linux.debug.x86_64 = "lib/libwebrtc_native.linux.template_debug.x86_64.so"
|
||||
linux.debug.x86_32 = "lib/libwebrtc_native.linux.template_debug.x86_32.so"
|
||||
linux.debug.arm64 = "lib/libwebrtc_native.linux.template_debug.arm64.so"
|
||||
linux.debug.arm32 = "lib/libwebrtc_native.linux.template_debug.arm32.so"
|
||||
macos.debug = "lib/libwebrtc_native.macos.template_debug.universal.framework"
|
||||
windows.debug.x86_64 = "lib/libwebrtc_native.windows.template_debug.x86_64.dll"
|
||||
windows.debug.x86_32 = "lib/libwebrtc_native.windows.template_debug.x86_32.dll"
|
||||
android.debug.arm64 = "lib/libwebrtc_native.android.template_debug.arm64.so"
|
||||
android.debug.x86_64 = "lib/libwebrtc_native.android.template_debug.x86_64.so"
|
||||
ios.debug.arm64 = "lib/libwebrtc_native.ios.template_debug.arm64.dylib"
|
||||
ios.debug.x86_64 = "lib/libwebrtc_native.ios.template_debug.x86_64.simulator.dylib"
|
||||
|
||||
linux.release.x86_64 = "lib/libwebrtc_native.linux.template_release.x86_64.so"
|
||||
linux.release.x86_32 = "lib/libwebrtc_native.linux.template_release.x86_32.so"
|
||||
linux.release.arm64 = "lib/libwebrtc_native.linux.template_release.arm64.so"
|
||||
linux.release.arm32 = "lib/libwebrtc_native.linux.template_release.arm32.so"
|
||||
macos.release = "lib/libwebrtc_native.macos.template_release.universal.framework"
|
||||
windows.release.x86_64 = "lib/libwebrtc_native.windows.template_release.x86_64.dll"
|
||||
windows.release.x86_32 = "lib/libwebrtc_native.windows.template_release.x86_32.dll"
|
||||
android.release.arm64 = "lib/libwebrtc_native.android.template_release.arm64.so"
|
||||
android.release.x86_64 = "lib/libwebrtc_native.android.template_release.x86_64.so"
|
||||
ios.release.arm64 = "lib/libwebrtc_native.ios.template_release.arm64.dylib"
|
||||
ios.release.x86_64 = "lib/libwebrtc_native.ios.template_release.x86_64.simulator.dylib"
|
||||
21
misc/webrtc.tres
Normal file
21
misc/webrtc.tres
Normal file
@@ -0,0 +1,21 @@
|
||||
[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.x86_64 = "res://{GDNATIVE_PATH}/lib/libwebrtc_native.linux.{TARGET}.x86_64.so"
|
||||
entry/X11.32.x86_32 = "res://{GDNATIVE_PATH}/lib/libwebrtc_native.linux.{TARGET}.x86_32.so"
|
||||
entry/X11.64.arm64 = "res://{GDNATIVE_PATH}/lib/libwebrtc_native.linux.{TARGET}.arm64.so"
|
||||
entry/X11.32.arm32 = "res://{GDNATIVE_PATH}/lib/libwebrtc_native.linux.{TARGET}.arm32.so"
|
||||
entry/Server.64.x86_64 = "res://{GDNATIVE_PATH}/lib/libwebrtc_native.linux.{TARGET}.x86_64.so"
|
||||
entry/Server.32.x86_32 = "res://{GDNATIVE_PATH}/lib/libwebrtc_native.linux.{TARGET}.x86_32.so"
|
||||
entry/Server.64.arm64 = "res://{GDNATIVE_PATH}/lib/libwebrtc_native.linux.{TARGET}.arm64.so"
|
||||
entry/Server.32.arm32 = "res://{GDNATIVE_PATH}/lib/libwebrtc_native.linux.{TARGET}.arm32.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"
|
||||
@@ -1,16 +0,0 @@
|
||||
#include "WebRTCLibPeer.hpp"
|
||||
|
||||
using namespace godot_webrtc;
|
||||
|
||||
WebRTCLibPeer::GodotCSDO::GodotCSDO(WebRTCLibPeer *parent) {
|
||||
this->parent = parent;
|
||||
}
|
||||
|
||||
void WebRTCLibPeer::GodotCSDO::OnSuccess(webrtc::SessionDescriptionInterface *desc) {
|
||||
// serialize this offer and send it to the remote peer:
|
||||
std::string sdp; // sdp = session description protocol
|
||||
desc->ToString(&sdp);
|
||||
parent->queue_signal("offer_created", 2, desc->type().c_str(), sdp.c_str());
|
||||
};
|
||||
|
||||
void WebRTCLibPeer::GodotCSDO::OnFailure(const std::string &error){};
|
||||
@@ -1,19 +0,0 @@
|
||||
#include "WebRTCLibPeer.hpp"
|
||||
|
||||
using namespace godot_webrtc;
|
||||
|
||||
WebRTCLibPeer::GodotDCO::GodotDCO(WebRTCLibPeer *parent) {
|
||||
this->parent = parent;
|
||||
}
|
||||
|
||||
void WebRTCLibPeer::GodotDCO::OnMessage(const webrtc::DataBuffer &buffer) {
|
||||
const uint8_t *data = buffer.data.data<uint8_t>();
|
||||
uint8_t *memory_controlled_buffer = new uint8_t[buffer.data.size()];
|
||||
|
||||
std::copy(data, data + buffer.data.size(), memory_controlled_buffer);
|
||||
parent->queue_packet(memory_controlled_buffer, buffer.data.size());
|
||||
};
|
||||
|
||||
void WebRTCLibPeer::GodotDCO::OnStateChange(){};
|
||||
|
||||
void WebRTCLibPeer::GodotDCO::OnBufferedAmountChange(uint64_t previous_amount){};
|
||||
@@ -1,46 +0,0 @@
|
||||
#include "WebRTCLibPeer.hpp"
|
||||
|
||||
using namespace godot_webrtc;
|
||||
|
||||
WebRTCLibPeer::GodotPCO::GodotPCO(WebRTCLibPeer *parent) {
|
||||
this->parent = parent;
|
||||
}
|
||||
|
||||
void WebRTCLibPeer::GodotPCO::OnSignalingChange(webrtc::PeerConnectionInterface::SignalingState new_state) {
|
||||
}
|
||||
|
||||
void WebRTCLibPeer::GodotPCO::OnAddStream(rtc::scoped_refptr<webrtc::MediaStreamInterface> stream) {
|
||||
}
|
||||
|
||||
void WebRTCLibPeer::GodotPCO::OnRemoveStream(rtc::scoped_refptr<webrtc::MediaStreamInterface> stream) {
|
||||
}
|
||||
|
||||
void WebRTCLibPeer::GodotPCO::OnDataChannel(rtc::scoped_refptr<webrtc::DataChannelInterface> data_channel) {
|
||||
}
|
||||
|
||||
void WebRTCLibPeer::GodotPCO::OnRenegotiationNeeded() {
|
||||
}
|
||||
|
||||
void WebRTCLibPeer::GodotPCO::OnIceConnectionChange(webrtc::PeerConnectionInterface::IceConnectionState new_state) {
|
||||
}
|
||||
|
||||
void WebRTCLibPeer::GodotPCO::OnIceGatheringChange(webrtc::PeerConnectionInterface::IceGatheringState new_state) {
|
||||
}
|
||||
|
||||
void WebRTCLibPeer::GodotPCO::OnIceCandidate(const webrtc::IceCandidateInterface *candidate) {
|
||||
// Serialize the candidate and send it to the remote peer:
|
||||
|
||||
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("new_ice_candidate",
|
||||
3,
|
||||
candidateSdpMidName,
|
||||
candidateSdpMlineIndexName,
|
||||
candidateSdpName);
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
#include "WebRTCLibPeer.hpp"
|
||||
|
||||
using namespace godot_webrtc;
|
||||
|
||||
WebRTCLibPeer::GodotSSDO::GodotSSDO(WebRTCLibPeer *parent) {
|
||||
this->parent = parent;
|
||||
}
|
||||
|
||||
void WebRTCLibPeer::GodotSSDO::OnSuccess(){};
|
||||
|
||||
void WebRTCLibPeer::GodotSSDO::OnFailure(const std::string &error){};
|
||||
231
src/WebRTCLibDataChannel.cpp
Normal file
231
src/WebRTCLibDataChannel.cpp
Normal file
@@ -0,0 +1,231 @@
|
||||
/**************************************************************************/
|
||||
/* 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;
|
||||
|
||||
// DataChannel
|
||||
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, nullptr);
|
||||
|
||||
#ifdef GDNATIVE_WEBRTC
|
||||
// Instance a WebRTCDataChannelGDNative object
|
||||
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");
|
||||
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(std::shared_ptr<rtc::DataChannel> p_channel, bool p_negotiated) {
|
||||
ERR_FAIL_COND(!p_channel);
|
||||
|
||||
channel = p_channel;
|
||||
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, bool p_is_string) {
|
||||
mutex->lock();
|
||||
|
||||
std::vector<uint8_t> packet;
|
||||
packet.resize(size);
|
||||
memcpy(&packet[0], data, size);
|
||||
packet_queue.push(QueuedPacket(packet, p_is_string));
|
||||
|
||||
mutex->unlock();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
WebRTCDataChannel::WriteMode WebRTCLibDataChannel::_get_write_mode() const {
|
||||
return write_mode;
|
||||
}
|
||||
|
||||
bool WebRTCLibDataChannel::_was_string_packet() const {
|
||||
return current_packet.second;
|
||||
}
|
||||
|
||||
WebRTCDataChannel::ChannelState WebRTCLibDataChannel::_get_ready_state() const {
|
||||
ERR_FAIL_COND_V(!channel, STATE_CLOSED);
|
||||
return channel_state;
|
||||
}
|
||||
|
||||
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, false);
|
||||
return channel->reliability().unordered == false;
|
||||
}
|
||||
|
||||
int32_t WebRTCLibDataChannel::_get_id() const {
|
||||
ERR_FAIL_COND_V(!channel, -1);
|
||||
return channel->id().value_or(-1);
|
||||
}
|
||||
|
||||
int32_t WebRTCLibDataChannel::_get_max_packet_life_time() const {
|
||||
ERR_FAIL_COND_V(!channel, 0);
|
||||
return channel->reliability().maxPacketLifeTime.has_value() ? channel->reliability().maxPacketLifeTime.value().count() : -1;
|
||||
}
|
||||
|
||||
int32_t WebRTCLibDataChannel::_get_max_retransmits() const {
|
||||
ERR_FAIL_COND_V(!channel, 0);
|
||||
return channel->reliability().maxRetransmits.value_or(-1);
|
||||
}
|
||||
|
||||
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, false);
|
||||
return negotiated;
|
||||
}
|
||||
|
||||
int32_t WebRTCLibDataChannel::_get_buffered_amount() const {
|
||||
ERR_FAIL_COND_V(!channel, 0);
|
||||
return channel->bufferedAmount();
|
||||
}
|
||||
|
||||
Error WebRTCLibDataChannel::_poll() {
|
||||
return OK;
|
||||
}
|
||||
|
||||
void WebRTCLibDataChannel::_close() try {
|
||||
if (channel) {
|
||||
channel->close();
|
||||
}
|
||||
} catch (...) {
|
||||
}
|
||||
|
||||
Error WebRTCLibDataChannel::_get_packet(const uint8_t **r_buffer, int32_t *r_len) {
|
||||
ERR_FAIL_COND_V(packet_queue.empty(), ERR_UNAVAILABLE);
|
||||
|
||||
mutex->lock();
|
||||
|
||||
// Update current packet and pop queue
|
||||
current_packet = packet_queue.front();
|
||||
packet_queue.pop();
|
||||
// Set out buffer and size (buffer will be gone at next get_packet or close)
|
||||
*r_buffer = ¤t_packet.first[0];
|
||||
*r_len = current_packet.first.size();
|
||||
|
||||
mutex->unlock();
|
||||
|
||||
return 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);
|
||||
}
|
||||
|
||||
int32_t WebRTCLibDataChannel::_get_available_packet_count() const {
|
||||
return packet_queue.size();
|
||||
}
|
||||
|
||||
int32_t WebRTCLibDataChannel::_get_max_packet_size() const {
|
||||
return 16384; // See RFC-8831 section 6.6: https://datatracker.ietf.org/doc/rfc8831/
|
||||
}
|
||||
|
||||
WebRTCLibDataChannel::WebRTCLibDataChannel() {
|
||||
mutex = new std::mutex;
|
||||
}
|
||||
|
||||
WebRTCLibDataChannel::~WebRTCLibDataChannel() {
|
||||
_close();
|
||||
channel = nullptr;
|
||||
delete mutex;
|
||||
}
|
||||
114
src/WebRTCLibDataChannel.hpp
Normal file
114
src/WebRTCLibDataChannel.hpp
Normal file
@@ -0,0 +1,114 @@
|
||||
/**************************************************************************/
|
||||
/* 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 "net/WebRTCDataChannelNative.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 godot::WebRTCDataChannelExtension {
|
||||
GDCLASS(WebRTCLibDataChannel, WebRTCDataChannelExtension);
|
||||
|
||||
private:
|
||||
using QueuedPacket = std::pair<std::vector<uint8_t>, bool>;
|
||||
std::mutex *mutex;
|
||||
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() {}
|
||||
|
||||
godot::String _to_string() const {
|
||||
return "WebRTCLibDataChannel";
|
||||
}
|
||||
|
||||
public:
|
||||
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, 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();
|
||||
};
|
||||
|
||||
} // namespace godot_webrtc
|
||||
|
||||
#endif // WEBRTC_DATA_CHANNEL_H
|
||||
@@ -1,202 +0,0 @@
|
||||
#include "WebRTCLibPeer.hpp"
|
||||
|
||||
using namespace godot_webrtc;
|
||||
|
||||
void WebRTCLibPeer::set_write_mode(godot_int mode) {
|
||||
}
|
||||
|
||||
godot_int WebRTCLibPeer::get_write_mode() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool WebRTCLibPeer::was_string_packet() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
godot_int WebRTCLibPeer::get_connection_state() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
godot_error WebRTCLibPeer::create_offer() {
|
||||
peer_connection->CreateOffer(
|
||||
ptr_csdo, // CreateSessionDescriptionObserver* observer,
|
||||
nullptr // webrtc::PeerConnectionInterface::RTCOfferAnswerOptions() // const MediaConstraintsInterface* constraints
|
||||
);
|
||||
return GODOT_OK;
|
||||
}
|
||||
|
||||
godot_error WebRTCLibPeer::set_remote_description(const char *type, const char *sdp) {
|
||||
godot_error err = set_description(type, sdp, false); //false meaning !isLocal because it is remote
|
||||
peer_connection->CreateAnswer(ptr_csdo, webrtc::PeerConnectionInterface::RTCOfferAnswerOptions());
|
||||
return err;
|
||||
}
|
||||
|
||||
godot_error WebRTCLibPeer::set_local_description(const char *type, const char *sdp) {
|
||||
return set_description(type, sdp, true); // isLocal == true
|
||||
}
|
||||
|
||||
godot_error WebRTCLibPeer::add_ice_candidate(const char *sdpMidName, int sdpMlineIndexName, const char *sdpName) {
|
||||
webrtc::SdpParseError *error = nullptr;
|
||||
webrtc::IceCandidateInterface *candidate = webrtc::CreateIceCandidate(
|
||||
sdpMidName,
|
||||
sdpMlineIndexName,
|
||||
sdpName,
|
||||
error);
|
||||
|
||||
// @TODO do something if there's an error (if error, or if !candidate)
|
||||
if (error || !candidate)
|
||||
std::cout << "ERROR with creating ICE candidate (" << error << ")\n";
|
||||
|
||||
if (!peer_connection->AddIceCandidate(candidate))
|
||||
ERR_PRINT("Error with adding ICE candidate");
|
||||
return GODOT_OK;
|
||||
}
|
||||
|
||||
godot_error WebRTCLibPeer::poll() {
|
||||
std::function<void()> signal;
|
||||
while (!signal_queue.empty()) {
|
||||
mutex_signal_queue->lock();
|
||||
signal = signal_queue.front();
|
||||
signal_queue.pop();
|
||||
mutex_signal_queue->unlock();
|
||||
|
||||
signal();
|
||||
}
|
||||
return GODOT_OK;
|
||||
}
|
||||
|
||||
godot_error WebRTCLibPeer::get_packet(const uint8_t **r_buffer, int *r_len) {
|
||||
if (packet_queue_size == 0)
|
||||
return GODOT_ERR_UNAVAILABLE;
|
||||
mutex_packet_queue->lock();
|
||||
uint8_t *current_packet = packet_queue.front();
|
||||
*r_buffer = current_packet;
|
||||
*r_len = packet_sizes_queue.front();
|
||||
|
||||
packet_queue.pop();
|
||||
packet_sizes_queue.pop();
|
||||
mutex_packet_queue->unlock();
|
||||
|
||||
--packet_queue_size;
|
||||
return GODOT_OK;
|
||||
}
|
||||
|
||||
godot_error WebRTCLibPeer::put_packet(const uint8_t *p_buffer, int p_len) {
|
||||
webrtc::DataBuffer webrtc_buffer(rtc::CopyOnWriteBuffer(p_buffer, p_len), true);
|
||||
data_channel->Send(webrtc_buffer);
|
||||
return GODOT_OK; // @TODO properly return any Error we may get.
|
||||
}
|
||||
|
||||
godot_int WebRTCLibPeer::get_available_packet_count() const {
|
||||
return packet_queue_size;
|
||||
}
|
||||
|
||||
godot_int WebRTCLibPeer::get_max_packet_size() const {
|
||||
return 1200;
|
||||
}
|
||||
|
||||
void WebRTCLibPeer::_register_methods() {
|
||||
}
|
||||
|
||||
void WebRTCLibPeer::_init() {
|
||||
register_interface(&interface);
|
||||
|
||||
// initialize variables:
|
||||
mutex_signal_queue = new std::mutex;
|
||||
mutex_packet_queue = new std::mutex;
|
||||
packet_queue_size = 0;
|
||||
|
||||
// create a PeerConnectionFactoryInterface:
|
||||
signaling_thread = new rtc::Thread;
|
||||
signaling_thread->Start();
|
||||
pc_factory = webrtc::CreateModularPeerConnectionFactory(
|
||||
nullptr, // rtc::Thread* network_thread,
|
||||
nullptr, // rtc::Thread* worker_thread,
|
||||
signaling_thread,
|
||||
nullptr, // std::unique_ptr<cricket::MediaEngineInterface> media_engine,
|
||||
nullptr, // std::unique_ptr<CallFactoryInterface> call_factory,
|
||||
nullptr // std::unique_ptr<RtcEventLogFactoryInterface> event_log_factory
|
||||
);
|
||||
if (pc_factory.get() == nullptr) { // PeerConnectionFactory couldn't be created. Fail the method call.
|
||||
ERR_PRINT("PeerConnectionFactory could not be created");
|
||||
// return GODOT_FAILED;
|
||||
}
|
||||
|
||||
// create PeerConnection configuration and add the ice servers:
|
||||
webrtc::PeerConnectionInterface::RTCConfiguration configuration;
|
||||
//webrtc::PeerConnectionInterface::IceServer ice_server;
|
||||
|
||||
//ice_server.uri = "stun:stun.l.google.com:19302"; // @FIXME allow user to input ice servers
|
||||
//configuration.servers.push_back(ice_server);
|
||||
|
||||
// create a PeerConnection object:
|
||||
peer_connection = pc_factory->CreatePeerConnection(configuration, nullptr, nullptr, &pco);
|
||||
if (peer_connection.get() == nullptr) { // PeerConnection couldn't be created. Fail the method call.
|
||||
ERR_PRINT("PeerConnection could not be created");
|
||||
// return GODOT_FAILED;
|
||||
}
|
||||
|
||||
// create a DataChannel
|
||||
webrtc::DataChannelInit data_channel_config;
|
||||
data_channel_config.negotiated = true; // True if the channel has been externally negotiated
|
||||
data_channel_config.id = 0;
|
||||
|
||||
data_channel = peer_connection->CreateDataChannel("channel", &data_channel_config);
|
||||
// @TODO (NONESSENTIAL) create data_channel check. fail function call if data_channel isn't created
|
||||
data_channel->RegisterObserver(&dco);
|
||||
}
|
||||
|
||||
WebRTCLibPeer::WebRTCLibPeer() :
|
||||
dco(this),
|
||||
pco(this),
|
||||
ptr_csdo(new rtc::RefCountedObject<GodotCSDO>(this)),
|
||||
ptr_ssdo(new rtc::RefCountedObject<GodotSSDO>(this)) {
|
||||
}
|
||||
|
||||
WebRTCLibPeer::~WebRTCLibPeer() {
|
||||
if (_owner) {
|
||||
register_interface(NULL);
|
||||
}
|
||||
delete mutex_signal_queue;
|
||||
delete mutex_packet_queue;
|
||||
}
|
||||
|
||||
void WebRTCLibPeer::queue_signal(godot::String p_name, int p_argc, const godot::Variant &p_arg1, const godot::Variant &p_arg2, const godot::Variant &p_arg3) {
|
||||
mutex_signal_queue->lock();
|
||||
signal_queue.push(
|
||||
[this, p_name, p_argc, p_arg1, p_arg2, p_arg3] {
|
||||
if (p_argc == 2)
|
||||
emit_signal(p_name, p_arg1, p_arg2);
|
||||
else
|
||||
emit_signal(p_name, p_arg1, p_arg2, p_arg3);
|
||||
});
|
||||
mutex_signal_queue->unlock();
|
||||
}
|
||||
|
||||
void WebRTCLibPeer::queue_packet(uint8_t *buffer, int buffer_size) {
|
||||
mutex_packet_queue->lock();
|
||||
packet_queue.push(buffer);
|
||||
packet_sizes_queue.push(buffer_size);
|
||||
++packet_queue_size;
|
||||
mutex_packet_queue->unlock();
|
||||
}
|
||||
|
||||
godot_error WebRTCLibPeer::set_description(const char *type, const char *sdp, bool isLocal) {
|
||||
// webrtc::SdpType type = (isOffer) ? webrtc::SdpType::kOffer : webrtc::SdpType::kAnswer;
|
||||
godot::String string_sdp = sdp;
|
||||
|
||||
webrtc::SdpType sdptype = (godot::String(type) == godot::String("offer")) ? webrtc::SdpType::kOffer : webrtc::SdpType::kAnswer;
|
||||
std::unique_ptr<webrtc::SessionDescriptionInterface> desc =
|
||||
webrtc::CreateSessionDescription(sdptype, sdp);
|
||||
|
||||
if (isLocal) {
|
||||
peer_connection->SetLocalDescription(
|
||||
ptr_ssdo, // @TODO (NONESSENTIAL, OPTIONAL) replace this with DummySetSessionDescriptionObserver::Create()
|
||||
desc.release());
|
||||
} else {
|
||||
peer_connection->SetRemoteDescription(
|
||||
ptr_ssdo, // @TODO (NONESSENTIAL, OPTIONAL) replace this with DummySetSessionDescriptionObserver::Create()
|
||||
desc.release());
|
||||
}
|
||||
return GODOT_OK;
|
||||
}
|
||||
@@ -1,117 +0,0 @@
|
||||
#ifndef WEBRTC_PEER_H
|
||||
#define WEBRTC_PEER_H
|
||||
|
||||
#include <Godot.hpp> // Godot.hpp must go first, or windows builds breaks
|
||||
|
||||
#include "api/peerconnectioninterface.h" // interface for all things needed from WebRTC
|
||||
#include "media/base/mediaengine.h" // needed for CreateModularPeerConnectionFactory
|
||||
#include <functional> // std::function
|
||||
#include <mutex> // mutex @TODO replace std::mutex with Godot mutex
|
||||
|
||||
#include "net/WebRTCPeerNative.hpp"
|
||||
|
||||
namespace godot_webrtc {
|
||||
|
||||
class WebRTCLibPeer : public WebRTCPeerNative {
|
||||
GODOT_CLASS(WebRTCLibPeer, WebRTCPeerNative);
|
||||
|
||||
public:
|
||||
static void _register_methods();
|
||||
|
||||
void _init();
|
||||
|
||||
void set_write_mode(godot_int mode);
|
||||
godot_int get_write_mode() const;
|
||||
bool was_string_packet() const;
|
||||
godot_int get_connection_state() const;
|
||||
|
||||
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();
|
||||
|
||||
/* WebRTCPeer */
|
||||
virtual godot_error get_packet(const uint8_t **r_buffer, int *r_len);
|
||||
virtual godot_error put_packet(const uint8_t *p_buffer, int p_len);
|
||||
virtual godot_int get_available_packet_count() const;
|
||||
virtual godot_int get_max_packet_size() const;
|
||||
|
||||
WebRTCLibPeer();
|
||||
~WebRTCLibPeer();
|
||||
|
||||
/* helper functions */
|
||||
|
||||
void queue_signal(godot::String p_name, int p_argc, const godot::Variant &p_arg1 = godot::Variant(), const godot::Variant &p_arg2 = godot::Variant(), const godot::Variant &p_arg3 = godot::Variant());
|
||||
// void queue_signal(godot::StringName p_name, Variant_ARG_LIST);
|
||||
void queue_packet(uint8_t *, int);
|
||||
godot_error set_description(const char *type, const char *sdp, bool isLocal);
|
||||
|
||||
/** DataChannelObserver callback functions **/
|
||||
class GodotDCO : public webrtc::DataChannelObserver {
|
||||
public:
|
||||
WebRTCLibPeer *parent;
|
||||
|
||||
GodotDCO(WebRTCLibPeer *parent);
|
||||
void OnMessage(const webrtc::DataBuffer &buffer) override;
|
||||
void OnStateChange() override; // UNUSED
|
||||
void OnBufferedAmountChange(uint64_t previous_amount) override; // UNUSED
|
||||
};
|
||||
|
||||
/** PeerConnectionObserver callback functions **/
|
||||
class GodotPCO : public webrtc::PeerConnectionObserver {
|
||||
public:
|
||||
WebRTCLibPeer *parent;
|
||||
|
||||
GodotPCO(WebRTCLibPeer *parent);
|
||||
void OnSignalingChange(webrtc::PeerConnectionInterface::SignalingState new_state) override;
|
||||
void OnAddStream(rtc::scoped_refptr<webrtc::MediaStreamInterface> stream) override;
|
||||
void OnRemoveStream(rtc::scoped_refptr<webrtc::MediaStreamInterface> stream) override;
|
||||
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;
|
||||
void OnIceCandidate(const webrtc::IceCandidateInterface *candidate) override;
|
||||
};
|
||||
|
||||
/** CreateSessionDescriptionObserver callback functions **/
|
||||
class GodotCSDO : public webrtc::CreateSessionDescriptionObserver {
|
||||
public:
|
||||
WebRTCLibPeer *parent;
|
||||
|
||||
GodotCSDO(WebRTCLibPeer *parent);
|
||||
void OnSuccess(webrtc::SessionDescriptionInterface *desc) override;
|
||||
void OnFailure(const std::string &error) override;
|
||||
};
|
||||
|
||||
/** SetSessionDescriptionObserver callback functions **/
|
||||
class GodotSSDO : public webrtc::SetSessionDescriptionObserver {
|
||||
public:
|
||||
WebRTCLibPeer *parent;
|
||||
|
||||
GodotSSDO(WebRTCLibPeer *parent);
|
||||
void OnSuccess() override;
|
||||
void OnFailure(const std::string &error) override;
|
||||
};
|
||||
|
||||
GodotDCO dco;
|
||||
GodotPCO pco;
|
||||
rtc::scoped_refptr<GodotSSDO> ptr_ssdo;
|
||||
rtc::scoped_refptr<GodotCSDO> ptr_csdo;
|
||||
|
||||
std::mutex *mutex_signal_queue;
|
||||
std::mutex *mutex_packet_queue;
|
||||
int packet_queue_size;
|
||||
std::queue<uint8_t *> packet_queue;
|
||||
std::queue<int> packet_sizes_queue;
|
||||
std::queue<std::function<void()> > signal_queue;
|
||||
|
||||
rtc::Thread *signaling_thread;
|
||||
rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> pc_factory;
|
||||
rtc::scoped_refptr<webrtc::PeerConnectionInterface> peer_connection;
|
||||
rtc::scoped_refptr<webrtc::DataChannelInterface> data_channel;
|
||||
};
|
||||
|
||||
} // namespace godot_webrtc
|
||||
|
||||
#endif // WEBRTC_PEER_H
|
||||
363
src/WebRTCLibPeerConnection.cpp
Normal file
363
src/WebRTCLibPeerConnection.cpp
Normal file
@@ -0,0 +1,363 @@
|
||||
/**************************************************************************/
|
||||
/* 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;
|
||||
|
||||
#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
|
||||
#define VERBOSE_PRINT(str) Godot::print(str)
|
||||
#else
|
||||
#include <godot_cpp/variant/utility_functions.hpp>
|
||||
#define VERBOSE_PRINT(str) UtilityFunctions::print_verbose(str)
|
||||
#endif
|
||||
void LogCallback(rtc::LogLevel level, std::string message) {
|
||||
switch (level) {
|
||||
case rtc::LogLevel::Fatal:
|
||||
case rtc::LogLevel::Error:
|
||||
ERR_PRINT(message.c_str());
|
||||
return;
|
||||
case rtc::LogLevel::Warning:
|
||||
WARN_PRINT(message.c_str());
|
||||
return;
|
||||
default:
|
||||
VERBOSE_PRINT(message.c_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void WebRTCLibPeerConnection::initialize_signaling() {
|
||||
#ifdef DEBUG_ENABLED
|
||||
rtc::InitLogger(rtc::LogLevel::Debug, LogCallback);
|
||||
#else
|
||||
rtc::InitLogger(rtc::LogLevel::Warning, LogCallback);
|
||||
#endif
|
||||
}
|
||||
|
||||
void WebRTCLibPeerConnection::deinitialize_signaling() {
|
||||
rtc::Cleanup();
|
||||
}
|
||||
|
||||
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
|
||||
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(ERR_INVALID_PARAMETER);
|
||||
}
|
||||
// Parse credentials (only meaningful for TURN, only support password)
|
||||
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") && p_server["credential"].get_type() == Variant::STRING) {
|
||||
credential = p_server["credential"];
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
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.maxPacketLifeTime = std::chrono::milliseconds(p_dict["maxPacketLifeTime"].operator int32_t());
|
||||
} else if (p_dict.has("maxRetransmits")) {
|
||||
r_config.reliability.maxRetransmits = 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;
|
||||
}
|
||||
|
||||
WebRTCPeerConnection::ConnectionState WebRTCLibPeerConnection::_get_connection_state() const {
|
||||
ERR_FAIL_COND_V(peer_connection == nullptr, STATE_CLOSED);
|
||||
|
||||
rtc::PeerConnection::State state = peer_connection->state();
|
||||
switch (state) {
|
||||
case rtc::PeerConnection::State::New:
|
||||
return STATE_NEW;
|
||||
case rtc::PeerConnection::State::Connecting:
|
||||
return STATE_CONNECTING;
|
||||
case rtc::PeerConnection::State::Connected:
|
||||
return STATE_CONNECTED;
|
||||
case rtc::PeerConnection::State::Disconnected:
|
||||
return STATE_DISCONNECTED;
|
||||
case rtc::PeerConnection::State::Failed:
|
||||
return STATE_FAILED;
|
||||
default:
|
||||
return STATE_CLOSED;
|
||||
}
|
||||
}
|
||||
|
||||
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++) {
|
||||
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);
|
||||
}
|
||||
|
||||
#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
|
||||
rtc::DataChannelInit config;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
return OK;
|
||||
} catch (const std::exception &e) {
|
||||
ERR_PRINT(e.what());
|
||||
ERR_FAIL_V(FAILED);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#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();
|
||||
Signal signal = signal_queue.front();
|
||||
signal_queue.pop();
|
||||
mutex_signal_queue->unlock();
|
||||
signal.emit(this);
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
void WebRTCLibPeerConnection::_close() {
|
||||
if (peer_connection != nullptr) {
|
||||
try {
|
||||
peer_connection->close();
|
||||
} catch (...) {
|
||||
}
|
||||
}
|
||||
|
||||
while (!signal_queue.empty()) {
|
||||
signal_queue.pop();
|
||||
}
|
||||
}
|
||||
|
||||
void WebRTCLibPeerConnection::_init() {
|
||||
#ifdef GDNATIVE_WEBRTC
|
||||
register_interface(&interface);
|
||||
#endif
|
||||
mutex_signal_queue = new std::mutex;
|
||||
|
||||
_initialize(Dictionary());
|
||||
}
|
||||
|
||||
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() {
|
||||
#ifndef GDNATIVE_WEBRTC
|
||||
_init();
|
||||
#endif
|
||||
}
|
||||
|
||||
WebRTCLibPeerConnection::~WebRTCLibPeerConnection() {
|
||||
#ifdef GDNATIVE_WEBRTC
|
||||
if (_owner) {
|
||||
register_interface(nullptr);
|
||||
}
|
||||
#endif
|
||||
_close();
|
||||
delete mutex_signal_queue;
|
||||
}
|
||||
|
||||
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 Variant argv[3] = { p_arg1, p_arg2, p_arg3 };
|
||||
signal_queue.push(Signal(p_name, p_argc, argv));
|
||||
mutex_signal_queue->unlock();
|
||||
}
|
||||
141
src/WebRTCLibPeerConnection.hpp
Normal file
141
src/WebRTCLibPeerConnection.hpp
Normal file
@@ -0,0 +1,141 @@
|
||||
/**************************************************************************/
|
||||
/* 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 "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 godot::WebRTCPeerConnectionExtension {
|
||||
GDCLASS(WebRTCLibPeerConnection, WebRTCPeerConnectionExtension);
|
||||
|
||||
private:
|
||||
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() {}
|
||||
|
||||
godot::String _to_string() const {
|
||||
return "WebRTCLibPeerConnection";
|
||||
}
|
||||
|
||||
public:
|
||||
static void _register_methods() {}
|
||||
static void initialize_signaling();
|
||||
static void deinitialize_signaling();
|
||||
|
||||
void _init();
|
||||
|
||||
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) 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();
|
||||
|
||||
private:
|
||||
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;
|
||||
argc = p_argc;
|
||||
for (int i = 0; i < argc; i++) {
|
||||
argv[i] = p_argv[i];
|
||||
}
|
||||
}
|
||||
|
||||
void emit(godot::Object *p_object) {
|
||||
if (argc == 0) {
|
||||
p_object->emit_signal(method);
|
||||
} else if (argc == 1) {
|
||||
p_object->emit_signal(method, argv[0]);
|
||||
} else if (argc == 2) {
|
||||
p_object->emit_signal(method, argv[0], argv[1]);
|
||||
} else if (argc == 3) {
|
||||
p_object->emit_signal(method, argv[0], argv[1], argv[2]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
std::mutex *mutex_signal_queue = nullptr;
|
||||
std::queue<Signal> signal_queue;
|
||||
|
||||
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
|
||||
|
||||
#endif // WEBRTC_PEER_H
|
||||
34
src/init.cpp
34
src/init.cpp
@@ -1,34 +0,0 @@
|
||||
#include "WebRTCLibPeer.hpp"
|
||||
#include "net/WebRTCPeerNative.hpp"
|
||||
#include <gdnative_api_struct.gen.h>
|
||||
|
||||
/* Godot export stuff */
|
||||
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;
|
||||
|
||||
const godot_gdnative_ext_net_api_struct *net_api = (godot_gdnative_ext_net_api_struct *)api->extensions[i];
|
||||
|
||||
if (!net_api->next)
|
||||
break;
|
||||
|
||||
if (net_api->next->version.major == 3 && net_api->next->version.minor == 2) {
|
||||
WebRTCPeerNative::_net_api = (const godot_gdnative_ext_net_3_2_api_struct *)net_api->next;
|
||||
}
|
||||
}
|
||||
|
||||
godot::Godot::gdnative_init(o);
|
||||
}
|
||||
|
||||
extern "C" void GDN_EXPORT godot_gdnative_terminate(godot_gdnative_terminate_options *o) {
|
||||
godot::Godot::gdnative_terminate(o);
|
||||
}
|
||||
|
||||
extern "C" void GDN_EXPORT godot_nativescript_init(void *handle) {
|
||||
godot::Godot::nativescript_init(handle);
|
||||
|
||||
godot::register_class<godot_webrtc::WebRTCLibPeer>();
|
||||
}
|
||||
82
src/init_gdextension.cpp
Normal file
82
src/init_gdextension.cpp
Normal 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();
|
||||
}
|
||||
}
|
||||
141
src/init_gdnative.cpp
Normal file
141
src/init_gdnative.cpp
Normal file
@@ -0,0 +1,141 @@
|
||||
/**************************************************************************/
|
||||
/* 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;
|
||||
static const godot_gdnative_core_api_struct *_singleton_api = NULL;
|
||||
static godot_class_constructor _create_ns_cb = NULL;
|
||||
static godot_method_bind *_set_script_mb = NULL;
|
||||
static godot_method_bind *_set_class_name_mb = NULL;
|
||||
static godot_method_bind *_set_library_mb = NULL;
|
||||
|
||||
void unregistered() {
|
||||
_singleton = false; // We are no longer the active singleton
|
||||
}
|
||||
|
||||
godot_error create_peer_connection_wp(godot_object *out) {
|
||||
ERR_FAIL_COND_V(!_singleton, GODOT_FAILED);
|
||||
// Create Script
|
||||
godot_object *script = _create_ns_cb();
|
||||
ERR_FAIL_COND_V(!script, GODOT_FAILED);
|
||||
|
||||
const void *args[] = { (void *)_singleton_lib };
|
||||
_singleton_api->godot_method_bind_ptrcall(_set_library_mb, script, args, nullptr);
|
||||
|
||||
godot_string s;
|
||||
_singleton_api->godot_string_new(&s);
|
||||
_singleton_api->godot_string_parse_utf8(&s, "WebRTCLibPeerConnection");
|
||||
const void *args2[] = { (void *)&s };
|
||||
_singleton_api->godot_method_bind_ptrcall(_set_class_name_mb, script, args2, nullptr);
|
||||
_singleton_api->godot_string_destroy(&s);
|
||||
|
||||
// Bind script to Object
|
||||
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 },
|
||||
&unregistered,
|
||||
&create_peer_connection_wp,
|
||||
NULL,
|
||||
};
|
||||
|
||||
extern "C" void GDN_EXPORT godot_gdnative_singleton() {
|
||||
if (godot::WebRTCPeerConnectionNative::_net_api) {
|
||||
ERR_FAIL_COND(!godot::gdnlib);
|
||||
_singleton_lib = godot::gdnlib;
|
||||
ERR_FAIL_COND(!godot::api);
|
||||
_singleton_api = godot::api;
|
||||
_create_ns_cb = godot::api->godot_get_class_constructor("NativeScript");
|
||||
ERR_FAIL_COND(!_create_ns_cb);
|
||||
_set_script_mb = godot::api->godot_method_bind_get_method("Object", "set_script");
|
||||
ERR_FAIL_COND(!_set_script_mb);
|
||||
_set_class_name_mb = godot::api->godot_method_bind_get_method("NativeScript", "set_class_name");
|
||||
ERR_FAIL_COND(!_set_class_name_mb);
|
||||
_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 = godot::WebRTCPeerConnectionNative::_net_api->godot_net_set_webrtc_library(&library) == GODOT_OK;
|
||||
if (!_singleton)
|
||||
ERR_PRINT("Failed initializing webrtc singleton library");
|
||||
}
|
||||
}
|
||||
|
||||
/* Godot export stuff */
|
||||
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;
|
||||
|
||||
const godot_gdnative_ext_net_api_struct *net_api = (godot_gdnative_ext_net_api_struct *)api->extensions[i];
|
||||
|
||||
if (!net_api->next)
|
||||
break;
|
||||
|
||||
if (net_api->next->version.major == 3 && net_api->next->version.minor == 2) {
|
||||
godot::WebRTCPeerConnectionNative::_net_api = (const godot_gdnative_ext_net_3_2_api_struct *)net_api->next;
|
||||
}
|
||||
}
|
||||
|
||||
godot_webrtc::WebRTCLibPeerConnection::initialize_signaling();
|
||||
godot::Godot::gdnative_init(o);
|
||||
}
|
||||
|
||||
extern "C" void GDN_EXPORT godot_gdnative_terminate(godot_gdnative_terminate_options *o) {
|
||||
if (_singleton) { // If we are the active singleton, unregister
|
||||
godot::WebRTCPeerConnectionNative::_net_api->godot_net_set_webrtc_library(NULL);
|
||||
}
|
||||
godot_webrtc::WebRTCLibPeerConnection::deinitialize_signaling();
|
||||
godot::Godot::gdnative_terminate(o);
|
||||
}
|
||||
|
||||
extern "C" void GDN_EXPORT godot_nativescript_init(void *handle) {
|
||||
godot::Godot::nativescript_init(handle);
|
||||
|
||||
godot::register_class<godot_webrtc::WebRTCLibPeerConnection>();
|
||||
godot::register_class<godot_webrtc::WebRTCLibDataChannel>();
|
||||
}
|
||||
128
src/net/WebRTCDataChannelNative.cpp
Normal file
128
src/net/WebRTCDataChannelNative.cpp
Normal file
@@ -0,0 +1,128 @@
|
||||
/**************************************************************************/
|
||||
/* 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);
|
||||
}
|
||||
|
||||
void WebRTCDataChannelNative::_register_methods() {}
|
||||
|
||||
void WebRTCDataChannelNative::_init() {
|
||||
register_interface(&interface);
|
||||
}
|
||||
|
||||
WebRTCDataChannelNative::~WebRTCDataChannelNative() {
|
||||
if (_owner) {
|
||||
register_interface(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The C interface that implements WebRTCDataChannel.
|
||||
* In this case it forwards calls to our C++ class, but could be plain C,
|
||||
* and you could use void *user for any kind of state struct pointer you have.
|
||||
*/
|
||||
godot_error get_packet_wdc(void *user, const uint8_t **r_buffer, int *r_len) {
|
||||
return (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 (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();
|
||||
}
|
||||
|
||||
godot_int get_max_packet_size_wdc(const void *user) {
|
||||
return ((WebRTCDataChannelNative *)user)->_get_max_packet_size();
|
||||
}
|
||||
|
||||
void set_write_mode_wdc(void *user, godot_int write_mode) {
|
||||
((WebRTCDataChannelNative *)user)->_set_write_mode((godot::WebRTCDataChannel::WriteMode)write_mode);
|
||||
}
|
||||
|
||||
godot_int get_write_mode_wdc(const void *user) {
|
||||
return ((WebRTCDataChannelNative *)user)->_get_write_mode();
|
||||
}
|
||||
|
||||
bool was_string_packet_wdc(const void *user) {
|
||||
return ((WebRTCDataChannelNative *)user)->_was_string_packet();
|
||||
}
|
||||
|
||||
godot_int get_ready_state_wdc(const void *user) {
|
||||
return (godot_int)(((WebRTCDataChannelNative *)user)->_get_ready_state());
|
||||
}
|
||||
|
||||
const char *get_label_wdc(const void *user) {
|
||||
return ((WebRTCDataChannelNative *)user)->_get_label().utf8().get_data();
|
||||
}
|
||||
|
||||
bool is_ordered_wdc(const void *user) {
|
||||
return ((WebRTCDataChannelNative *)user)->_is_ordered();
|
||||
}
|
||||
|
||||
int get_id_wdc(const void *user) {
|
||||
return ((WebRTCDataChannelNative *)user)->_get_id();
|
||||
}
|
||||
|
||||
int get_max_packet_life_time_wdc(const void *user) {
|
||||
return ((WebRTCDataChannelNative *)user)->_get_max_packet_life_time();
|
||||
}
|
||||
|
||||
int get_max_retransmits_wdc(const void *user) {
|
||||
return ((WebRTCDataChannelNative *)user)->_get_max_retransmits();
|
||||
}
|
||||
|
||||
const char *get_protocol_wdc(const void *user) {
|
||||
return ((WebRTCDataChannelNative *)user)->_get_protocol().utf8().get_data();
|
||||
}
|
||||
|
||||
bool is_negotiated_wdc(const void *user) {
|
||||
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 (godot_error)(((WebRTCDataChannelNative *)user)->_poll());
|
||||
}
|
||||
|
||||
void close_wdc(void *user) {
|
||||
((WebRTCDataChannelNative *)user)->_close();
|
||||
}
|
||||
143
src/net/WebRTCDataChannelNative.hpp
Normal file
143
src/net/WebRTCDataChannelNative.hpp
Normal file
@@ -0,0 +1,143 @@
|
||||
/**************************************************************************/
|
||||
/* 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
|
||||
|
||||
#include <Godot.hpp>
|
||||
#include <Reference.hpp>
|
||||
#include <WebRTCDataChannelGDNative.hpp>
|
||||
|
||||
#include <net/godot_net.h>
|
||||
|
||||
/* Forward declare interface functions */
|
||||
godot_error get_packet_wdc(void *, const uint8_t **, int *);
|
||||
godot_error put_packet_wdc(void *, const uint8_t *, int);
|
||||
godot_int get_available_packet_count_wdc(const void *);
|
||||
godot_int get_max_packet_size_wdc(const void *);
|
||||
|
||||
void set_write_mode_wdc(void *, godot_int);
|
||||
godot_int get_write_mode_wdc(const void *);
|
||||
bool was_string_packet_wdc(const void *);
|
||||
godot_int get_ready_state_wdc(const void *);
|
||||
const char *get_label_wdc(const void *);
|
||||
bool is_ordered_wdc(const void *);
|
||||
int get_id_wdc(const void *);
|
||||
int get_max_packet_life_time_wdc(const void *);
|
||||
int get_max_retransmits_wdc(const void *);
|
||||
const char *get_protocol_wdc(const void *);
|
||||
bool is_negotiated_wdc(const void *);
|
||||
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,
|
||||
|
||||
&get_packet_wdc,
|
||||
&put_packet_wdc,
|
||||
&get_available_packet_count_wdc,
|
||||
&get_max_packet_size_wdc,
|
||||
|
||||
&set_write_mode_wdc,
|
||||
&get_write_mode_wdc,
|
||||
&was_string_packet_wdc,
|
||||
&get_ready_state_wdc,
|
||||
&get_label_wdc,
|
||||
&is_ordered_wdc,
|
||||
&get_id_wdc,
|
||||
&get_max_packet_life_time_wdc,
|
||||
&get_max_retransmits_wdc,
|
||||
&get_protocol_wdc,
|
||||
&is_negotiated_wdc,
|
||||
|
||||
&poll_wdc,
|
||||
&close_wdc,
|
||||
&interface_ext,
|
||||
};
|
||||
|
||||
public:
|
||||
static void _register_methods();
|
||||
|
||||
void _init();
|
||||
void register_interface(const godot_net_webrtc_data_channel *interface);
|
||||
|
||||
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 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;
|
||||
|
||||
/* PacketPeer */
|
||||
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
|
||||
101
src/net/WebRTCPeerConnectionNative.cpp
Normal file
101
src/net/WebRTCPeerConnectionNative.cpp
Normal file
@@ -0,0 +1,101 @@
|
||||
/**************************************************************************/
|
||||
/* 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) {
|
||||
ERR_FAIL_COND(!_net_api);
|
||||
_net_api->godot_net_bind_webrtc_peer_connection(_owner, p_interface);
|
||||
}
|
||||
|
||||
void WebRTCPeerConnectionNative::_register_methods() {}
|
||||
|
||||
void WebRTCPeerConnectionNative::_init() {
|
||||
register_interface(&interface);
|
||||
}
|
||||
|
||||
WebRTCPeerConnectionNative::~WebRTCPeerConnectionNative() {
|
||||
if (_owner) {
|
||||
register_interface(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The C interface that implements WebRTCPeerConnection.
|
||||
* In this case it forwards calls to our C++ class, but could be plain C,
|
||||
* and you could use void *user for any kind of state struct pointer you have.
|
||||
*/
|
||||
godot_int get_connection_state_wp(const void *user) {
|
||||
return (godot_int)((WebRTCPeerConnectionNative *)user)->_get_connection_state();
|
||||
}
|
||||
|
||||
godot_error initialize_wp(void *user, const godot_dictionary *p_config) {
|
||||
return (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) {
|
||||
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 (godot_error)(((WebRTCPeerConnectionNative *)user)->_create_offer());
|
||||
}
|
||||
|
||||
godot_error create_answer_wp(void *user) {
|
||||
return GODOT_ERR_UNAVAILABLE; // Not implemented, not used yet.
|
||||
}
|
||||
|
||||
godot_error set_remote_description_wp(void *user, const char *type, const char *sdp) {
|
||||
return (godot_error)(((WebRTCPeerConnectionNative *)user)->_set_remote_description(type, sdp));
|
||||
}
|
||||
|
||||
godot_error set_local_description_wp(void *user, const char *type, const char *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 (godot_error)(((WebRTCPeerConnectionNative *)user)->_add_ice_candidate(sdpMidName, sdpMlineIndexName, sdpName));
|
||||
}
|
||||
|
||||
godot_error poll_wp(void *user) {
|
||||
return (godot_error)((WebRTCPeerConnectionNative *)user)->_poll();
|
||||
}
|
||||
|
||||
void close_wp(void *user) {
|
||||
((WebRTCPeerConnectionNative *)user)->_close();
|
||||
}
|
||||
117
src/net/WebRTCPeerConnectionNative.hpp
Normal file
117
src/net/WebRTCPeerConnectionNative.hpp
Normal file
@@ -0,0 +1,117 @@
|
||||
/**************************************************************************/
|
||||
/* 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
|
||||
|
||||
#include <Godot.hpp>
|
||||
#include <Reference.hpp>
|
||||
#include <WebRTCPeerConnectionGDNative.hpp>
|
||||
|
||||
#include <net/godot_net.h>
|
||||
|
||||
/* Forward declare interface functions */
|
||||
godot_int get_connection_state_wp(const void *);
|
||||
|
||||
godot_error initialize_wp(void *, const godot_dictionary *);
|
||||
godot_object *create_data_channel_wp(void *, const char *, const godot_dictionary *);
|
||||
godot_error create_offer_wp(void *);
|
||||
godot_error create_answer_wp(void *);
|
||||
godot_error set_remote_description_wp(void *, const char *, const char *);
|
||||
godot_error set_local_description_wp(void *, const char *, const char *);
|
||||
godot_error add_ice_candidate_wp(void *, const char *, int, const char *);
|
||||
godot_error poll_wp(void *);
|
||||
void close_wp(void *);
|
||||
|
||||
namespace godot {
|
||||
|
||||
class WebRTCPeerConnectionNative : public godot::WebRTCPeerConnectionGDNative {
|
||||
GODOT_CLASS(WebRTCPeerConnectionNative, godot::WebRTCPeerConnectionGDNative);
|
||||
|
||||
protected:
|
||||
godot_net_webrtc_peer_connection interface = {
|
||||
{ 3, 1 },
|
||||
this,
|
||||
|
||||
&get_connection_state_wp,
|
||||
|
||||
&initialize_wp,
|
||||
&create_data_channel_wp,
|
||||
&create_offer_wp,
|
||||
&create_answer_wp,
|
||||
&set_remote_description_wp,
|
||||
&set_local_description_wp,
|
||||
&add_ice_candidate_wp,
|
||||
&poll_wp,
|
||||
&close_wp,
|
||||
NULL,
|
||||
};
|
||||
|
||||
public:
|
||||
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 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 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
|
||||
@@ -1,77 +0,0 @@
|
||||
#include "WebRTCPeerNative.hpp"
|
||||
|
||||
const godot_gdnative_ext_net_3_2_api_struct *WebRTCPeerNative::_net_api = NULL;
|
||||
|
||||
void WebRTCPeerNative::register_interface(const godot_net_webrtc_peer *p_interface) {
|
||||
ERR_FAIL_COND(!_net_api);
|
||||
_net_api->godot_net_bind_webrtc_peer(_owner, p_interface);
|
||||
}
|
||||
|
||||
void WebRTCPeerNative::_register_methods() {}
|
||||
|
||||
void WebRTCPeerNative::_init() {
|
||||
register_interface(&interface);
|
||||
}
|
||||
|
||||
WebRTCPeerNative::~WebRTCPeerNative() {
|
||||
if (_owner) {
|
||||
register_interface(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The C interface that implements WebRTCPeer.
|
||||
* In this case it forwards calls to our C++ class, but could be plain C,
|
||||
* and you could use void *user for any kind of state struct pointer you have.
|
||||
*/
|
||||
godot_error get_packet_wp(void *user, const uint8_t **r_buffer, int *r_len) {
|
||||
return ((WebRTCPeerNative *)user)->get_packet(r_buffer, r_len);
|
||||
}
|
||||
|
||||
godot_error put_packet_wp(void *user, const uint8_t *p_buffer, int p_len) {
|
||||
return ((WebRTCPeerNative *)user)->put_packet(p_buffer, p_len);
|
||||
}
|
||||
|
||||
godot_int get_available_packet_count_wp(const void *user) {
|
||||
return ((WebRTCPeerNative *)user)->get_available_packet_count();
|
||||
}
|
||||
|
||||
godot_int get_max_packet_size_wp(const void *user) {
|
||||
return ((WebRTCPeerNative *)user)->get_max_packet_size();
|
||||
}
|
||||
|
||||
void set_write_mode_wp(void *user, godot_int write_mode) {
|
||||
((WebRTCPeerNative *)user)->set_write_mode(write_mode);
|
||||
}
|
||||
|
||||
godot_int get_write_mode_wp(const void *user) {
|
||||
return ((WebRTCPeerNative *)user)->get_write_mode();
|
||||
}
|
||||
|
||||
bool was_string_packet_wp(const void *user) {
|
||||
return ((WebRTCPeerNative *)user)->was_string_packet();
|
||||
}
|
||||
|
||||
godot_int get_connection_state_wp(const void *user) {
|
||||
return ((WebRTCPeerNative *)user)->get_connection_state();
|
||||
}
|
||||
|
||||
godot_error create_offer_wp(void *user) {
|
||||
return ((WebRTCPeerNative *)user)->create_offer();
|
||||
}
|
||||
|
||||
godot_error set_remote_description_wp(void *user, const char *type, const char *sdp) {
|
||||
return ((WebRTCPeerNative *)user)->set_remote_description(type, sdp);
|
||||
}
|
||||
|
||||
godot_error set_local_description_wp(void *user, const char *type, const char *sdp) {
|
||||
return ((WebRTCPeerNative *)user)->set_local_description(type, sdp);
|
||||
}
|
||||
|
||||
godot_error add_ice_candidate_wp(void *user, const char *sdpMidName, int sdpMlineIndexName, const char *sdpName) {
|
||||
return ((WebRTCPeerNative *)user)->add_ice_candidate(sdpMidName, sdpMlineIndexName, sdpName);
|
||||
}
|
||||
|
||||
godot_error poll_wp(void *user) {
|
||||
return ((WebRTCPeerNative *)user)->poll();
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
#ifndef WEBRTC_PEER_NATIVE
|
||||
#define WEBRTC_PEER_NATIVE
|
||||
|
||||
#include <Godot.hpp>
|
||||
#include <Reference.hpp>
|
||||
#include <WebRTCPeerGDNative.hpp>
|
||||
|
||||
#include <net/godot_net.h>
|
||||
|
||||
/* Forward declare interface functions */
|
||||
godot_error get_packet_wp(void *, const uint8_t **, int *);
|
||||
godot_error put_packet_wp(void *, const uint8_t *, int);
|
||||
godot_int get_available_packet_count_wp(const void *);
|
||||
godot_int get_max_packet_size_wp(const void *);
|
||||
|
||||
void set_write_mode_wp(void *, godot_int);
|
||||
godot_int get_write_mode_wp(const void *);
|
||||
bool was_string_packet_wp(const void *);
|
||||
godot_int get_connection_state_wp(const void *);
|
||||
|
||||
godot_error create_offer_wp(void *);
|
||||
godot_error set_remote_description_wp(void *, const char *, const char *);
|
||||
godot_error set_local_description_wp(void *, const char *, const char *);
|
||||
godot_error add_ice_candidate_wp(void *, const char *, int, const char *);
|
||||
godot_error poll_wp(void *);
|
||||
|
||||
class WebRTCPeerNative : public godot::WebRTCPeerGDNative {
|
||||
GODOT_CLASS(WebRTCPeerNative, godot::WebRTCPeerGDNative);
|
||||
|
||||
protected:
|
||||
godot_net_webrtc_peer interface = {
|
||||
{ 3, 1 },
|
||||
this,
|
||||
|
||||
&get_packet_wp,
|
||||
&put_packet_wp,
|
||||
&get_available_packet_count_wp,
|
||||
&get_max_packet_size_wp,
|
||||
|
||||
&set_write_mode_wp,
|
||||
&get_write_mode_wp,
|
||||
&was_string_packet_wp,
|
||||
&get_connection_state_wp,
|
||||
|
||||
&create_offer_wp,
|
||||
&set_remote_description_wp,
|
||||
&set_local_description_wp,
|
||||
&add_ice_candidate_wp,
|
||||
&poll_wp,
|
||||
NULL,
|
||||
};
|
||||
|
||||
public:
|
||||
static void _register_methods();
|
||||
static const godot_gdnative_ext_net_3_2_api_struct *_net_api;
|
||||
|
||||
void _init();
|
||||
void register_interface(const godot_net_webrtc_peer *interface);
|
||||
|
||||
virtual void set_write_mode(godot_int mode) = 0;
|
||||
virtual godot_int get_write_mode() const = 0;
|
||||
virtual bool was_string_packet() const = 0;
|
||||
virtual godot_int get_connection_state() const = 0;
|
||||
|
||||
virtual godot_error create_offer() = 0;
|
||||
virtual godot_error set_remote_description(const char *type, const char *sdp) = 0;
|
||||
virtual godot_error set_local_description(const char *type, const char *sdp) = 0;
|
||||
virtual godot_error add_ice_candidate(const char *sdpMidName, int sdpMlineIndexName, const char *sdpName) = 0;
|
||||
virtual godot_error poll() = 0;
|
||||
|
||||
/* PacketPeer */
|
||||
virtual godot_error get_packet(const uint8_t **r_buffer, int *r_len) = 0;
|
||||
virtual godot_error put_packet(const uint8_t *p_buffer, int p_len) = 0;
|
||||
virtual godot_int get_available_packet_count() const = 0;
|
||||
virtual godot_int get_max_packet_size() const = 0;
|
||||
|
||||
~WebRTCPeerNative();
|
||||
};
|
||||
|
||||
#endif // WEBRTC_PEER_NATIVE
|
||||
82
thirdparty/README.md
vendored
Normal file
82
thirdparty/README.md
vendored
Normal 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.11.3 (9cca280a4d0ccf0c08f47a99aa71d1b0e52f8d03, 2023)
|
||||
- License: MIT
|
||||
|
||||
Module location:
|
||||
|
||||
- thirdparty/libdatachannel/deps/json
|
||||
|
||||
|
||||
## libdatachannel
|
||||
|
||||
- Upstream: https://github.com/paullouisageneau/libdatachannel
|
||||
- Version: 0.22.2 (3c33ea0f49fff2630be080b2043052b4d3de5786, 2024)
|
||||
- License: MPL 2.0
|
||||
|
||||
Module location:
|
||||
|
||||
- thirdparty/libdatachannel
|
||||
|
||||
|
||||
# libjuice
|
||||
|
||||
- Upstream: https://github.com/paullouisageneau/libjuice
|
||||
- Version: 1.5.7 (70ba50cce33350b64404557ea63658e925758ce6, 2024)
|
||||
- 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.4.0 (98acb6b02839c609ef5b837794e08d906d965335, 2024)
|
||||
- License: Apache 2.0
|
||||
|
||||
Module location:
|
||||
|
||||
- thirdparty/openssl
|
||||
|
||||
|
||||
## plog
|
||||
|
||||
- Upstream: https://github.com/SergiusTheBest/plog
|
||||
- Version: 1.1.10 (e21baecd4753f14da64ede979c5a19302618b752, 2023)
|
||||
- License: MIT
|
||||
|
||||
Module location:
|
||||
|
||||
- thirdparty/libdatachannel/deps/plog
|
||||
|
||||
|
||||
## usrsctp
|
||||
|
||||
- Upstream: https://github.com/sctplab/usrsctp
|
||||
- Version: git (ebb18adac6501bad4501b1f6dccb67a1c85cc299, 2023)
|
||||
- License: BSD-3-Clause
|
||||
|
||||
Module location:
|
||||
|
||||
- thirdparty/libdatachannel/deps/usrsctp
|
||||
1
thirdparty/libdatachannel
vendored
Submodule
1
thirdparty/libdatachannel
vendored
Submodule
Submodule thirdparty/libdatachannel added at 3c33ea0f49
1
thirdparty/openssl
vendored
Submodule
1
thirdparty/openssl
vendored
Submodule
Submodule thirdparty/openssl added at 98acb6b028
136
tools/cmake.py
Normal file
136
tools/cmake.py
Normal file
@@ -0,0 +1,136 @@
|
||||
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",
|
||||
"arm32": "-march=armv7-a",
|
||||
"arm64": "-march=armv8-a",
|
||||
}.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.get("macos_deployment_target", "default") != "default":
|
||||
config["CMAKE_OSX_DEPLOYMENT_TARGET"] = env["macos_deployment_target"]
|
||||
if 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")
|
||||
298
tools/openssl.py
Normal file
298
tools/openssl.py
Normal file
@@ -0,0 +1,298 @@
|
||||
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-x86_64-xcrun",
|
||||
"arm64": "iossimulator-arm64-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"] == "ios":
|
||||
if env.get("ios_min_version", "default") != "default":
|
||||
if env.get("ios_simulator", False):
|
||||
args.append("-mios-simulator-version-min=%s" % env["ios_min_version"])
|
||||
else:
|
||||
args.append("-miphoneos-version-min=%s" % env["ios_min_version"])
|
||||
elif env["platform"] == "macos":
|
||||
if env.get("macos_deployment_target", "default") != "default":
|
||||
args.append("-mmacosx-version-min=%s" % env["macos_deployment_target"])
|
||||
# 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"])
|
||||
if env["platform"] == "linux":
|
||||
env.PrependUnique(LIBS=["pthread", "dl"])
|
||||
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"])
|
||||
if env["platform"] == "linux":
|
||||
env.PrependUnique(LIBS=["pthread", "dl"])
|
||||
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")
|
||||
53
tools/rtc.py
Normal file
53
tools/rtc.py
Normal file
@@ -0,0 +1,53 @@
|
||||
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"])
|
||||
if env["platform"] == "linux":
|
||||
env.PrependUnique(LIBS=["pthread"])
|
||||
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")
|
||||
Reference in New Issue
Block a user