Compare commits

..

59 Commits

Author SHA1 Message Date
Fabio Alessandrelli
61a6d25c47 Merge pull request #75 from Faless/bump/beta8
Bump godot-cpp to beta8, libdatachannel to v0.18.0
2022-12-10 18:26:25 +01:00
Fabio Alessandrelli
dfaad6f5ba Bump godot-cpp to beta8, libdatachannel to v0.18.0
libdatachannel and libjuice are now released under MPL 2.0.

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

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

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

Override GDN_EXPORT which is incorrectly defined in the upstream
gdnative headers (3.x) and godot-cpp include (4.0) when building for
windows with mingw.
2022-06-18 14:35:51 +02:00
Fabio Alessandrelli
62ab2e59f8 Merge pull request #53 from Faless/fix/build_deps_target
[SCons] Apply "target" to dependencies.
2022-06-18 03:00:48 +02:00
Fabio Alessandrelli
a2fc27f646 [SCons] Apply "target" to dependencies.
Dependencies used to be built with the default option (release for
OpenSSL, debug for libdachannel).
They now follow the desired target (producing smaller binaries in
release, and bigger in debug).
2022-06-18 02:00:18 +02:00
Fabio Alessandrelli
b2654cc2bd Merge pull request #51 from Faless/libdatachannel_pr
Switch to libdatachannel as RTC library. Add GDExtension support.
2022-06-16 11:32:10 +02:00
Fabio Alessandrelli
e19b370126 Use libdatachannel library, add Godot 4 support. 2022-06-15 21:38:12 +02:00
Fabio Alessandrelli
8c18112f5d Merge pull request #43 from dsnopek/buffered-amount
Add get_buffered_amount() to WebRTCDataChannel (GDNative)
2021-09-22 23:06:19 +02:00
Fabio Alessandrelli
c37cc530e7 Merge pull request #46 from Faless/issue_template
Add issue templates for reporting bugs.
2021-07-26 15:39:53 +02:00
Fabio Alessandrelli
13ab33af36 Add issue templates for reporting bugs. 2021-07-26 13:19:29 +02:00
David Snopek
3bdf6cdc13 Add get_buffered_amount() to WebRTCDataChannel 2021-07-21 10:48:09 -05:00
Fabio Alessandrelli
072ba5c1d0 Merge pull request #40 from Faless/osx/arm64
Add OSX arm64 build.
2021-07-11 10:51:37 +02:00
Fabio Alessandrelli
7cb6d6c846 Add OSX arm64 build.
Needs a more recent revision of godot-cpp, but can still use
godot-headers from 3.2 . See CI script update for details.
2021-07-11 10:01:55 +02:00
Fabio Alessandrelli
c0b31562f5 Merge pull request #39 from Faless/style/clang_black
Add static checks
2021-07-09 19:43:04 +02:00
Fabio Alessandrelli
69f92fa26c Run clang-format on src/* 2021-07-09 18:55:32 +02:00
Fabio Alessandrelli
d06e536d12 Add copyright headers 2021-07-09 18:55:32 +02:00
Fabio Alessandrelli
68a892d9f3 run black -l 120 on SConstruct. 2021-07-09 18:55:32 +02:00
Fabio Alessandrelli
72b337e32c static checks. 2021-07-09 18:55:32 +02:00
Fabio Alessandrelli
eeabf0a844 Merge pull request #38 from Faless/refactor/signals
Refactor signals and obeserver, fixes answer creation.
2021-07-09 16:24:35 +02:00
Fabio Alessandrelli
04fbae6ce3 Properly wait success callback before creating answers. 2021-07-09 03:46:25 +02:00
Fabio Alessandrelli
ce3f086ec4 Move observers implementations into PeerConnection. 2021-07-09 03:45:45 +02:00
Fabio Alessandrelli
00ac03c8e7 Use a class instead of lambdas for signals. 2021-07-09 00:53:15 +02:00
Fabio Alessandrelli
fa5296a4e4 Merge pull request #37 from Faless/ci/auto
[CI] Use organization's repository for automated builds.
2021-07-08 23:56:42 +02:00
Fabio Alessandrelli
189c353264 [CI] Use organization's repository for automated builds.
Update README.md to reflect new build sources.
2021-07-08 23:04:16 +02:00
Fabio Alessandrelli
e44c42fde8 Merge pull request #36 from Faless/ci/single
Setup CI for Android, iOS, Linux, macOS, Windows.
2021-07-06 16:27:59 +02:00
Fabio Alessandrelli
524fdde8f2 Setup CI for Android, iOS, Linux, macOS, Windows.
Includes all supported architectures:

* Android:
  - arm (neon)
  - arm64
  - x86
  - x64

* iOS:
  - arm
  - arm64
  - x64 (simulator)

* Linux
  - x86
  - x64

* macOS
  - x64

* windows
  - x86
  - x64

Use a single matrix for builds, then an extra step will package for
release.

Artefacts are generated for each platform/arch combination, along for
the 2 zip containing the full `webrtc` and `webrtc_debug` plugin.
2021-07-06 15:57:55 +02:00
Fabio Alessandrelli
673a4c1a1c Merge pull request #34 from Faless/build/optimization_flags
Fix osx, android optimization flags.
2021-07-05 03:17:27 +02:00
Fabio Alessandrelli
cf98eb2e7a Fix osx, android optimization flags.
Will need to be also fixed in upstream godot-cpp.
2021-07-02 21:58:44 +02:00
34 changed files with 2153 additions and 864 deletions

128
.clang-format Normal file
View File

@@ -0,0 +1,128 @@
# 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 6.0.1).
---
### General config, applies to all languages ###
BasedOnStyle: LLVM
AccessModifierOffset: -4
AlignAfterOpenBracket: DontAlign
# AlignConsecutiveAssignments: false
# AlignConsecutiveDeclarations: false
# AlignEscapedNewlines: Right
# AlignOperands: true
AlignTrailingComments: false
AllowAllParametersOfDeclarationOnNextLine: false
# AllowShortBlocksOnASingleLine: false
# AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Inline
# AllowShortIfStatementsOnASingleLine: false
# AllowShortLoopsOnASingleLine: false
# AlwaysBreakAfterDefinitionReturnType: None
# AlwaysBreakAfterReturnType: None
# AlwaysBreakBeforeMultilineStrings: false
# AlwaysBreakTemplateDeclarations: false
# BinPackArguments: true
# BinPackParameters: true
# BraceWrapping:
# AfterClass: false
# AfterControlStatement: false
# AfterEnum: false
# AfterFunction: false
# AfterNamespace: false
# AfterObjCDeclaration: false
# AfterStruct: false
# AfterUnion: false
# AfterExternBlock: false
# BeforeCatch: false
# BeforeElse: false
# IndentBraces: false
# SplitEmptyFunction: true
# SplitEmptyRecord: true
# SplitEmptyNamespace: true
# BreakBeforeBinaryOperators: None
# BreakBeforeBraces: Attach
# BreakBeforeInheritanceComma: false
BreakBeforeTernaryOperators: false
# BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: AfterColon
# BreakStringLiterals: true
ColumnLimit: 0
# CommentPragmas: '^ IWYU pragma:'
# CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 8
ContinuationIndentWidth: 8
Cpp11BracedListStyle: false
# DerivePointerAlignment: false
# DisableFormat: false
# ExperimentalAutoDetectBinPacking: false
# FixNamespaceComments: true
# ForEachMacros:
# - foreach
# - Q_FOREACH
# - BOOST_FOREACH
# IncludeBlocks: Preserve
IncludeCategories:
- Regex: '".*"'
Priority: 1
- Regex: '^<.*\.h>'
Priority: 2
- Regex: '^<.*'
Priority: 3
# IncludeIsMainRegex: '(Test)?$'
IndentCaseLabels: true
# IndentPPDirectives: None
IndentWidth: 4
# IndentWrappedFunctionNames: false
# JavaScriptQuotes: Leave
# JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: false
# MacroBlockBegin: ''
# MacroBlockEnd: ''
# MaxEmptyLinesToKeep: 1
# NamespaceIndentation: None
# PenaltyBreakAssignment: 2
# PenaltyBreakBeforeFirstCallParameter: 19
# PenaltyBreakComment: 300
# PenaltyBreakFirstLessLess: 120
# PenaltyBreakString: 1000
# PenaltyExcessCharacter: 1000000
# PenaltyReturnTypeOnItsOwnLine: 60
# PointerAlignment: Right
# RawStringFormats:
# - Delimiter: pb
# Language: TextProto
# BasedOnStyle: google
# ReflowComments: true
# SortIncludes: true
# SortUsingDeclarations: true
# SpaceAfterCStyleCast: false
# SpaceAfterTemplateKeyword: true
# SpaceBeforeAssignmentOperators: true
# SpaceBeforeParens: ControlStatements
# SpaceInEmptyParentheses: false
# SpacesBeforeTrailingComments: 1
# SpacesInAngles: false
# SpacesInContainerLiterals: true
# SpacesInCStyleCastParentheses: false
# SpacesInParentheses: false
# SpacesInSquareBrackets: false
TabWidth: 4
UseTab: Always
---
### C++ specific config ###
Language: Cpp
Standard: Cpp11
---
### ObjC specific config ###
Language: ObjC
Standard: Cpp11
ObjCBlockIndentWidth: 4
# ObjCSpaceAfterProperty: false
# ObjCSpaceBeforeProtocolList: true
---
### Java specific config ###
Language: Java
# BreakAfterJavaFieldAnnotations: false
JavaImportGroups: ['org.godotengine', 'android', 'androidx', 'com.android', 'com.google', 'java', 'javax']
...

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

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

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

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

227
.github/workflows/build_release.yml vendored Normal file
View File

@@ -0,0 +1,227 @@
name: 🔧 Build -> Package 📦
on: [push, pull_request]
env:
# Only used for the cache key. Increment version to force clean build.
GODOT_BASE_BRANCH: master
jobs:
static-checks:
name: 📊 Static Checks (clang-format, black format, file format)
runs-on: ubuntu-20.04
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Install dependencies
run: |
sudo apt-get install -qq dos2unix recode clang-format-11
sudo update-alternatives --remove-all clang-format
sudo update-alternatives --install /usr/bin/clang-format clang-format /usr/bin/clang-format-11 100
sudo pip3 install black==20.8b1 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-11'
cache-name: ios-x86_64-simulator
- platform: ios
arch: 'arm64'
gdnative_flags: 'ios_arch=arm64'
sconsflags: ''
os: 'macos-11'
cache-name: ios-arm64
# Linux
- platform: linux
arch: 'x86_32'
gdnative_flags: 'bits=32'
sconsflags: ''
os: 'ubuntu-20.04'
cache-name: linux-x86_32
- platform: linux
arch: 'x86_64'
gdnative_flags: 'bits=64'
sconsflags: ''
os: 'ubuntu-20.04'
cache-name: linux-x86_64
# macOS
- platform: macos
arch: 'x86_64'
gdnative_flags: 'macos_arch=x86_64 bits=64'
sconsflags: ''
os: 'macos-11'
cache-name: macos-x86_64
- platform: macos
gdnative_flags: 'macos_arch=arm64 bits=64'
arch: 'arm64'
sconsflags: ''
os: 'macos-11'
cache-name: macos-arm64
# 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 }} --jobs=2
defaults:
run:
shell: bash
steps:
- uses: actions/checkout@v3
with:
submodules: recursive
- name: Setup Godot build cache
uses: ./godot-cpp/.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 install build-essential gcc-multilib g++-multilib
- name: Set up Python 3.x
uses: actions/setup-python@v4
with:
python-version: '3.x'
architecture: 'x64'
- name: Configuring Python packages
run: |
python -c "import sys; print(sys.version)"
python -m pip install scons
python --version
scons --version
cmake --version
- name: Compile Extension - template_debug - ${{ matrix.platform }} - ${{ matrix.arch }}
run: |
scons target=template_debug generate_bindings=yes
- name: Compile Extension - template_release - ${{ matrix.platform }} - ${{ matrix.arch }}
run: |
scons target=template_release
- name: Compile GDNative - release ${{ matrix.platform }} - ${{ matrix.arch }}
run: |
scons target=release generate_bindings=yes ${{ matrix.gdnative_flags }} godot_version=3
- uses: actions/upload-artifact@v3
with:
name: ${{ github.job }}-${{ matrix.platform }}-${{ matrix.arch }}
path: |
bin/
!bin/thirdparty/
package:
name: 📦 Package
needs: build
runs-on: "ubuntu-latest"
steps:
- uses: actions/checkout@v3
with:
submodules: recursive
- uses: actions/download-artifact@v3
with:
path: artifacts
- name: Bundle licenses.
run: |
cp LICENSE artifacts/LICENSE.webrtc-native
cp thirdparty/libdatachannel/LICENSE artifacts/LICENSE.libdatachannel
cp thirdparty/openssl/LICENSE.txt artifacts/LICENSE.openssl
cp thirdparty/libdatachannel/deps/libjuice/LICENSE artifacts/LICENSE.libjuice
cp thirdparty/libdatachannel/deps/usrsctp/LICENSE.md artifacts/LICENSE.usrsctp
cp thirdparty/libdatachannel/deps/libsrtp/LICENSE artifacts/LICENSE.libsrtp
cp thirdparty/libdatachannel/deps/json/LICENSE.MIT artifacts/LICENSE.json
cp thirdparty/libdatachannel/deps/plog/LICENSE artifacts/LICENSE.plog
- name: Package artifacts for release
env:
DESTINATION: "release"
run: |
mkdir release
VERSION="extension" TYPE="webrtc" ./misc/scripts/package_release.sh
VERSION="gdnative" TYPE="webrtc" ./misc/scripts/package_release.sh
ls -R release
- uses: actions/upload-artifact@v3
with:
name: godot-webrtc-extension
path: release/*-extension-*.zip
- uses: actions/upload-artifact@v3
with:
name: godot-webrtc-gdnative
path: release/*-gdnative-*.zip

11
.gitmodules vendored
View File

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

View File

@@ -7,15 +7,10 @@
### Compiling
Clone this repository with the following command to checkout both [godot-cpp](https://github.com/GodotNativeTools/godot-cpp) and [godot_headers](https://github.com/GodotNativeTools/godot_headers) dependencies.
Clone this repository with the following command to checkout all the dependencies: [godot-cpp](https://github.com/godotengine/godot-cpp), [openssl](https://www.openssl.org/) and [libdatachannel](https://github.com/paullouisageneau/libdatachannel) (and sub-dependencies).
```
$ git clone --recurse-submodules git@github.com:godotengine/webrtc-native.git
```
Note that if you wish to use a specific branch, add the -b option to the clone command:
```
$ git clone --recurse-submodules -b 3.2 git@github.com:godotengine/webrtc-native.git
$ 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:
@@ -24,43 +19,30 @@ If you already checked out the branch use the following commands to update the d
$ git submodule update --init --recursive
```
Right now our directory structure should look like this:
```
webrtc-native/
├─bin/
├─godot-cpp/
| └─godot_headers/
├─src/
└─webrtc/
```
### Compiling the extension.
### Compiling the cpp bindings library
First, we need to compile our cpp bindings library:
```
$ cd godot-cpp
$ scons platform=<your platform> generate_bindings=yes
$ cd ..
```
> Replace `<your platform>` with either `windows`, `linux` or `osx`.
> Include `use_llvm=yes` for using clang++
> Include `target=runtime` to build a runtime build (windows only at the moment)
> Include `target=release` or `target=debug` for release or debug build.
> The resulting library will be created in `godot-cpp/bin/`, take note of its name as it will be different depending on platform.
### Building WebRTC
Use [this script](https://github.com/Faless/webrtc-builds) to build and package the WebRTCLibrary (`branch-heads/68`), or [**download latest pre-compiled binaries**](https://github.com/Faless/webrtc-builds/releases)
Extract content of `include` into `webrtc/include` and content of `bin` into `webrtc/<your platform>`
### Compiling the plugin.
To build the GDExtension version of the plugin (Godot 4.0) run the following command from the `webrtc-native` folder:
```
$ scons platform=<your platform> target=<your target>
$ scons platform=<your platform>
```
The generated library and associated `gdns` will be placed in `bin/webrtc/` or `bin/webrtc_debug/` according to the desired target. You simply need to copy that folder into your project.
This will build all the required dependencies into a single shared library.
To build the GDNative version of the plugin (Godot 3.x) run the following command instead:
```
$ scons platform=<your platform> godot_version=3
```
> Replace `<your platform>` with either `windows`, `linux`, `osx`, `android`, or `ios`.
> Include `target=release` or `target=debug` for release or debug build (default is `debug`).
The resulting library and associated `tres` or `gdextension` will be created in `bin/[extension|gdnative]/webrtc[_debug]` depending on the `target` and `godot_version`.
You simply need to copy that folder to the root folder of your project. Note that you will have to build the library for all the desired export platforms.
### License
The `webrtc-native` plugin is licensed under the MIT license (see [LICENSE](https://github.com/godotengine/webrtc-native/blob/master/LICENSE)), while `libdatachannel` and its dependencies are licensed under other permissive open source licences. Please see [`thirdparty/README.md`](thirdparty/README.md) for more informations.

View File

@@ -2,343 +2,164 @@
import os, sys, platform, json, subprocess
if sys.version_info < (3,):
def decode_utf8(x):
return x
else:
import codecs
def decode_utf8(x):
return codecs.utf_8_decode(x)[0]
import builders
def add_sources(sources, dirpath, extension):
for f in os.listdir(dirpath):
if f.endswith('.' + extension):
sources.append(dirpath + '/' + f)
for f in os.listdir(dirpath):
if f.endswith("." + extension):
sources.append(dirpath + "/" + f)
def gen_gdnative_lib(target, source, env):
for t in target:
with open(t.srcnode().path, 'w') as w:
w.write(decode_utf8(source[0].get_contents()).replace('{GDNATIVE_PATH}', os.path.splitext(t.name)[0]).replace('{TARGET}', env['target']))
def replace_flags(flags, replaces):
for k, v in replaces.items():
if k in flags:
flags[flags.index(k)] = v
env = Environment()
target_arch = ARGUMENTS.get('b', ARGUMENTS.get('bits', '64'))
target_platform = ARGUMENTS.get('p', ARGUMENTS.get('platform', 'linux'))
if target_platform == 'windows':
# This makes sure to keep the session environment variables on windows,
# that way you can run scons in a vs 2017 prompt and it will find all the required tools
if (target_arch == '64'):
env = Environment(ENV = os.environ, TARGET_ARCH='amd64')
else:
env = Environment(ENV = os.environ, TARGET_ARCH='x86')
env.Append(BUILDERS={'GDNativeLibBuilder': Builder(action=gen_gdnative_lib)})
customs = ['custom.py']
opts = Variables(customs, ARGUMENTS)
opts.Add(BoolVariable('use_llvm', 'Use the LLVM compiler', False))
opts.Add(EnumVariable('target', "Compilation target", 'debug', ('debug', 'release')))
opts.Add(EnumVariable(
'android_arch',
'Target Android architecture',
'armv7',
['armv7','arm64v8', 'x86', 'x86_64']
))
opts.Add(
'android_api_level',
'Target Android API level',
'18' if ARGUMENTS.get("android_arch", 'armv7') in ['armv7', 'x86'] else '21'
)
opts.Add(
'ANDROID_NDK_ROOT',
'Path to your Android NDK installation. By default, uses ANDROID_NDK_ROOT from your defined environment variables.',
os.environ.get("ANDROID_NDK_ROOT", None)
)
opts.Add(EnumVariable(
'ios_arch',
'Target iOS architecture',
'arm64',
['armv7', 'arm64', 'x86_64']
))
opts.Add(BoolVariable(
'ios_simulator',
'Target iOS Simulator',
False
))
opts.Add(
'IPHONEPATH',
'Path to iPhone toolchain',
'/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain',
)
# Update environment (parse options)
opts = Variables(["customs.py"], ARGUMENTS)
opts.Add(EnumVariable("godot_version", "The Godot target version", "4", ["3", "4"]))
opts.Update(env)
target = env['target']
if env["godot_version"] == "3":
if "platform" in ARGUMENTS and ARGUMENTS["platform"] == "macos":
ARGUMENTS["platform"] = "osx" # compatibility with old osx name
if target_platform == 'android':
target_arch = env['android_arch']
elif target_platform == 'ios':
target_arch = env['ios_arch']
scons_cache_path = os.environ.get("SCONS_CACHE")
if scons_cache_path is not None:
CacheDir(scons_cache_path)
Decider("MD5")
host_platform = platform.system()
# Local dependency paths, adapt them to your setup
godot_headers = ARGUMENTS.get('headers', 'godot-cpp/godot-headers')
godot_cpp_headers = ARGUMENTS.get('godot_cpp_headers', 'godot-cpp/include')
godot_cpp_lib_dir = ARGUMENTS.get('godot_cpp_lib_dir', 'godot-cpp/bin')
result_path = os.path.join('bin', 'webrtc' if env['target'] == 'release' else 'webrtc_debug', 'lib')
lib_prefix = ""
env = SConscript("godot-cpp-3.x/SConstruct")
# Convenience check to enforce the use_llvm overrides when CXX is clang(++)
if 'CXX' in env and 'clang' in os.path.basename(env['CXX']):
env['use_llvm'] = True
# Patch base env
replace_flags(env["CCFLAGS"], {
"-mios-simulator-version-min=10.0": "-mios-simulator-version-min=11.0",
"-miphoneos-version-min=10.0": "-miphoneos-version-min=11.0",
"/std:c++14": "/std:c++17",
"-std=c++14": "-std=c++17",
})
if target_platform == 'linux':
env['CXX']='g++'
env = env.Clone()
# LLVM
if env['use_llvm']:
if ('clang++' not in os.path.basename(env['CXX'])):
env['CC'] = 'clang'
env["CXX"] = "clang++"
env["LINK"] = "clang++"
if env["target"] == "debug":
env.Append(CPPDEFINES=["DEBUG_ENABLED"])
if (env["target"] == "debug"):
env.Prepend(CCFLAGS=['-g3'])
env.Append(LINKFLAGS=['-rdynamic'])
else:
env.Prepend(CCFLAGS=['-O3'])
if env["platform"] == "windows" and env["use_mingw"]:
env.Append(LINKFLAGS=["-static-libgcc"])
env.Append(CCFLAGS=['-fPIC', '-std=c++14'])
if env["platform"] == "osx":
env["platform"] = "macos" # compatibility with old osx name
ARGUMENTS["platform"] = "macos"
if target_arch == '32':
env.Append(CCFLAGS = [ '-m32' ])
env.Append(LINKFLAGS = [ '-m32' ])
elif target_arch == '64':
env.Append(CCFLAGS = [ '-m64' ])
env.Append(LINKFLAGS = [ '-m64' ])
# i386 does not like static libstdc++
env.Append(LINKFLAGS=['-static-libgcc', '-static-libstdc++'])
elif target_platform == 'windows':
if host_platform == 'Windows':
lib_prefix = "lib"
env.Append(LINKFLAGS = [ '/WX' ])
if target == 'debug':
env.Append(CCFLAGS = ['/EHsc', '/D_DEBUG', '/MDd' ])
else:
env.Append(CCFLAGS = ['/O2', '/EHsc', '/DNDEBUG', '/MD' ])
else:
if target_arch == '32':
env['CXX']='i686-w64-mingw32-g++'
elif target_arch == '64':
env['CXX']='x86_64-w64-mingw32-g++'
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'
env.Append(CCFLAGS = [ '-g','-O3', '-std=c++14', '-arch', 'x86_64' ])
env.Append(LINKFLAGS = [ '-arch', 'x86_64', '-framework', 'Cocoa', '-Wl,-undefined,dynamic_lookup' ])
if env['target'] == 'debug':
env.Append(CCFLAGS=['-Og', '-g'])
elif env['target'] == 'release':
env.Append(CCFLAGS=['-O3'])
elif target_platform == 'ios':
if env['ios_simulator']:
sdk_name = 'iphonesimulator'
env.Append(CCFLAGS=['-mios-simulator-version-min=10.0'])
env['LIBSUFFIX'] = ".simulator" + env['LIBSUFFIX']
else:
sdk_name = 'iphoneos'
env.Append(CCFLAGS=['-miphoneos-version-min=10.0'])
try:
sdk_path = decode_utf8(subprocess.check_output(['xcrun', '--sdk', sdk_name, '--show-sdk-path']).strip())
except (subprocess.CalledProcessError, OSError):
raise ValueError("Failed to find SDK path while running xcrun --sdk {} --show-sdk-path.".format(sdk_name))
compiler_path = env['IPHONEPATH'] + '/usr/bin/'
env['ENV']['PATH'] = env['IPHONEPATH'] + "/Developer/usr/bin/:" + env['ENV']['PATH']
env['CC'] = compiler_path + 'clang'
env['CXX'] = compiler_path + 'clang++'
env['AR'] = compiler_path + 'ar'
env['RANLIB'] = compiler_path + 'ranlib'
env.Append(CCFLAGS=['-std=c++14', '-arch', env['ios_arch'], '-isysroot', sdk_path])
env.Append(LINKFLAGS=[
'-arch',
env['ios_arch'],
'-Wl,-undefined,dynamic_lookup',
'-isysroot', sdk_path,
'-F' + sdk_path
])
if env['target'] == 'debug':
env.Append(CCFLAGS=['-Og', '-g'])
elif env['target'] == 'release':
env.Append(CCFLAGS=['-O3'])
elif target_platform == 'android':
# Verify NDK root
if not 'ANDROID_NDK_ROOT' in env:
raise ValueError("To build for Android, ANDROID_NDK_ROOT must be defined. Please set ANDROID_NDK_ROOT to the root folder of your Android NDK installation.")
# Validate API level
api_level = int(env['android_api_level'])
if target_arch in ['arm64v8', 'x86_64'] and api_level < 21:
print("WARN: 64-bit Android architectures require an API level of at least 21; setting android_api_level=21")
env['android_api_level'] = '21'
api_level = 21
# Setup toolchain
toolchain = env['ANDROID_NDK_ROOT'] + "/toolchains/llvm/prebuilt/"
if host_platform == "Windows":
toolchain += "windows"
import platform as pltfm
if pltfm.machine().endswith("64"):
toolchain += "-x86_64"
elif host_platform == "Linux":
toolchain += "linux-x86_64"
elif host_platform == "Darwin":
toolchain += "darwin-x86_64"
# Get architecture info
arch_info_table = {
"armv7" : {
"march":"armv7-a", "target":"armv7a-linux-androideabi", "tool_path":"arm-linux-androideabi", "compiler_path":"armv7a-linux-androideabi",
"ccflags" : ['-mfpu=neon']
},
"arm64v8" : {
"march":"armv8-a", "target":"aarch64-linux-android", "tool_path":"aarch64-linux-android", "compiler_path":"aarch64-linux-android",
"ccflags" : []
},
"x86" : {
"march":"i686", "target":"i686-linux-android", "tool_path":"i686-linux-android", "compiler_path":"i686-linux-android",
"ccflags" : ['-mstackrealign']
},
"x86_64" : {"march":"x86-64", "target":"x86_64-linux-android", "tool_path":"x86_64-linux-android", "compiler_path":"x86_64-linux-android",
"ccflags" : []
}
}
arch_info = arch_info_table[target_arch]
# Setup tools
env['CC'] = toolchain + "/bin/clang"
env['CXX'] = toolchain + "/bin/clang++"
env.Append(CCFLAGS=['--target=' + arch_info['target'] + env['android_api_level'], '-march=' + arch_info['march'], '-fPIC'])
env.Append(CCFLAGS=arch_info['ccflags'])
env.Append(LINKFLAGS=['--target=' + arch_info['target'] + env['android_api_level'], '-march=' + arch_info['march']])
# Normalize suffix
if env["platform"] in ["windows", "linux"]:
env["arch"] = "x86_32" if env["bits"] == "32" else "x86_64"
env["arch_suffix"] = env["arch"]
elif env["platform"] == "macos":
env["arch"] = env["macos_arch"]
env["arch_suffix"] = env["arch"]
elif env["platform"] == "ios":
env["arch"] = "arm32" if env["ios_arch"] == "armv7" else env["ios_arch"]
env["arch_suffix"] = env["ios_arch"] + (".simulator" if env["ios_simulator"] else "")
elif env["platform"] == "android":
env["arch"] = {
"armv7": "arm32",
"arm64v8": "arm64",
"x86": "x86_32",
"x86_64": "x86_64",
}[env["android_arch"]]
env["arch_suffix"] = env["arch"]
target_compat = "template_" + env["target"]
env["suffix"] = ".{}.{}.{}".format(env["platform"], target_compat, env["arch_suffix"])
env["debug_symbols"] = False
else:
print("No valid target platform selected.")
sys.exit(1)
ARGUMENTS["ios_min_version"] = "11.0"
env = SConscript("godot-cpp/SConstruct").Clone()
# Godot CPP bindings
env.Append(CPPPATH=[godot_headers])
env.Append(CPPPATH=[godot_cpp_headers, godot_cpp_headers + '/core', godot_cpp_headers + '/gen'])
env.Append(LIBPATH=[godot_cpp_lib_dir])
env.Append(LIBS=['%sgodot-cpp.%s.%s.%s%s' % (lib_prefix, target_platform, target, target_arch, ".simulator" if env["ios_simulator"] else "")])
# Should probably go to upstream godot-cpp.
# We let SCons build its default ENV as it includes OS-specific things which we don't
# want to have to pull in manually.
# Then we prepend PATH to make it take precedence, while preserving SCons' own entries.
env.PrependENVPath("PATH", os.getenv("PATH"))
env.PrependENVPath("PKG_CONFIG_PATH", os.getenv("PKG_CONFIG_PATH"))
if "TERM" in os.environ: # Used for colored output.
env["ENV"]["TERM"] = os.environ["TERM"]
# WebRTC stuff
webrtc_dir = "webrtc"
lib_name = 'libwebrtc_full'
lib_path = os.path.join(webrtc_dir, target_platform)
# Patch mingw SHLIBSUFFIX.
if env["platform"] == "windows" and env["use_mingw"]:
env["SHLIBSUFFIX"] = ".dll"
lib_path += {'32': '/x86',
'64': '/x64',
'armv7': '/arm',
'arm64v8': '/arm64',
'arm64': '/arm64',
'x86': '/x86',
'x86_64': '/x64'}[target_arch]
opts.Update(env)
if target == 'debug':
lib_path += '/Debug'
target = env["target"]
if env["godot_version"] == "3":
result_path = os.path.join("bin", "gdnative", "webrtc" if env["target"] == "release" else "webrtc_debug")
else:
lib_path += '/Release'
result_path = os.path.join("bin", "extension", "webrtc")
env.Append(CPPPATH=[webrtc_dir + "/include", webrtc_dir + "/include/third_party/abseil-cpp"])
# Dependencies
env.Append(BUILDERS={
"BuildOpenSSL": env.Builder(action=builders.ssl_action, emitter=builders.ssl_emitter),
"BuildLibDataChannel": env.Builder(action=builders.rtc_action, emitter=builders.rtc_emitter),
})
if target_platform == "linux":
env.Append(LIBS=[lib_name, "atomic"])
env.Append(LIBPATH=[lib_path])
#env.Append(CCFLAGS=["-std=c++11"])
env.Append(CCFLAGS=["-DWEBRTC_POSIX", "-DWEBRTC_LINUX"])
env.Append(CCFLAGS=["-DRTC_UNUSED=''", "-DNO_RETURN=''"])
# SSL
ssl = env.BuildOpenSSL(env.Dir(builders.get_ssl_build_dir(env)), env.Dir(builders.get_ssl_source_dir(env)))
env.Depends(ssl, [env.File("builders.py"), env.File(builders.get_ssl_source_dir(env) + "/VERSION.dat")])
env.NoCache(ssl) # Needs refactoring to properly cache generated headers.
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])
env.Prepend(CPPPATH=[builders.get_ssl_include_dir(env)])
env.Prepend(LIBPATH=[builders.get_ssl_build_dir(env)])
env.Append(LIBS=[builders.get_ssl_libs(env)])
elif target_platform == "osx":
env.Append(LIBS=[lib_name])
env.Append(LIBPATH=[lib_path])
env.Append(CCFLAGS=["-DWEBRTC_POSIX", "-DWEBRTC_MAC"])
env.Append(CCFLAGS=["-DRTC_UNUSED=''", "-DNO_RETURN=''"])
# RTC
rtc = env.BuildLibDataChannel(env.Dir(builders.get_rtc_build_dir(env)), [env.Dir(builders.get_rtc_source_dir(env))] + ssl)
env.Depends(rtc, [env.File("builders.py"), env.File(builders.get_rtc_source_dir(env) + "/CMakeLists.txt")])
elif target_platform == 'ios':
env.Append(LIBS=[lib_name])
env.Append(LIBPATH=[lib_path])
env.Append(CCFLAGS=["-DWEBRTC_POSIX", "-DWEBRTC_MAC", "-DWEBRTC_IOS"])
env.Append(CCFLAGS=["-DRTC_UNUSED=''", "-DNO_RETURN=''"])
elif target_platform == "android":
env.Append(LIBS=['log'])
env.Append(LIBS=[lib_name])
env.Append(LIBPATH=[lib_path])
env.Append(CCFLAGS=["-DWEBRTC_POSIX", "-DWEBRTC_LINUX", "-DWEBRTC_ANDROID"])
env.Append(CCFLAGS=["-DRTC_UNUSED=''", "-DNO_RETURN=''"])
if target_arch == 'arm64v8':
env.Append(CCFLAGS=["-DWEBRTC_ARCH_ARM64", "-DWEBRTC_HAS_NEON"])
elif target_arch == 'armv7':
env.Append(CCFLAGS=["-DWEBRTC_ARCH_ARM", "-DWEBRTC_ARCH_ARM_V7", "-DWEBRTC_HAS_NEON"])
env.Append(LIBPATH=[builders.get_rtc_build_dir(env)])
env.Append(CPPPATH=[builders.get_rtc_include_dir(env)])
env.Prepend(LIBS=[builders.get_rtc_libs(env)])
# 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"] == "4":
sources.append("src/init_gdextension.cpp")
else:
env.Append(CPPDEFINES=["GDNATIVE_WEBRTC"])
sources.append("src/init_gdnative.cpp")
add_sources(sources, "src/net/", "cpp")
# Suffix
suffix = '.%s.%s' % (target, target_arch)
env["SHOBJSUFFIX"] = suffix + env["SHOBJSUFFIX"]
env.Depends(sources, [builders.get_ssl_libs(env), builders.get_rtc_libs(env)])
# Make the shared library
result_name = 'webrtc_native.%s.%s.%s' % (target_platform, target, target_arch) + env["SHLIBSUFFIX"]
result_name = "webrtc_native{}{}".format(env["suffix"], env["SHLIBSUFFIX"])
env.Depends(sources, ssl)
library = env.SharedLibrary(target=os.path.join(result_path, result_name), source=sources)
if env["platform"] == "windows" and env["use_mingw"]:
env.Append(LIBS=["iphlpapi", "ws2_32", "bcrypt"])
library = env.SharedLibrary(target=os.path.join(result_path, "lib", result_name), source=sources)
Default(library)
# GDNativeLibrary
gdnlib = 'webrtc'
if target != 'release':
gdnlib += '_debug'
Default(env.GDNativeLibBuilder([os.path.join('bin', gdnlib, gdnlib + '.tres')], ['misc/gdnlib.tres']))
if env["godot_version"] == "3":
gdnlib = "webrtc" if target != "debug" else "webrtc_debug"
ext = ".tres"
extfile = env.Substfile(os.path.join(result_path, gdnlib + ext), "misc/webrtc" + ext, SUBST_DICT={
"{GDNATIVE_PATH}": gdnlib,
"{TARGET}": "template_" + env["target"],
})
else:
extfile = env.InstallAs(os.path.join(result_path, "webrtc.gdextension"), "misc/webrtc.gdextension")
Default(extfile)

247
builders.py Normal file
View File

@@ -0,0 +1,247 @@
import os
from SCons.Defaults import Mkdir
from SCons.Script import Environment
def get_android_api(env):
return env["android_api_level"] if int(env["android_api_level"]) > 28 else "28"
def get_deps_dir(env):
return env.Dir("#thirdparty").abspath
def get_deps_build_dir(env):
return env.Dir("#bin/thirdparty").abspath + "/{}.{}.dir".format(env["suffix"][1:], "RelWithDebInfo" if env["debug_symbols"] else "Release")
def get_rtc_source_dir(env):
return get_deps_dir(env) + "/libdatachannel"
def get_rtc_build_dir(env):
return get_deps_build_dir(env) + "/libdatachannel"
def get_rtc_include_dir(env):
return get_rtc_source_dir(env) + "/include"
def get_rtc_libs(env):
bdir = get_rtc_build_dir(env)
libs = [
"libdatachannel-static.a",
"deps/libjuice/libjuice-static.a",
"deps/libsrtp/libsrtp2.a",
"deps/usrsctp/usrsctplib/libusrsctp.a"
]
return [env.File(bdir + "/" + lib) for lib in libs]
def get_ssl_source_dir(env):
return get_deps_dir(env) + "/openssl"
def get_ssl_build_dir(env):
return get_deps_build_dir(env) + "/openssl"
def get_ssl_install_dir(env):
return get_ssl_build_dir(env) + "/dest"
def get_ssl_include_dir(env):
return get_ssl_install_dir(env) + "/include"
def get_ssl_libs(env):
bdir = get_ssl_build_dir(env)
return [env.File(bdir + "/" + lib) for lib in ["libssl.a", "libcrypto.a"]]
def ssl_emitter(target, source, env):
return get_ssl_libs(env), source
def ssl_action(target, source, env):
build_dir = get_ssl_build_dir(env)
source_dir = source[0].abspath
ssl_env = env.Clone()
install_dir = get_ssl_install_dir(env)
args = [
"no-ssl3",
"no-weak-ssl-ciphers",
"no-legacy",
"--prefix=%s" % install_dir,
"--openssldir=%s" % install_dir,
]
if env["debug_symbols"]:
args.append("-d")
if env["platform"] != "windows":
args.append("no-shared") # Windows "app" doesn't like static-only builds.
if env["platform"] == "linux":
if env["arch"] == "x86_32":
args.extend(["linux-x86"])
else:
args.extend(["linux-x86_64"])
elif env["platform"] == "android":
args.extend([
{
"arm64": "android-arm64",
"arm32": "android-arm",
"x86_32": "android-x86",
"x86_64": "android-x86_64",
}[env["arch"]],
"-D__ANDROID_API__=%s" % get_android_api(env),
])
# Setup toolchain path.
ssl_env.PrependENVPath("PATH", os.path.dirname(env["CC"]))
ssl_env["ENV"]["ANDROID_NDK_ROOT"] = os.environ.get("ANDROID_NDK_ROOT", "")
elif env["platform"] == "macos":
if env["arch"] == "x86_64":
args.extend(["darwin64-x86_64"])
elif env["arch"] == "arm64":
args.extend(["darwin64-arm64"])
else:
raise ValueError("macOS architecture not supported: %s" % env["arch"])
elif env["platform"] == "ios":
if env["ios_simulator"]:
args.extend(["iossimulator-xcrun"])
elif env["arch"] == "arm32":
args.extend(["ios-xcrun"])
elif env["arch"] == "arm64":
args.extend(["ios64-xcrun"])
else:
raise ValueError("iOS architecture not supported: %s" % env["arch"])
elif env["platform"] == "windows":
if env["arch"] == "x86_32":
if env["use_mingw"]:
args.extend([
"mingw",
"--cross-compile-prefix=i686-w64-mingw32-",
])
else:
args.extend(["VC-WIN32"])
else:
if env["use_mingw"]:
args.extend([
"mingw64",
"--cross-compile-prefix=x86_64-w64-mingw32-",
])
else:
args.extend(["VC-WIN64A"])
jobs = env.GetOption("num_jobs")
ssl_env.Execute([
Mkdir(build_dir),
"cd %s && perl %s/Configure %s" % (build_dir, source_dir, " ".join(['"%s"' % a for a in args])),
"make -C %s -j%s" % (build_dir, jobs),
"make -C %s install_sw install_ssldirs -j%s" % (build_dir, jobs),
]
)
return None
def rtc_emitter(target, source, env):
return get_rtc_libs(env), source
def rtc_action(target, source, env):
build_dir = get_rtc_build_dir(env)
source_dir = source[0].abspath
args = [
"cmake",
"-B",
build_dir,
"-DUSE_NICE=0",
"-DNO_WEBSOCKET=1",
#"-DNO_MEDIA=1", # Windows builds fail without it.
"-DNO_EXAMPLES=1",
"-DNO_TESTS=1",
"-DOPENSSL_USE_STATIC_LIBS=1",
"-DOPENSSL_INCLUDE_DIR=%s" % get_ssl_include_dir(env),
"-DOPENSSL_SSL_LIBRARY=%s/libssl.a" % get_ssl_build_dir(env),
"-DOPENSSL_CRYPTO_LIBRARY=%s/libcrypto.a" % get_ssl_build_dir(env),
"-DCMAKE_BUILD_TYPE=%s" % ("RelWithDebInfo" if env["debug_symbols"] else "Release"),
]
if env["platform"] == "android":
abi = {
"arm64": "arm64-v8a",
"arm32": "armeabi-v7a",
"x86_32": "x86",
"x86_64": "x86_64",
}[env["arch"]]
args.extend([
"-DCMAKE_SYSTEM_NAME=Android",
"-DCMAKE_SYSTEM_VERSION=%s" % get_android_api(env),
"-DCMAKE_ANDROID_ARCH_ABI=%s" % abi,
"-DANDROID_ABI=%s" % abi,
"-DCMAKE_TOOLCHAIN_FILE=%s/build/cmake/android.toolchain.cmake" % os.environ.get("ANDROID_NDK_ROOT", ""),
"-DCMAKE_ANDROID_STL_TYPE=c++_static",
])
elif env["platform"] == "linux":
if env["arch"] == "x86_32":
args.extend([
"-DCMAKE_C_FLAGS=-m32",
"-DCMAKE_CXX_FLAGS=-m32"
])
else:
args.extend([
"-DCMAKE_C_FLAGS=-m64",
"-DCMAKE_CXX_FLAGS=-m64"
])
elif env["platform"] == "macos":
if env["macos_deployment_target"] != "default":
args.extend(["-DCMAKE_OSX_DEPLOYMENT_TARGET=%s" % env["macos_deployment_target"]])
if env["arch"] == "x86_64":
args.extend(["-DCMAKE_OSX_ARCHITECTURES=x86_64"])
elif env["arch"] == "arm64":
args.extend(["-DCMAKE_OSX_ARCHITECTURES=arm64"])
else:
raise ValueError("OSX architecture not supported: %s" % env["arch"])
elif env["platform"] == "ios":
if env["arch"] == "universal":
raise ValueError("iOS architecture not supported: %s" % env["arch"])
args.extend([
"-DCMAKE_SYSTEM_NAME=iOS",
"-DCMAKE_OSX_DEPLOYMENT_TARGET=11.0",
"-DCMAKE_OSX_ARCHITECTURES=%s" % env["arch"],
])
if env["ios_simulator"]:
args.extend(["-DCMAKE_OSX_SYSROOT=iphonesimulator"])
elif env["platform"] == "windows":
args.extend(["-DOPENSSL_ROOT_DIR=%s" % get_ssl_build_dir(env)])
if env["arch"] == "x86_32":
if env["use_mingw"]:
args.extend([
"-G",
"Unix Makefiles",
"-DCMAKE_C_COMPILER=i686-w64-mingw32-gcc",
"-DCMAKE_CXX_COMPILER=i686-w64-mingw32-g++",
"-DCMAKE_SYSTEM_NAME=Windows",
])
else:
if env["use_mingw"]:
args.extend([
"-G",
"Unix Makefiles",
"-DCMAKE_C_COMPILER=x86_64-w64-mingw32-gcc",
"-DCMAKE_CXX_COMPILER=x86_64-w64-mingw32-g++",
"-DCMAKE_SYSTEM_NAME=Windows"
])
args.append(source_dir)
jobs = env.GetOption("num_jobs")
rtc_env = env.Clone()
rtc_env.Execute([
" ".join(['"%s"' % a for a in args]),
"cmake --build %s -t datachannel-static -j%s" % (build_dir, jobs)
]
)
return None

1
godot-cpp-3.x Submodule

Submodule godot-cpp-3.x added at ac572d5f84

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

@@ -0,0 +1,34 @@
#!/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=$(find \( -path "./.git" \
-o -path "./webrtc" \
-o -path "./godot-cpp" \
\) -prune \
-o \( -name "SConstruct" \
-o -name "SCsub" \
-o -name "*.py" \
\) -print)
black -l 120 $PY_FILES
git diff > patch.patch
# If no patch has been generated all is OK, clean up, and exit.
if [ ! -s patch.patch ] ; then
printf "Files in this commit comply with the black style rules.\n"
rm -f patch.patch
exit 0
fi
# A patch has been created, notify the user, clean up, and exit.
printf "\n*** The following differences were found between the code "
printf "and the formatting rules:\n\n"
cat patch.patch
printf "\n*** Aborting, please fix your commit(s) with 'git commit --amend' or 'git rebase -i <hash>'\n"
rm -f patch.patch
exit 1

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

@@ -0,0 +1,58 @@
#!/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
IFS=$'\n\t'
CLANG_FORMAT_FILE_EXTS=(".c" ".h" ".cpp" ".hpp" ".cc" ".hh" ".cxx" ".m" ".mm" ".inc" ".java" ".glsl")
# Loops through all text files tracked by Git.
git grep -zIl '' |
while IFS= read -rd '' f; do
# Exclude some files.
if [[ "$f" == "thirdparty"* ]]; then
continue
elif [[ "$f" == "platform/android/java/lib/src/com/google"* ]]; then
continue
elif [[ "$f" == *"-so_wrap."* ]]; then
continue
fi
for extension in ${CLANG_FORMAT_FILE_EXTS[@]}; do
if [[ "$f" == *"$extension" ]]; then
# Run clang-format.
clang-format -i "$f"
# Fix copyright headers, but not all files get them.
if [[ "$f" == *"inc" ]]; then
continue 2
elif [[ "$f" == *"glsl" ]]; then
continue 2
elif [[ "$f" == *"theme_data.h" ]]; then
continue 2
elif [[ "$f" == "platform/android/java/lib/src/org/godotengine/godot/input/InputManager"* ]]; then
continue 2
fi
python misc/scripts/copyright_headers.py "$f"
continue 2
fi
done
done
git diff > patch.patch
# If no patch has been generated all is OK, clean up, and exit.
if [ ! -s patch.patch ] ; then
printf "Files in this commit comply with the clang-format style rules.\n"
rm -f patch.patch
exit 0
fi
# A patch has been created, notify the user, clean up, and exit.
printf "\n*** The following differences were found between the code "
printf "and the formatting rules:\n\n"
cat patch.patch
printf "\n*** Aborting, please fix your commit(s) with 'git commit --amend' or 'git rebase -i <hash>'\n"
rm -f patch.patch
exit 1

View File

@@ -0,0 +1,95 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
header = """\
/*************************************************************************/
/* $filename */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
"""
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()

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

@@ -0,0 +1,50 @@
#!/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 recode.
if [ ! -x "$(command -v dos2unix)" -o ! -x "$(command -v recode)" ]; then
printf "Install 'dos2unix' and 'recode' to use this script.\n"
fi
set -uo pipefail
IFS=$'\n\t'
# Loops through all text files tracked by Git.
git grep -zIl '' |
while IFS= read -rd '' f; do
# Exclude some types of files.
if [[ "$f" == "webrtc"* ]]; then
continue
elif [[ "$f" == "godot-cpp"* ]]; then
continue
elif [[ "$f" == "misc/patches"* ]]; then
continue
fi
# Ensure that files are UTF-8 formatted.
recode UTF-8 "$f" 2> /dev/null
# 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
git diff > patch.patch
# If no patch has been generated all is OK, clean up, and exit.
if [ ! -s patch.patch ] ; then
printf "Files in this commit comply with the formatting rules.\n"
rm -f patch.patch
exit 0
fi
# A patch has been created, notify the user, clean up, and exit.
printf "\n*** The following differences were found between the code "
printf "and the formatting rules:\n\n"
cat patch.patch
printf "\n*** Aborting, please fix your commit(s) with 'git commit --amend' or 'git rebase -i <hash>'\n"
rm -f patch.patch
exit 1

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

@@ -0,0 +1,32 @@
#!/bin/bash
set -e
set -x
ARTIFACTS=${ARTIFACTS:-"artifacts"}
DESTINATION=${DESTIONATION:-"release"}
VERSION=${VERSION:-"extension"}
TYPE=${TYPE:-"webrtc"}
mkdir -p ${DESTINATION}
ls -R ${DESTINATION}
DESTDIR="${DESTINATION}/${VERSION}/${TYPE}"
mkdir -p ${DESTDIR}/lib
find "${ARTIFACTS}" -wholename "*/${VERSION}/${TYPE}/lib/*" | xargs cp -t "${DESTDIR}/lib/"
find "${ARTIFACTS}" -wholename "*/LICENSE*" | xargs cp -t "${DESTDIR}/"
if [ $VERSION = "extension" ]; then
find "${ARTIFACTS}" -wholename "*/${VERSION}/${TYPE}/${TYPE}.gdextension" | head -n 1 | xargs cp -t "${DESTDIR}/"
else
find "${ARTIFACTS}" -wholename "*/${VERSION}/${TYPE}/${TYPE}.tres" | 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}

27
misc/webrtc.gdextension Normal file
View File

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

View File

@@ -3,21 +3,19 @@
[resource]
singleton = true
reloadable = false
entry/OSX.64 = "res://{GDNATIVE_PATH}/lib/libwebrtc_native.osx.{TARGET}.64.dylib"
entry/OSX.64 = "res://{GDNATIVE_PATH}/lib/libwebrtc_native.osx.{TARGET}.x86_64.dylib"
entry/OSX.arm64 = "res://{GDNATIVE_PATH}/lib/libwebrtc_native.osx.{TARGET}.arm64.dylib"
entry/Windows.64 = "res://{GDNATIVE_PATH}/lib/webrtc_native.windows.{TARGET}.64.dll"
entry/Windows.32 = "res://{GDNATIVE_PATH}/lib/webrtc_native.windows.{TARGET}.32.dll"
entry/X11.64 = "res://{GDNATIVE_PATH}/lib/libwebrtc_native.linux.{TARGET}.64.so"
entry/X11.32 = "res://{GDNATIVE_PATH}/lib/libwebrtc_native.linux.{TARGET}.32.so"
entry/Server.64 = "res://{GDNATIVE_PATH}/lib/libwebrtc_native.linux.{TARGET}.64.so"
entry/Server.32 = "res://{GDNATIVE_PATH}/lib/libwebrtc_native.linux.{TARGET}.32.so"
entry/Android.armeabi-v7a = "res://{GDNATIVE_PATH}/lib/libwebrtc_native.android.{TARGET}.armv7.so"
entry/Android.arm64-v8a = "res://{GDNATIVE_PATH}/lib/libwebrtc_native.android.{TARGET}.arm64v8.so"
entry/Windows.64 = "res://{GDNATIVE_PATH}/lib/libwebrtc_native.windows.{TARGET}.x86_64.dll"
entry/Windows.32 = "res://{GDNATIVE_PATH}/lib/libwebrtc_native.windows.{TARGET}.x86_32.dll"
entry/X11.64 = "res://{GDNATIVE_PATH}/lib/libwebrtc_native.linux.{TARGET}.x86_64.so"
entry/X11.32 = "res://{GDNATIVE_PATH}/lib/libwebrtc_native.linux.{TARGET}.x86_32.so"
entry/Server.64 = "res://{GDNATIVE_PATH}/lib/libwebrtc_native.linux.{TARGET}.x86_64.so"
entry/Server.32 = "res://{GDNATIVE_PATH}/lib/libwebrtc_native.linux.{TARGET}.x86_32.so"
entry/Android.arm64-v8a = "res://{GDNATIVE_PATH}/lib/libwebrtc_native.android.{TARGET}.arm64.so"
entry/Android.x64 = "res://{GDNATIVE_PATH}/lib/libwebrtc_native.android.{TARGET}.x86_64.so"
entry/Android.x86 = "res://{GDNATIVE_PATH}/lib/libwebrtc_native.android.{TARGET}.x86.so"
entry/iOS.armv7 = "res://{GDNATIVE_PATH}/lib/libwebrtc_native.ios.{TARGET}.armv7.dylib"
entry/iOS.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.dylib"
entry/iOS.x86_64 = "res://{GDNATIVE_PATH}/lib/libwebrtc_native.ios.{TARGET}.x86_64.simulator.dylib"
dependency/Windows.64 = [ ]
dependency/Windows.32 = [ ]
dependency/X11.64 = [ ]

View File

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

View File

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

View File

@@ -1,53 +0,0 @@
#include "WebRTCLibDataChannel.hpp"
#include "WebRTCLibPeerConnection.hpp"
using namespace godot_webrtc;
// CreateSessionObseerver
WebRTCLibPeerConnection::GodotCSDO::GodotCSDO(WebRTCLibPeerConnection *parent) {
this->parent = parent;
}
void WebRTCLibPeerConnection::GodotCSDO::OnSuccess(webrtc::SessionDescriptionInterface *desc) {
// serialize this offer and send it to the remote peer:
std::string sdp; // sdp = session description protocol
desc->ToString(&sdp);
parent->queue_signal("session_description_created", 2, desc->type().c_str(), sdp.c_str());
};
void WebRTCLibPeerConnection::GodotCSDO::OnFailure(webrtc::RTCError error){};
// SetSessionObseerver
WebRTCLibPeerConnection::GodotSSDO::GodotSSDO(WebRTCLibPeerConnection *parent) {
this->parent = parent;
}
void WebRTCLibPeerConnection::GodotSSDO::OnSuccess(){};
void WebRTCLibPeerConnection::GodotSSDO::OnFailure(webrtc::RTCError error){};
// PeerConnectionObserver
WebRTCLibPeerConnection::GodotPCO::GodotPCO(WebRTCLibPeerConnection *parent) {
this->parent = parent;
}
void WebRTCLibPeerConnection::GodotPCO::OnDataChannel(rtc::scoped_refptr<webrtc::DataChannelInterface> data_channel) {
parent->queue_signal("data_channel_received", 1, WebRTCLibDataChannel::new_data_channel(data_channel));
}
void WebRTCLibPeerConnection::GodotPCO::OnIceCandidate(const webrtc::IceCandidateInterface *candidate) {
godot::Dictionary candidateSDP;
godot::String candidateSdpMidName = candidate->sdp_mid().c_str();
int candidateSdpMlineIndexName = candidate->sdp_mline_index();
std::string sdp;
candidate->ToString(&sdp);
godot::String candidateSdpName = sdp.c_str();
parent->queue_signal("ice_candidate_created", 3, candidateSdpMidName, candidateSdpMlineIndexName, candidateSdpName);
}
void WebRTCLibPeerConnection::GodotPCO::OnSignalingChange(webrtc::PeerConnectionInterface::SignalingState new_state) {}
void WebRTCLibPeerConnection::GodotPCO::OnAddStream(rtc::scoped_refptr<webrtc::MediaStreamInterface> stream) {}
void WebRTCLibPeerConnection::GodotPCO::OnRemoveStream(rtc::scoped_refptr<webrtc::MediaStreamInterface> stream) {}
void WebRTCLibPeerConnection::GodotPCO::OnRenegotiationNeeded() {}
void WebRTCLibPeerConnection::GodotPCO::OnIceConnectionChange(webrtc::PeerConnectionInterface::IceConnectionState new_state) {}
void WebRTCLibPeerConnection::GodotPCO::OnIceGatheringChange(webrtc::PeerConnectionInterface::IceGatheringState new_state) {}

View File

@@ -1,258 +1,336 @@
#include "WebRTCDataChannel.hpp"
#include "WebRTCDataChannelGDNative.hpp"
/*************************************************************************/
/* WebRTCLibPeerConnection.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "WebRTCLibPeerConnection.hpp"
#include "WebRTCLibDataChannel.hpp"
using namespace godot;
using namespace godot_webrtc;
std::unique_ptr<rtc::Thread> WebRTCLibPeerConnection::signaling_thread = nullptr;
#ifdef GDNATIVE_WEBRTC
#define OK Error::OK
#define FAILED Error::FAILED
#define ERR_UNCONFIGURED Error::ERR_UNCONFIGURED
#define ERR_INVALID_PARAMETER Error::ERR_INVALID_PARAMETER
#endif
void WebRTCLibPeerConnection::initialize_signaling() {
if (signaling_thread.get() == nullptr) {
signaling_thread = rtc::Thread::Create();
}
signaling_thread->Start();
#ifdef DEBUG_ENABLED
rtc::InitLogger(rtc::LogLevel::Debug);
#endif
}
void WebRTCLibPeerConnection::deinitialize_signaling() {
if (signaling_thread.get() != nullptr) {
signaling_thread->Stop();
}
}
godot_error _parse_ice_server(webrtc::PeerConnectionInterface::RTCConfiguration &r_config, godot::Dictionary p_server) {
godot::Variant v;
webrtc::PeerConnectionInterface::IceServer ice_server;
godot::String url;
ERR_FAIL_COND_V(!p_server.has("urls"), GODOT_ERR_INVALID_PARAMETER);
Error WebRTCLibPeerConnection::_parse_ice_server(rtc::Configuration &r_config, Dictionary p_server) {
ERR_FAIL_COND_V(!p_server.has("urls"), ERR_INVALID_PARAMETER);
// Parse mandatory URL
v = p_server["urls"];
if (v.get_type() == godot::Variant::STRING) {
url = v;
ice_server.urls.push_back(url.utf8().get_data());
} else if (v.get_type() == godot::Variant::ARRAY) {
godot::Array names = v;
for (int j = 0; j < names.size(); j++) {
v = names[j];
ERR_FAIL_COND_V(v.get_type() != godot::Variant::STRING, GODOT_ERR_INVALID_PARAMETER);
url = v;
ice_server.urls.push_back(url.utf8().get_data());
}
Array urls;
Variant urls_var = p_server["urls"];
if (urls_var.get_type() == Variant::STRING) {
urls.push_back(urls_var);
} else if (urls_var.get_type() == Variant::ARRAY) {
urls = urls_var;
} else {
ERR_FAIL_V(GODOT_ERR_INVALID_PARAMETER);
ERR_FAIL_V(ERR_INVALID_PARAMETER);
}
// Parse credentials (only meaningful for TURN, only support password)
if (p_server.has("username") && (v = p_server["username"]) && v.get_type() == godot::Variant::STRING) {
ice_server.username = (v.operator godot::String()).utf8().get_data();
String username;
String credential;
if (p_server.has("username") && p_server["username"].get_type() == Variant::STRING) {
username = p_server["username"];
}
if (p_server.has("credential") && (v = p_server["credential"]) && v.get_type() == godot::Variant::STRING) {
ice_server.password = (v.operator godot::String()).utf8().get_data();
if (p_server.has("credential") && p_server["credential"].get_type() == Variant::STRING) {
credential = p_server["credential"];
}
r_config.servers.push_back(ice_server);
return GODOT_OK;
for (int i = 0; i < urls.size(); i++) {
rtc::IceServer srv(urls[i].operator String().utf8().get_data());
srv.username = username.utf8().get_data();
srv.password = credential.utf8().get_data();
r_config.iceServers.push_back(srv);
}
return OK;
}
godot_error _parse_channel_config(webrtc::DataChannelInit &r_config, godot::Dictionary p_dict) {
godot::Variant v;
#define _SET_N(PROP, PNAME, TYPE) if (p_dict.has(#PROP)) { v = p_dict[#PROP]; if(v.get_type() == godot::Variant::TYPE) r_config.PNAME = v; }
#define _SET(PROP, TYPE) _SET_N(PROP, PROP, TYPE)
_SET(negotiated, BOOL);
_SET(id, INT);
_SET_N(maxPacketLifeTime, maxRetransmitTime, INT);
_SET(maxRetransmits, INT);
_SET(ordered, BOOL);
#undef _SET
if (p_dict.has("protocol") && (v = p_dict["protocol"]) && v.get_type() == godot::Variant::STRING) {
r_config.protocol = v.operator godot::String().utf8().get_data();
Error WebRTCLibPeerConnection::_parse_channel_config(rtc::DataChannelInit &r_config, const Dictionary &p_dict) {
Variant nil;
Variant v;
if (p_dict.has("negotiated")) {
r_config.negotiated = p_dict["negotiated"].operator bool();
}
// ID makes sense only when negotiated is true (and must be set in that case)
ERR_FAIL_COND_V(r_config.negotiated ? r_config.id == -1 : r_config.id != -1, GODOT_ERR_INVALID_PARAMETER);
// Only one of maxRetransmits and maxRetransmitTime can be set on a channel.
ERR_FAIL_COND_V(r_config.maxRetransmits && r_config.maxRetransmitTime, GODOT_ERR_INVALID_PARAMETER);
return GODOT_OK;
if (p_dict.has("id")) {
r_config.id = uint16_t(p_dict["id"].operator int32_t());
}
// If negotiated it must have an ID, and ID only makes sense when negotiated.
ERR_FAIL_COND_V(r_config.negotiated != r_config.id.has_value(), ERR_INVALID_PARAMETER);
// Channels cannot be both time-constrained and retry-constrained.
ERR_FAIL_COND_V(p_dict.has("maxPacketLifeTime") && p_dict.has("maxRetransmits"), ERR_INVALID_PARAMETER);
if (p_dict.has("maxPacketLifeTime")) {
r_config.reliability.type = rtc::Reliability::Type::Timed;
r_config.reliability.rexmit = std::chrono::milliseconds(p_dict["maxPacketLifeTime"].operator int32_t());
} else if (p_dict.has("maxRetransmits")) {
r_config.reliability.type = rtc::Reliability::Type::Rexmit;
r_config.reliability.rexmit = p_dict["maxRetransmits"].operator int32_t();
}
if (p_dict.has("ordered") && p_dict["ordered"].operator bool() == false) {
r_config.reliability.unordered = true;
}
if (p_dict.has("protocol")) {
r_config.protocol = p_dict["protocol"].operator String().utf8().get_data();
}
return OK;
}
WebRTCLibPeerConnection::ConnectionState WebRTCLibPeerConnection::get_connection_state() const {
ERR_FAIL_COND_V(peer_connection.get() == nullptr, STATE_CLOSED);
WebRTCPeerConnection::ConnectionState WebRTCLibPeerConnection::_get_connection_state() const {
ERR_FAIL_COND_V(peer_connection == nullptr, STATE_CLOSED);
webrtc::PeerConnectionInterface::IceConnectionState state = peer_connection->ice_connection_state();
switch(state) {
case webrtc::PeerConnectionInterface::kIceConnectionNew:
rtc::PeerConnection::State state = peer_connection->state();
switch (state) {
case rtc::PeerConnection::State::New:
return STATE_NEW;
case webrtc::PeerConnectionInterface::kIceConnectionChecking:
case rtc::PeerConnection::State::Connecting:
return STATE_CONNECTING;
case webrtc::PeerConnectionInterface::kIceConnectionConnected:
case rtc::PeerConnection::State::Connected:
return STATE_CONNECTED;
case webrtc::PeerConnectionInterface::kIceConnectionCompleted:
return STATE_CONNECTED;
case webrtc::PeerConnectionInterface::kIceConnectionFailed:
return STATE_FAILED;
case webrtc::PeerConnectionInterface::kIceConnectionDisconnected:
case rtc::PeerConnection::State::Disconnected:
return STATE_DISCONNECTED;
case webrtc::PeerConnectionInterface::kIceConnectionClosed:
return STATE_CLOSED;
case rtc::PeerConnection::State::Failed:
return STATE_FAILED;
default:
return STATE_CLOSED;
}
}
godot_error WebRTCLibPeerConnection::initialize(const godot_dictionary *p_config) {
webrtc::PeerConnectionInterface::RTCConfiguration config;
godot::Dictionary d = *(godot::Dictionary *)p_config;
godot::Variant v;
if (d.has("iceServers") && (v = d["iceServers"]) && v.get_type() == godot::Variant::ARRAY) {
godot::Array servers = v;
WebRTCLibPeerConnection::GatheringState WebRTCLibPeerConnection::_get_gathering_state() const {
ERR_FAIL_COND_V(peer_connection == nullptr, GATHERING_STATE_NEW);
rtc::PeerConnection::GatheringState state = peer_connection->gatheringState();
switch (state) {
case rtc::PeerConnection::GatheringState::New:
return GATHERING_STATE_NEW;
case rtc::PeerConnection::GatheringState::InProgress:
return GATHERING_STATE_GATHERING;
case rtc::PeerConnection::GatheringState::Complete:
return GATHERING_STATE_COMPLETE;
default:
return GATHERING_STATE_NEW;
}
}
WebRTCLibPeerConnection::SignalingState WebRTCLibPeerConnection::_get_signaling_state() const {
ERR_FAIL_COND_V(peer_connection == nullptr, SIGNALING_STATE_CLOSED);
rtc::PeerConnection::SignalingState state = peer_connection->signalingState();
switch (state) {
case rtc::PeerConnection::SignalingState::Stable:
return SIGNALING_STATE_STABLE;
case rtc::PeerConnection::SignalingState::HaveLocalOffer:
return SIGNALING_STATE_HAVE_LOCAL_OFFER;
case rtc::PeerConnection::SignalingState::HaveRemoteOffer:
return SIGNALING_STATE_HAVE_REMOTE_OFFER;
case rtc::PeerConnection::SignalingState::HaveLocalPranswer:
return SIGNALING_STATE_HAVE_LOCAL_PRANSWER;
case rtc::PeerConnection::SignalingState::HaveRemotePranswer:
return SIGNALING_STATE_HAVE_REMOTE_PRANSWER;
default:
return SIGNALING_STATE_CLOSED;
}
}
Error WebRTCLibPeerConnection::_initialize(const Dictionary &p_config) {
rtc::Configuration config = {};
if (p_config.has("iceServers") && p_config["iceServers"].get_type() == Variant::ARRAY) {
Array servers = p_config["iceServers"];
for (int i = 0; i < servers.size(); i++) {
v = servers[i];
ERR_FAIL_COND_V(v.get_type() != godot::Variant::DICTIONARY, GODOT_ERR_INVALID_PARAMETER);
godot_error err;
godot::Dictionary server = v;
err = _parse_ice_server(config, server);
ERR_FAIL_COND_V(err != GODOT_OK, err);
ERR_FAIL_COND_V(servers[i].get_type() != Variant::DICTIONARY, ERR_INVALID_PARAMETER);
Dictionary server = servers[i];
Error err = _parse_ice_server(config, server);
ERR_FAIL_COND_V(err != OK, FAILED);
}
}
return _create_pc(config);
}
godot_object *WebRTCLibPeerConnection::create_data_channel(const char *p_channel, const godot_dictionary *p_channel_config) {
ERR_FAIL_COND_V(peer_connection.get() == nullptr, NULL);
Object *WebRTCLibPeerConnection::_create_data_channel(const String &p_channel, const Dictionary &p_channel_config) try {
ERR_FAIL_COND_V(!peer_connection, nullptr);
// Read config from dictionary
webrtc::DataChannelInit config;
godot::Dictionary d = *(godot::Dictionary *)p_channel_config;
godot_error err = _parse_channel_config(config, d);
ERR_FAIL_COND_V(err != GODOT_OK, NULL);
rtc::DataChannelInit config;
WebRTCLibDataChannel *wrapper = WebRTCLibDataChannel::new_data_channel(peer_connection->CreateDataChannel(p_channel, &config));
ERR_FAIL_COND_V(wrapper == NULL, NULL);
return wrapper->_owner;
Error err = _parse_channel_config(config, p_channel_config);
ERR_FAIL_COND_V(err != OK, nullptr);
std::shared_ptr<rtc::DataChannel> ch = peer_connection->createDataChannel(p_channel.utf8().get_data(), config);
ERR_FAIL_COND_V(ch == nullptr, nullptr);
WebRTCLibDataChannel *wrapper = WebRTCLibDataChannel::new_data_channel(ch, ch->id().has_value());
ERR_FAIL_COND_V(wrapper == nullptr, nullptr);
return wrapper;
} catch (const std::exception &e) {
ERR_PRINT(e.what());
ERR_FAIL_V(nullptr);
}
godot_error WebRTCLibPeerConnection::create_offer() {
ERR_FAIL_COND_V(peer_connection.get() == nullptr, GODOT_ERR_UNCONFIGURED);
peer_connection->CreateOffer(ptr_csdo, webrtc::PeerConnectionInterface::RTCOfferAnswerOptions());
return GODOT_OK;
Error WebRTCLibPeerConnection::_create_offer() try {
ERR_FAIL_COND_V(!peer_connection, ERR_UNCONFIGURED);
ERR_FAIL_COND_V(_get_connection_state() != STATE_NEW, FAILED);
peer_connection->setLocalDescription(rtc::Description::Type::Offer);
return OK;
} catch (const std::exception &e) {
ERR_PRINT(e.what());
ERR_FAIL_V(FAILED);
}
#define _MAKE_DESC(TYPE, SDP) webrtc::CreateSessionDescription((godot::String(TYPE) == godot::String("offer") ? webrtc::SdpType::kOffer : webrtc::SdpType::kAnswer), SDP)
godot_error WebRTCLibPeerConnection::set_remote_description(const char *type, const char *sdp) {
ERR_FAIL_COND_V(peer_connection.get() == nullptr, GODOT_ERR_UNCONFIGURED);
std::unique_ptr<webrtc::SessionDescriptionInterface> desc = _MAKE_DESC(type, sdp);
peer_connection->SetRemoteDescription(ptr_ssdo, desc.release());
peer_connection->CreateAnswer(ptr_csdo, webrtc::PeerConnectionInterface::RTCOfferAnswerOptions());
return GODOT_OK;
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);
}
godot_error WebRTCLibPeerConnection::set_local_description(const char *type, const char *sdp) {
ERR_FAIL_COND_V(peer_connection.get() == nullptr, GODOT_ERR_UNCONFIGURED);
std::unique_ptr<webrtc::SessionDescriptionInterface> desc = _MAKE_DESC(type, sdp);
peer_connection->SetLocalDescription(ptr_ssdo, desc.release());
return GODOT_OK;
}
#undef _MAKE_DESC
godot_error WebRTCLibPeerConnection::add_ice_candidate(const char *sdpMidName, int sdpMlineIndexName, const char *sdpName) {
ERR_FAIL_COND_V(peer_connection.get() == nullptr, GODOT_ERR_UNCONFIGURED);
webrtc::SdpParseError *error = nullptr;
webrtc::IceCandidateInterface *candidate = webrtc::CreateIceCandidate(
sdpMidName,
sdpMlineIndexName,
sdpName,
error);
ERR_FAIL_COND_V(error || !candidate, GODOT_ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V(!peer_connection->AddIceCandidate(candidate), GODOT_FAILED);
return GODOT_OK;
Error WebRTCLibPeerConnection::_set_local_description(const String &p_type, const String &p_sdp) {
ERR_FAIL_COND_V(!peer_connection, ERR_UNCONFIGURED);
// XXX Library quirk. It doesn't seem possible to create offers/answers without setting the local description.
// Ignore this call for now to avoid crash (it's already set automatically!).
//peer_connection->setLocalDescription(p_type == String("offer") ? rtc::Description::Type::Offer : rtc::Description::Type::Answer);
return OK;
}
godot_error WebRTCLibPeerConnection::poll() {
ERR_FAIL_COND_V(peer_connection.get() == nullptr, GODOT_ERR_UNCONFIGURED);
Error WebRTCLibPeerConnection::_add_ice_candidate(const String &sdpMidName, int64_t sdpMlineIndexName, const String &sdpName) try {
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);
std::function<void()> signal;
while (!signal_queue.empty()) {
mutex_signal_queue->lock();
signal = signal_queue.front();
Signal signal = signal_queue.front();
signal_queue.pop();
mutex_signal_queue->unlock();
signal();
signal.emit(this);
}
return GODOT_OK;
return OK;
}
void WebRTCLibPeerConnection::close() {
if (peer_connection.get() != nullptr) {
peer_connection->Close();
void WebRTCLibPeerConnection::_close() {
if (peer_connection != nullptr) {
try {
peer_connection->close();
} catch (...) {
}
}
peer_connection = nullptr;
while(!signal_queue.empty()) {
while (!signal_queue.empty()) {
signal_queue.pop();
}
}
void WebRTCLibPeerConnection::_register_methods() {
}
void WebRTCLibPeerConnection::_init() {
#ifdef GDNATIVE_WEBRTC
register_interface(&interface);
// initialize variables:
#endif
mutex_signal_queue = new std::mutex;
// create a PeerConnectionFactoryInterface:
webrtc::PeerConnectionFactoryDependencies deps;
ERR_FAIL_COND(signaling_thread.get() == nullptr);
deps.signaling_thread = signaling_thread.get();
pc_factory = webrtc::CreateModularPeerConnectionFactory(std::move(deps));
// Create peer connection with default configuration.
webrtc::PeerConnectionInterface::RTCConfiguration config;
_create_pc(config);
_initialize(Dictionary());
}
godot_error WebRTCLibPeerConnection::_create_pc(webrtc::PeerConnectionInterface::RTCConfiguration &config) {
ERR_FAIL_COND_V(pc_factory.get() == nullptr, GODOT_ERR_BUG);
peer_connection = nullptr;
peer_connection = pc_factory->CreatePeerConnection(config, nullptr, nullptr, &pco);
if (peer_connection.get() == nullptr) { // PeerConnection couldn't be created. Fail the method call.
ERR_PRINT("PeerConnection could not be created");
return GODOT_FAILED;
}
return GODOT_OK;
Error WebRTCLibPeerConnection::_create_pc(rtc::Configuration &r_config) try {
// Prevents libdatachannel from automatically creating offers.
r_config.disableAutoNegotiation = true;
peer_connection = std::make_shared<rtc::PeerConnection>(r_config);
ERR_FAIL_COND_V(!peer_connection, FAILED);
// Binding this should be fine as long as we call close when going out of scope.
peer_connection->onLocalDescription([this](rtc::Description description) {
String type = description.type() == rtc::Description::Type::Offer ? "offer" : "answer";
queue_signal("session_description_created", 2, type, String(std::string(description).c_str()));
});
peer_connection->onLocalCandidate([this](rtc::Candidate candidate) {
queue_signal("ice_candidate_created", 3, String(candidate.mid().c_str()), 0, String(candidate.candidate().c_str()));
});
peer_connection->onDataChannel([this](std::shared_ptr<rtc::DataChannel> channel) {
queue_signal("data_channel_received", 1, WebRTCLibDataChannel::new_data_channel(channel, false));
});
/*
peer_connection->onStateChange([](rtc::PeerConnection::State state) {
std::cout << "[State: " << state << "]" << std::endl;
});
peer_connection->onGatheringStateChange([](rtc::PeerConnection::GatheringState state) {
std::cout << "[Gathering State: " << state << "]" << std::endl;
});
*/
return OK;
} catch (const std::exception &e) {
ERR_PRINT(e.what());
ERR_FAIL_V(FAILED);
}
WebRTCLibPeerConnection::WebRTCLibPeerConnection() :
pco(this),
ptr_csdo(new rtc::RefCountedObject<GodotCSDO>(this)),
ptr_ssdo(new rtc::RefCountedObject<GodotSSDO>(this)) {
WebRTCLibPeerConnection::WebRTCLibPeerConnection() {
#ifndef GDNATIVE_WEBRTC
_init();
#endif
}
WebRTCLibPeerConnection::~WebRTCLibPeerConnection() {
#ifdef GDNATIVE_WEBRTC
if (_owner) {
register_interface(NULL);
register_interface(nullptr);
}
close();
#endif
_close();
delete mutex_signal_queue;
}
void WebRTCLibPeerConnection::queue_signal(godot::String p_name, int p_argc, const godot::Variant &p_arg1, const godot::Variant &p_arg2, const godot::Variant &p_arg3) {
void WebRTCLibPeerConnection::queue_signal(String p_name, int p_argc, const Variant &p_arg1, const Variant &p_arg2, const Variant &p_arg3) {
mutex_signal_queue->lock();
signal_queue.push(
[this, p_name, p_argc, p_arg1, p_arg2, p_arg3] {
if (p_argc == 1) {
emit_signal(p_name, p_arg1);
} else if (p_argc == 2) {
emit_signal(p_name, p_arg1, p_arg2);
} else {
emit_signal(p_name, p_arg1, p_arg2, p_arg3);
}
});
const Variant argv[3] = { p_arg1, p_arg2, p_arg3 };
signal_queue.push(Signal(p_name, p_argc, argv));
mutex_signal_queue->unlock();
}

View File

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

78
src/init_gdextension.cpp Normal file
View File

@@ -0,0 +1,78 @@
/*************************************************************************/
/* init_gdextension.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include <godot/gdnative_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" {
GDNativeBool GDN_EXPORT webrtc_extension_init(const GDNativeInterface *p_interface, const GDNativeExtensionClassLibraryPtr p_library, GDNativeInitialization *r_initialization) {
GDExtensionBinding::InitObject init_obj(p_interface, p_library, r_initialization);
init_obj.register_initializer(register_webrtc_extension_types);
init_obj.register_terminator(unregister_webrtc_extension_types);
init_obj.set_minimum_library_initialization_level(MODULE_INITIALIZATION_LEVEL_SCENE);
return init_obj.init();
}
}

View File

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

View File

@@ -1,6 +1,38 @@
/*************************************************************************/
/* WebRTCDataChannelNative.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "WebRTCDataChannelNative.hpp"
#include "net/WebRTCPeerConnectionNative.hpp"
using namespace godot;
void WebRTCDataChannelNative::register_interface(const godot_net_webrtc_data_channel *p_interface) {
ERR_FAIL_COND(!WebRTCPeerConnectionNative::_net_api);
WebRTCPeerConnectionNative::_net_api->godot_net_bind_webrtc_data_channel(_owner, p_interface);
@@ -24,69 +56,73 @@ WebRTCDataChannelNative::~WebRTCDataChannelNative() {
* and you could use void *user for any kind of state struct pointer you have.
*/
godot_error get_packet_wdc(void *user, const uint8_t **r_buffer, int *r_len) {
return ((WebRTCDataChannelNative *)user)->get_packet(r_buffer, r_len);
return (godot_error)(((WebRTCDataChannelNative *)user)->_get_packet(r_buffer, r_len));
}
godot_error put_packet_wdc(void *user, const uint8_t *p_buffer, int p_len) {
return ((WebRTCDataChannelNative *)user)->put_packet(p_buffer, p_len);
return (godot_error)(((WebRTCDataChannelNative *)user)->_put_packet(p_buffer, p_len));
}
godot_int get_available_packet_count_wdc(const void *user) {
return ((WebRTCDataChannelNative *)user)->get_available_packet_count();
return ((WebRTCDataChannelNative *)user)->_get_available_packet_count();
}
godot_int get_max_packet_size_wdc(const void *user) {
return ((WebRTCDataChannelNative *)user)->get_max_packet_size();
return ((WebRTCDataChannelNative *)user)->_get_max_packet_size();
}
void set_write_mode_wdc(void *user, godot_int write_mode) {
((WebRTCDataChannelNative *)user)->set_write_mode(write_mode);
((WebRTCDataChannelNative *)user)->_set_write_mode((godot::WebRTCDataChannel::WriteMode)write_mode);
}
godot_int get_write_mode_wdc(const void *user) {
return ((WebRTCDataChannelNative *)user)->get_write_mode();
return ((WebRTCDataChannelNative *)user)->_get_write_mode();
}
bool was_string_packet_wdc(const void *user) {
return ((WebRTCDataChannelNative *)user)->was_string_packet();
return ((WebRTCDataChannelNative *)user)->_was_string_packet();
}
godot_int get_ready_state_wdc(const void *user) {
return (godot_int)(((WebRTCDataChannelNative *)user)->get_ready_state());
return (godot_int)(((WebRTCDataChannelNative *)user)->_get_ready_state());
}
const char *get_label_wdc(const void *user) {
return ((WebRTCDataChannelNative *)user)->get_label();
return ((WebRTCDataChannelNative *)user)->_get_label().utf8().get_data();
}
bool is_ordered_wdc(const void *user) {
return ((WebRTCDataChannelNative *)user)->is_ordered();
return ((WebRTCDataChannelNative *)user)->_is_ordered();
}
int get_id_wdc(const void *user) {
return ((WebRTCDataChannelNative *)user)->get_id();
return ((WebRTCDataChannelNative *)user)->_get_id();
}
int get_max_packet_life_time_wdc(const void *user) {
return ((WebRTCDataChannelNative *)user)->get_max_packet_life_time();
return ((WebRTCDataChannelNative *)user)->_get_max_packet_life_time();
}
int get_max_retransmits_wdc(const void *user) {
return ((WebRTCDataChannelNative *)user)->get_max_retransmits();
return ((WebRTCDataChannelNative *)user)->_get_max_retransmits();
}
const char *get_protocol_wdc(const void *user) {
return ((WebRTCDataChannelNative *)user)->get_protocol();
return ((WebRTCDataChannelNative *)user)->_get_protocol().utf8().get_data();
}
bool is_negotiated_wdc(const void *user) {
return ((WebRTCDataChannelNative *)user)->is_negotiated();
return ((WebRTCDataChannelNative *)user)->_is_negotiated();
}
int get_buffered_amount_wdc(const void *user) {
return ((WebRTCDataChannelNative *)user)->_get_buffered_amount();
}
godot_error poll_wdc(void *user) {
return ((WebRTCDataChannelNative *)user)->poll();
return (godot_error)(((WebRTCDataChannelNative *)user)->_poll());
}
void close_wdc(void *user) {
((WebRTCDataChannelNative *)user)->close();
((WebRTCDataChannelNative *)user)->_close();
}

View File

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

View File

@@ -1,5 +1,37 @@
/*************************************************************************/
/* WebRTCPeerConnectionNative.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "WebRTCPeerConnectionNative.hpp"
using namespace godot;
const godot_gdnative_ext_net_3_2_api_struct *WebRTCPeerConnectionNative::_net_api = NULL;
void WebRTCPeerConnectionNative::register_interface(const godot_net_webrtc_peer_connection *p_interface) {
@@ -25,19 +57,23 @@ WebRTCPeerConnectionNative::~WebRTCPeerConnectionNative() {
* and you could use void *user for any kind of state struct pointer you have.
*/
godot_int get_connection_state_wp(const void *user) {
return (godot_int)((WebRTCPeerConnectionNative *)user)->get_connection_state();
return (godot_int)((WebRTCPeerConnectionNative *)user)->_get_connection_state();
}
godot_error initialize_wp(void *user, const godot_dictionary *p_config) {
return ((WebRTCPeerConnectionNative *)user)->initialize(p_config);
return (godot_error)(((WebRTCPeerConnectionNative *)user)->_initialize(*(Dictionary *)p_config));
}
godot_object *create_data_channel_wp(void *user, const char *p_channel, const godot_dictionary *p_channel_config) {
return ((WebRTCPeerConnectionNative *)user)->create_data_channel(p_channel, p_channel_config);
Object *ptr = ((WebRTCPeerConnectionNative *)user)->_create_data_channel(p_channel, *(Dictionary *)p_channel_config);
if (ptr) {
return ptr->_owner;
}
return nullptr;
}
godot_error create_offer_wp(void *user) {
return ((WebRTCPeerConnectionNative *)user)->create_offer();
return (godot_error)(((WebRTCPeerConnectionNative *)user)->_create_offer());
}
godot_error create_answer_wp(void *user) {
@@ -45,21 +81,21 @@ godot_error create_answer_wp(void *user) {
}
godot_error set_remote_description_wp(void *user, const char *type, const char *sdp) {
return ((WebRTCPeerConnectionNative *)user)->set_remote_description(type, sdp);
return (godot_error)(((WebRTCPeerConnectionNative *)user)->_set_remote_description(type, sdp));
}
godot_error set_local_description_wp(void *user, const char *type, const char *sdp) {
return ((WebRTCPeerConnectionNative *)user)->set_local_description(type, sdp);
return (godot_error)(((WebRTCPeerConnectionNative *)user)->_set_local_description(type, sdp));
}
godot_error add_ice_candidate_wp(void *user, const char *sdpMidName, int sdpMlineIndexName, const char *sdpName) {
return ((WebRTCPeerConnectionNative *)user)->add_ice_candidate(sdpMidName, sdpMlineIndexName, sdpName);
return (godot_error)(((WebRTCPeerConnectionNative *)user)->_add_ice_candidate(sdpMidName, sdpMlineIndexName, sdpName));
}
godot_error poll_wp(void *user) {
return ((WebRTCPeerConnectionNative *)user)->poll();
return (godot_error)((WebRTCPeerConnectionNative *)user)->_poll();
}
void close_wp(void *user) {
((WebRTCPeerConnectionNative *)user)->close();
((WebRTCPeerConnectionNative *)user)->_close();
}

View File

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

82
thirdparty/README.md vendored Normal file
View File

@@ -0,0 +1,82 @@
# Third party libraries
Please keep categories (`##` level) listed alphabetically and matching their
respective folder names. Use two empty lines to separate categories for
readability.
## json
- Upstream: https://github.com/nlohmann/json
- Version: 3.10.5 (4f8fba14066156b73f1189a2b8bd568bde5284c5, 2022)
- License: MIT
Module location:
- thirdparty/libdatachannel/deps/json
## libdatachannel
- Upstream: https://github.com/paullouisageneau/libdatachannel
- Version: 0.18.0 (084445012d6c63c9f2cc250d88df553aed2eb189, 2022)
- License: MPL 2.0
Module location:
- thirdparty/libdatachannel
# libjuice
- Upstream: https://github.com/paullouisageneau/libjuice
- Version: 1.1.0 (0dabc046cd23da6908749e4c6add834ec29a7c49, 2022)
- License: MPL 2.0
Module location:
- thirdparty/libdatachannel/deps/libjuice
## libsrtp
- Upstream: https://github.com/cisco/libsrtp
- Version: 2.4.2 (90d05bf8980d16e4ac3f16c19b77e296c4bc207b, 2021)
- License: BSD-3-Clause
Module location:
- thirdparty/libdatachannel/deps/libsrtp
## openssl
- Upstream: git://git.openssl.org/openssl.git
- Version: 3.0.7 (19cc035b6c6f2283573d29c7ea7f7d675cf750ce, 2022)
- License: Apache 2.0
Module location:
- thirdparty/openssl
## plog
- Upstream: https://github.com/SergiusTheBest/plog
- Version: git (d8461e9d473e59fbcc1f79eee021550dcf81e618, 2021)
- License: MPL 2.0
Module location:
- thirdparty/libdatachannel/deps/plog
## usrsctp
- Upstream: https://github.com/sctplab/usrsctp
- Version: git (7c31bd35c79ba67084ce029511193a19ceb97447, 2021)
- License: BSD-3-Clause
Module location:
- thirdparty/libdatachannel/deps/usrsctp

1
thirdparty/libdatachannel vendored Submodule

1
thirdparty/openssl vendored Submodule

Submodule thirdparty/openssl added at 19cc035b6c

1
webrtc/.gitignore vendored
View File

@@ -1 +0,0 @@
include/

View File

@@ -1,2 +0,0 @@
*
!.gitignore