Compare commits

...

49 Commits

Author SHA1 Message Date
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
Fabio Alessandrelli
7b92ab2a7b Add missing iOS armv7 entry. 2021-07-02 18:11:35 +02:00
Fabio Alessandrelli
e120cc7ed6 Merge pull request #33 from Faless/bump/webrtc_4472
Bump webrtc to branch-heads/4472. Fixes signalling.
2021-07-02 15:50:08 +02:00
Fabio Alessandrelli
da20ebf397 Unified signalling thread. 2021-07-02 15:12:41 +02:00
Fabio Alessandrelli
3711ad23f6 Bump webrtc to branch-heads/4472. 2021-07-02 15:12:41 +02:00
Fabio Alessandrelli
001be78500 Merge pull request #32 from Faless/release/3.2_fix
Fix API breakage after godot cpp 3.2 bump.
2021-07-02 00:39:52 +02:00
Fabio Alessandrelli
416ea27305 Fix API breakage after godot cpp 3.2 bump. 2021-07-02 00:36:41 +02:00
Fabio Alessandrelli
65bb4cb9ae Merge pull request #31 from Faless/release/3.2
Update godot-cpp to tip of 3.2 branch.
2021-07-02 00:29:11 +02:00
Fabio Alessandrelli
3014c3099f Update godot-cpp to tip of 3.2 branch. 2021-07-02 00:26:10 +02:00
Fabio Alessandrelli
c1c7ae5081 Merge pull request #30 from Faless/scons/mac_ios
Add mac and ios platforms. Fix GDNLibrary.
2021-07-02 00:13:48 +02:00
Fabio Alessandrelli
9e287f7cee Add mac and ios platforms. Fix GDNLibrary. 2021-07-01 23:58:01 +02:00
Fabio Alessandrelli
a374cf4510 Merge pull request #24 from rondao/add_android_build_support
Add build support for Android
2021-07-01 07:34:03 +02:00
Fabio Alessandrelli
9ee98ff0e9 Merge pull request #28 from Faless/fix/python3
Fix gdns generation with python3.
2021-05-05 16:42:21 +02:00
Fabio Alessandrelli
f26a1d8e83 Fix gdns generation with python3.
Python2 has reached end-of-life.
2021-05-05 16:40:22 +02:00
Rafael Rondao
7a62fe467b Add build support for Android
To build for Android, use platform=android.
ANDROID_NDK_ROOT env variable needs to be defined.

By default, it builds for armv7 with Api 18.
To build for arm64v8 (or x86, x86_64), use android_arch=arm64v8.
64 bits requires at least Api level 21.

If needed, you can change it with android_api_level=XX.

Signed-off-by: Rafael Rondao <rafael.rondao@gmail.com>
2020-11-07 23:01:34 -03:00
Fabio Alessandrelli
74f2c78db5 Merge pull request #18 from MarkSort/support-server-platform
set library paths for Server platform
2020-08-02 12:07:13 +02:00
Mark Achée
db6d416eba set library paths for Server platform 2020-06-20 12:22:29 -05:00
Fabio Alessandrelli
5f9e74f2fb Merge pull request #11 from Faless/fix/close_crash
Fix crash when closing an invalid peerconnection.
2020-01-13 18:18:20 +01:00
Fabio Alessandrelli
bd8e139ccc Fix crash when closing an invalid peerconnection. 2020-01-03 19:50:48 +01:00
Fabio Alessandrelli
61e45cb083 Merge pull request #10 from Faless/refactor/better-scons
Better build script, readme
2020-01-03 19:43:01 +01:00
Fabio Alessandrelli
6983019cab Initial README 2020-01-03 19:41:21 +01:00
Fabio Alessandrelli
54cbe83c56 Simplify webrtc lib folder structure 2020-01-03 19:41:21 +01:00
Fabio Alessandrelli
20f8f89c2c Use submodule for godot-cpp 2020-01-03 19:41:21 +01:00
Fabio Alessandrelli
4b22741255 Build script also create gdnlib 2020-01-03 19:41:07 +01:00
Fabio Alessandrelli
5769d8b2de Merge observers 2020-01-03 19:35:20 +01:00
Fabio Alessandrelli
423454086e Merge pull request #3 from Faless/channels_pr
Update to new DataChannel API, singleton load.
2019-05-21 14:08:30 +02:00
Fabio Alessandrelli
599ed98f6c Small build system improvement 2019-05-16 12:08:39 +02:00
Fabio Alessandrelli
f5ebac4519 Working singleton load 2019-05-16 10:32:51 +02:00
Fabio Alessandrelli
3e64a42b14 Update to new DataChannel API.
New WebRTCLibDataChannel class act as PacketPeer.
Old WebRTCPeer (now WebRTCPeerConnection) now allows you to set
configuration (STUN/TURN) and creating multiple data channels.
Fixed many bugs and implemented most of the missing API.
2019-05-16 10:32:51 +02:00
37 changed files with 2483 additions and 664 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.

View File

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

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

@@ -0,0 +1,222 @@
name: 🔧 Build -> Package 📦
on: [push, pull_request]
jobs:
static-checks:
name: 📊 Static Checks (clang-format, black format, file format)
runs-on: ubuntu-20.04
steps:
- name: Checkout
uses: actions/checkout@v2
- 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:
matrix:
include:
# Android
- platform: android
arch: 'x86'
sconsflags: 'android_arch=x86'
os: 'ubuntu-20.04'
- platform: android
arch: 'x64'
sconsflags: 'android_arch=x86_64'
os: 'ubuntu-20.04'
- platform: android
arch: 'arm'
sconsflags: 'android_arch=armv7'
os: 'ubuntu-20.04'
- platform: android
arch: 'arm64'
sconsflags: 'android_arch=arm64v8'
os: 'ubuntu-20.04'
# iOS
- platform: ios
arch: 'x64'
sconsflags: 'ios_arch=x86_64 ios_simulator=true'
os: 'macos-latest'
- platform: ios
arch: 'arm'
sconsflags: 'ios_arch=armv7'
os: 'macos-latest'
- platform: ios
arch: 'arm64'
sconsflags: 'ios_arch=arm64'
os: 'macos-latest'
# Linux
- platform: linux
arch: 'x86'
sconsflags: 'bits=32'
os: 'ubuntu-20.04'
- platform: linux
arch: 'x64'
sconsflags: 'bits=64'
os: 'ubuntu-20.04'
# macOS
- platform: osx
arch: 'x64'
sconsflags: 'bits=64'
os: 'macos-latest'
- platform: osx
arch: 'arm64'
sconsflags: 'bits=64 macos_arch=arm64 macos_sdk_path=/Library/Developer/CommandLineTools/SDKs/MacOSX11.1.sdk/'
os: 'macos-10.15'
# Windows
- platform: windows
arch: 'x86'
sconsflags: 'bits=32'
os: 'windows-latest'
msvc_arch: amd64_x86
- platform: windows
arch: 'x64'
sconsflags: 'bits=64'
os: 'windows-latest'
msvc_arch: amd64
env:
SCONSFLAGS: ${{ matrix.sconsflags }} platform=${{ matrix.platform }} --jobs=2
NDK_VERSION: 22b
ANDROID_NDK_ROOT: ${{github.workspace}}/android-ndk-r22b
MSVC_VARS: 'C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat'
defaults:
run:
shell: bash
steps:
- uses: actions/checkout@v2
with:
submodules: recursive
- name: Cache NDK
id: cache-ndk
if: ${{ matrix.platform == 'android' }}
uses: actions/cache@v2
with:
path: ${{ env.ANDROID_NDK_ROOT }}
key: ndk-${{ env.NDK_VERSION }}
- name: Download NDK
if: ${{ matrix.platform == 'android' && steps.cache-ndk.outputs.cache-hit != 'true' }}
id: setup-ndk
run: |
cd ${{ github.workspace }}
curl -L https://dl.google.com/android/repository/android-ndk-r${{ env.NDK_VERSION }}-linux-x86_64.zip -o ndk.zip
unzip ndk.zip
ls
- name: Setup MSVC build environment for ${{ matrix.msvc_arch }}
if: ${{ matrix.platform == 'windows' }}
run: "'${{ env.MSVC_VARS }}' ${{ matrix.msvc_arch }}"
- name: Install Linux build dependencies
if: ${{ matrix.platform == 'linux' }}
run: |
sudo apt-get install build-essential gcc-multilib wget g++-multilib
- name: Set up Python 3.x
uses: actions/setup-python@v2
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
- name: Get WebRTC package for ${{ matrix.platform }} - ${{ matrix.arch }}
uses: ./.github/actions/webrtc-download
with:
platform: ${{ matrix.platform }}
archs: ${{ matrix.arch }}
- name: Fix godot-cpp revision and file names for OSX arm64 build.
if: ${{ matrix.platform == 'osx' && matrix.arch == 'arm64' }}
run: |
cd godot-cpp
git checkout e08ecdc28c5409cb5366027227e996c342dcee93
rm -rf src/gen/
rm -rf include/gen/
mkdir bin
ln -s libgodot-cpp.osx.debug.64.a bin/libgodot-cpp.osx.debug.arm64.a
ln -s libgodot-cpp.osx.release.64.a bin/libgodot-cpp.osx.release.arm64.a
- name: Compilation ${{ matrix.platform }} - ${{ matrix.arch }} - godot-cpp
run: |
scons -C godot-cpp target=debug generate_bindings=yes
scons -C godot-cpp target=release
- name: Compilation ${{ matrix.platform }} - ${{ matrix.arch }} - webrtc-native
run: |
scons target=debug
scons target=release
- uses: actions/upload-artifact@v2
with:
name: ${{ github.job }}-${{ matrix.platform }}-${{ matrix.arch }}
path: bin/*
package:
name: 📦 Package
needs: build
runs-on: "ubuntu-latest"
steps:
- uses: actions/checkout@v2
- uses: actions/download-artifact@v2
with:
path: artifacts
- name: Package artifacts for release
run: |
mkdir release
cd release
for name in webrtc webrtc_debug
do
mkdir -p ${name}/lib/
find ../artifacts -wholename "*/${name}/lib/*" | xargs cp -t ${name}/lib/
find ../artifacts -wholename "*/${name}/${name}.tres" | head -n 1 | xargs cp -t ${name}/
done
zip -r godot-webrtc-native-release.zip webrtc
zip -r godot-webrtc-native-debug.zip webrtc_debug
ls -R
- uses: actions/upload-artifact@v2
with:
name: godot-webrtc-native-debug.zip
path: release/godot-webrtc-native-debug.zip
- uses: actions/upload-artifact@v2
with:
name: godot-webrtc-native-release.zip
path: release/godot-webrtc-native-release.zip

1
.gitignore vendored
View File

@@ -4,3 +4,4 @@ bin/*
*.lib
.sconsign.dblite
*.obj
*.swp

3
.gitmodules vendored Normal file
View File

@@ -0,0 +1,3 @@
[submodule "godot-cpp"]
path = godot-cpp
url = https://github.com/GodotNativeTools/godot-cpp

View File

@@ -0,0 +1,71 @@
# GDNative WebRTC plugin for Godot
## Getting Started
| **Download latest binary version** | [**GitHub**](https://github.com/godotengine/webrtc-native/releases) |
| --- | --- |
### Compiling
Clone this repository with the following command to checkout both [godot-cpp](https://github.com/godotengine/godot-cpp) and [godot-headers](https://github.com/godotengine/godot-headers) dependencies.
```
$ git clone --recurse-submodules https://github.com/godotengine/webrtc-native.git
```
Note that if you wish to use a specific branch, add the -b option to the clone command:
```
$ git clone --recurse-submodules -b 3.2 https://github.com/godotengine/webrtc-native.git
```
If you already checked out the branch use the following commands to update the dependencies:
```
$ git submodule update --init --recursive
```
Right now our directory structure should look like this:
```
webrtc-native/
├─bin/
├─godot-cpp/
| └─godot-headers/
├─src/
└─webrtc/
```
### Compiling the cpp bindings library
First, we need to compile our cpp bindings library:
```
$ cd godot-cpp
$ scons platform=<your platform> generate_bindings=yes
$ cd ..
```
> Replace `<your platform>` with either `windows`, `linux` or `osx`.
> Include `use_llvm=yes` for using clang++
> Include `target=runtime` to build a runtime build (windows only at the moment)
> Include `target=release` or `target=debug` for release or debug build.
> The resulting library will be created in `godot-cpp/bin/`, take note of its name as it will be different depending on platform.
### Building WebRTC
Building WebRTC is quite a complex task, involves huge downloads and long build times, and produces multiple output libraries that needs to bundled together.
To make things easier, a set of [GitHub Actions](https://docs.github.com/en/actions) are used to generate the library for this plugin, [available in this repository](https://github.com/godotengine/webrtc-actions).
Alternatively, [**download the latest pre-compiled libraries**](https://github.com/godotengine/webrtc-actions/releases).
Extract content of `include` into `webrtc/include` and content of `bin` into `webrtc/<your platform>`
### Compiling the plugin.
```
$ scons platform=<your platform> target=<your target>
```
The generated library and associated `tres` will be placed in `bin/webrtc/` or `bin/webrtc_debug/` according to the desired target. You simply need to copy that folder to the root folder of your project.

View File

@@ -1,104 +1,278 @@
#!python
import os, sys, platform, json
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]
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"])
)
env = Environment()
customs = ['custom.py']
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(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",
)
opts.Add("macos_sdk_path", "macOS SDK path", "")
opts.Add(EnumVariable("macos_arch", "Target macOS architecture", "x86_64", ["x86_64", "arm64"]))
# Update environment (parse options)
opts.Update(env)
target = env['target']
target = env["target"]
if target_platform == "android":
target_arch = env["android_arch"]
elif target_platform == "ios":
target_arch = env["ios_arch"]
host_platform = platform.system()
target_platform = ARGUMENTS.get('p', ARGUMENTS.get('platform', 'linux'))
target_arch = ARGUMENTS.get('a', ARGUMENTS.get('arch', '64'))
# Local dependency paths, adapt them to your setup
godot_headers = ARGUMENTS.get('headers', '../godot_headers')
godot_cpp_headers = ARGUMENTS.get('godot_cpp_headers', '../godot-cpp/include')
godot_cpp_lib_dir = ARGUMENTS.get('godot_cpp_lib_dir', 'lib/godot-cpp')
result_path = 'bin'
result_name = 'webrtc_native'
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 = ""
# Convenience check to enforce the use_llvm overrides when CXX is clang(++)
if 'CXX' in env and 'clang' in os.path.basename(env['CXX']):
env['use_llvm'] = True
if "CXX" in env and "clang" in os.path.basename(env["CXX"]):
env["use_llvm"] = True
if target_platform == 'linux':
result_name += '.linux.' + target + '.' + target_arch
env['CXX']='g++'
if target_platform == "linux":
env["CXX"] = "g++"
# LLVM
if env['use_llvm']:
if ('clang++' not in os.path.basename(env['CXX'])):
env['CC'] = 'clang'
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.Prepend(CCFLAGS=['-g3'])
env.Append(LINKFLAGS=['-rdynamic'])
if env["target"] == "debug":
env.Prepend(CCFLAGS=["-g3"])
env.Append(LINKFLAGS=["-rdynamic"])
else:
env.Prepend(CCFLAGS=['-O3'])
env.Prepend(CCFLAGS=["-O3"])
env.Append(CCFLAGS=['-fPIC', '-std=c++11'])
env.Append(CCFLAGS=["-fPIC", "-std=c++14"])
if target_arch == '32':
env.Append(CCFLAGS = [ '-m32' ])
env.Append(LINKFLAGS = [ '-m32' ])
elif target_arch == '64':
env.Append(CCFLAGS = [ '-m64' ])
env.Append(LINKFLAGS = [ '-m64' ])
if 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':
# 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')
elif target_platform == "windows":
if host_platform == "Windows":
result_name += '.windows.' + target + '.' + target_arch
if host_platform == 'Windows':
#result_name += '.lib'
env.Append(LINKFLAGS = [ '/WX' ])
if target == 'debug':
env.Append(CCFLAGS = ['/EHsc', '/D_DEBUG', '/MDd' ])
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' ])
env.Append(CCFLAGS=["/O2", "/EHsc", "/DNDEBUG", "/MD"])
else:
if target_arch == '32':
env['CXX']='i686-w64-mingw32-g++'
elif target_arch == '64':
env['CXX']='x86_64-w64-mingw32-g++'
if 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++' ])
if env["target"] == "debug":
env.Append(CCFLAGS=["-Og", "-g"])
elif env["target"] == "release":
env.Append(CCFLAGS=["-O3"])
elif target_platform == 'osx':
if env['use_llvm']:
env['CXX'] = 'clang++'
env.Append(CCFLAGS=["-std=c++14", "-Wwrite-strings"])
env.Append(LINKFLAGS=["--static", "-Wl,--no-undefined", "-static-libgcc", "-static-libstdc++"])
elif target_platform == "osx":
if env["use_llvm"]:
env["CXX"] = "clang++"
# Only 64-bits is supported for OS X
target_arch = '64'
result_name += '.osx.' + target + '.' + target_arch
target_arch = "64"
if env["macos_arch"] != "x86_64":
target_arch = "arm64"
env.Append(CCFLAGS = [ '-g','-O3', '-std=c++14', '-arch', 'x86_64' ])
env.Append(LINKFLAGS = [ '-arch', 'x86_64', '-framework', 'Cocoa', '-Wl,-undefined,dynamic_lookup' ])
env.Append(CCFLAGS=["-std=c++14", "-arch", env["macos_arch"]])
env.Append(LINKFLAGS=["-arch", env["macos_arch"], "-framework", "Cocoa", "-Wl,-undefined,dynamic_lookup"])
if env["macos_sdk_path"]:
env.Append(CCFLAGS=["-isysroot", env["macos_sdk_path"]])
env.Append(LINKFLAGS=["-isysroot", env["macos_sdk_path"]])
if env["target"] == "debug":
env.Append(CCFLAGS=["-Og", "-g"])
elif env["target"] == "release":
env.Append(CCFLAGS=["-O3"])
elif target_platform == "ios":
if env["ios_simulator"]:
sdk_name = "iphonesimulator"
env.Append(CCFLAGS=["-mios-simulator-version-min=10.0"])
env["LIBSUFFIX"] = ".simulator" + env["LIBSUFFIX"]
else:
sdk_name = "iphoneos"
env.Append(CCFLAGS=["-miphoneos-version-min=10.0"])
try:
sdk_path = decode_utf8(subprocess.check_output(["xcrun", "--sdk", sdk_name, "--show-sdk-path"]).strip())
except (subprocess.CalledProcessError, OSError):
raise ValueError("Failed to find SDK path while running xcrun --sdk {} --show-sdk-path.".format(sdk_name))
compiler_path = env["IPHONEPATH"] + "/usr/bin/"
env["ENV"]["PATH"] = env["IPHONEPATH"] + "/Developer/usr/bin/:" + env["ENV"]["PATH"]
env["CC"] = compiler_path + "clang"
env["CXX"] = compiler_path + "clang++"
env["AR"] = compiler_path + "ar"
env["RANLIB"] = compiler_path + "ranlib"
env.Append(CCFLAGS=["-std=c++14", "-arch", env["ios_arch"], "-isysroot", sdk_path])
env.Append(
LINKFLAGS=["-arch", env["ios_arch"], "-Wl,-undefined,dynamic_lookup", "-isysroot", sdk_path, "-F" + sdk_path]
)
if env["target"] == "debug":
env.Append(CCFLAGS=["-Og", "-g"])
elif env["target"] == "release":
env.Append(CCFLAGS=["-O3"])
elif target_platform == "android":
# Verify NDK root
if not "ANDROID_NDK_ROOT" in env:
raise ValueError(
"To build for Android, ANDROID_NDK_ROOT must be defined. Please set ANDROID_NDK_ROOT to the root folder of your Android NDK installation."
)
# Validate API level
api_level = int(env["android_api_level"])
if target_arch in ["arm64v8", "x86_64"] and api_level < 21:
print("WARN: 64-bit Android architectures require an API level of at least 21; setting android_api_level=21")
env["android_api_level"] = "21"
api_level = 21
# Setup toolchain
toolchain = env["ANDROID_NDK_ROOT"] + "/toolchains/llvm/prebuilt/"
if host_platform == "Windows":
toolchain += "windows"
import platform as pltfm
if pltfm.machine().endswith("64"):
toolchain += "-x86_64"
elif host_platform == "Linux":
toolchain += "linux-x86_64"
elif host_platform == "Darwin":
toolchain += "darwin-x86_64"
# Get architecture info
arch_info_table = {
"armv7": {
"march": "armv7-a",
"target": "armv7a-linux-androideabi",
"tool_path": "arm-linux-androideabi",
"compiler_path": "armv7a-linux-androideabi",
"ccflags": ["-mfpu=neon"],
},
"arm64v8": {
"march": "armv8-a",
"target": "aarch64-linux-android",
"tool_path": "aarch64-linux-android",
"compiler_path": "aarch64-linux-android",
"ccflags": [],
},
"x86": {
"march": "i686",
"target": "i686-linux-android",
"tool_path": "i686-linux-android",
"compiler_path": "i686-linux-android",
"ccflags": ["-mstackrealign"],
},
"x86_64": {
"march": "x86-64",
"target": "x86_64-linux-android",
"tool_path": "x86_64-linux-android",
"compiler_path": "x86_64-linux-android",
"ccflags": [],
},
}
arch_info = arch_info_table[target_arch]
# Setup tools
env["CC"] = toolchain + "/bin/clang"
env["CXX"] = toolchain + "/bin/clang++"
env.Append(
CCFLAGS=["--target=" + arch_info["target"] + env["android_api_level"], "-march=" + arch_info["march"], "-fPIC"]
)
env.Append(CCFLAGS=arch_info["ccflags"])
env.Append(LINKFLAGS=["--target=" + arch_info["target"] + env["android_api_level"], "-march=" + arch_info["march"]])
if env["target"] == "debug":
env.Append(CCFLAGS=["-Og", "-g"])
elif env["target"] == "release":
env.Append(CCFLAGS=["-O3"])
else:
print("No valid target platform selected.")
@@ -106,31 +280,41 @@ else:
# Godot CPP bindings
env.Append(CPPPATH=[godot_headers])
env.Append(CPPPATH=[godot_cpp_headers, godot_cpp_headers + '/core', godot_cpp_headers + '/gen'])
env.Append(LIBPATH=[godot_cpp_lib_dir + '/' + target])
env.Append(LIBS=['godot-cpp'])
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 "")
]
)
# WebRTC stuff
webrtc_dir = "lib/webrtc"
lib_name = 'libwebrtc_full'
lib_path = webrtc_dir + '/lib/' + target_platform
webrtc_dir = "webrtc"
lib_name = "libwebrtc_full"
lib_path = os.path.join(webrtc_dir, target_platform)
if target_arch == '64':
lib_path += '/x64'
elif target_arch == '32':
lib_path += '/x86'
lib_path += {
"32": "/x86",
"64": "/x64",
"armv7": "/arm",
"arm64v8": "/arm64",
"arm64": "/arm64",
"x86": "/x86",
"x86_64": "/x64",
}[target_arch]
if target == 'debug':
lib_path += '/Debug'
if target == "debug":
lib_path += "/Debug"
else:
lib_path += '/Release'
lib_path += "/Release"
env.Append(CPPPATH=[webrtc_dir + "/include"])
env.Append(CPPPATH=[webrtc_dir + "/include", webrtc_dir + "/include/third_party/abseil-cpp"])
if target_platform == "linux":
env.Append(LIBS=[lib_name])
env.Append(LIBS=[lib_name, "atomic"])
env.Append(LIBPATH=[lib_path])
#env.Append(CCFLAGS=["-std=c++11"])
# env.Append(CCFLAGS=["-std=c++11"])
env.Append(CCFLAGS=["-DWEBRTC_POSIX", "-DWEBRTC_LINUX"])
env.Append(CCFLAGS=["-DRTC_UNUSED=''", "-DNO_RETURN=''"])
@@ -142,20 +326,62 @@ elif target_platform == "windows":
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(
CCFLAGS=[
"-DWINVER=0x0603",
"-D_WIN32_WINNT=0x0603",
"-DWEBRTC_WIN",
"-DWIN32_LEAN_AND_MEAN",
"-DNOMINMAX",
"-DRTC_UNUSED=",
"-DNO_RETURN=",
]
)
env.Append(LINKFLAGS=[p + env["LIBSUFFIX"] for p in ["secur32", "advapi32", "winmm", lib_name]])
env.Append(LIBPATH=[lib_path])
elif target_platform == "osx":
env.Append(LIBS=[lib_name])
env.Append(LIBPATH=[lib_path])
env.Append(CCFLAGS=["-DWEBRTC_POSIX", "-DWEBRTC_MAC"])
env.Append(CCFLAGS=["-DRTC_UNUSED=''", "-DNO_RETURN=''"])
elif target_platform == "ios":
env.Append(LIBS=[lib_name])
env.Append(LIBPATH=[lib_path])
env.Append(CCFLAGS=["-DWEBRTC_POSIX", "-DWEBRTC_MAC", "-DWEBRTC_IOS"])
env.Append(CCFLAGS=["-DRTC_UNUSED=''", "-DNO_RETURN=''"])
elif target_platform == "android":
env.Append(LIBS=["log"])
env.Append(LIBS=[lib_name])
env.Append(LIBPATH=[lib_path])
env.Append(CCFLAGS=["-DWEBRTC_POSIX", "-DWEBRTC_LINUX", "-DWEBRTC_ANDROID"])
env.Append(CCFLAGS=["-DRTC_UNUSED=''", "-DNO_RETURN=''"])
if target_arch == "arm64v8":
env.Append(CCFLAGS=["-DWEBRTC_ARCH_ARM64", "-DWEBRTC_HAS_NEON"])
elif target_arch == "armv7":
env.Append(CCFLAGS=["-DWEBRTC_ARCH_ARM", "-DWEBRTC_ARCH_ARM_V7", "-DWEBRTC_HAS_NEON"])
# Our includes and sources
env.Append(CPPPATH=['src/'])
env.Append(CPPPATH=["src/"])
sources = []
add_sources(sources, 'src/', 'cpp')
add_sources(sources, 'src/net/', 'cpp')
add_sources(sources, "src/", "cpp")
add_sources(sources, "src/net/", "cpp")
# Suffix
suffix = ".%s.%s" % (target, target_arch)
env["SHOBJSUFFIX"] = suffix + env["SHOBJSUFFIX"]
# Make the shared library
result_name = "webrtc_native.%s.%s.%s" % (target_platform, target, target_arch) + env["SHLIBSUFFIX"]
library = env.SharedLibrary(target=os.path.join(result_path, result_name), source=sources)
Default(library)
# GDNativeLibrary
gdnlib = "webrtc"
if target != "release":
gdnlib += "_debug"
Default(env.GDNativeLibBuilder([os.path.join("bin", gdnlib, gdnlib + ".tres")], ["misc/gdnlib.tres"]))

1
godot-cpp Submodule

Submodule godot-cpp added at 77d41fa179

View File

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

View File

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

View File

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

View File

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

28
misc/gdnlib.tres Normal file
View File

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

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()

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

@@ -0,0 +1,48 @@
#!/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
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

View File

@@ -1,16 +0,0 @@
#include "WebRTCLibPeer.hpp"
using namespace godot_webrtc;
WebRTCLibPeer::GodotCSDO::GodotCSDO(WebRTCLibPeer *parent) {
this->parent = parent;
}
void WebRTCLibPeer::GodotCSDO::OnSuccess(webrtc::SessionDescriptionInterface *desc) {
// serialize this offer and send it to the remote peer:
std::string sdp; // sdp = session description protocol
desc->ToString(&sdp);
parent->queue_signal("offer_created", 2, desc->type().c_str(), sdp.c_str());
};
void WebRTCLibPeer::GodotCSDO::OnFailure(const std::string &error){};

View File

@@ -1,19 +0,0 @@
#include "WebRTCLibPeer.hpp"
using namespace godot_webrtc;
WebRTCLibPeer::GodotDCO::GodotDCO(WebRTCLibPeer *parent) {
this->parent = parent;
}
void WebRTCLibPeer::GodotDCO::OnMessage(const webrtc::DataBuffer &buffer) {
const uint8_t *data = buffer.data.data<uint8_t>();
uint8_t *memory_controlled_buffer = new uint8_t[buffer.data.size()];
std::copy(data, data + buffer.data.size(), memory_controlled_buffer);
parent->queue_packet(memory_controlled_buffer, buffer.data.size());
};
void WebRTCLibPeer::GodotDCO::OnStateChange(){};
void WebRTCLibPeer::GodotDCO::OnBufferedAmountChange(uint64_t previous_amount){};

View File

@@ -1,46 +0,0 @@
#include "WebRTCLibPeer.hpp"
using namespace godot_webrtc;
WebRTCLibPeer::GodotPCO::GodotPCO(WebRTCLibPeer *parent) {
this->parent = parent;
}
void WebRTCLibPeer::GodotPCO::OnSignalingChange(webrtc::PeerConnectionInterface::SignalingState new_state) {
}
void WebRTCLibPeer::GodotPCO::OnAddStream(rtc::scoped_refptr<webrtc::MediaStreamInterface> stream) {
}
void WebRTCLibPeer::GodotPCO::OnRemoveStream(rtc::scoped_refptr<webrtc::MediaStreamInterface> stream) {
}
void WebRTCLibPeer::GodotPCO::OnDataChannel(rtc::scoped_refptr<webrtc::DataChannelInterface> data_channel) {
}
void WebRTCLibPeer::GodotPCO::OnRenegotiationNeeded() {
}
void WebRTCLibPeer::GodotPCO::OnIceConnectionChange(webrtc::PeerConnectionInterface::IceConnectionState new_state) {
}
void WebRTCLibPeer::GodotPCO::OnIceGatheringChange(webrtc::PeerConnectionInterface::IceGatheringState new_state) {
}
void WebRTCLibPeer::GodotPCO::OnIceCandidate(const webrtc::IceCandidateInterface *candidate) {
// Serialize the candidate and send it to the remote peer:
godot::Dictionary candidateSDP;
godot::String candidateSdpMidName = candidate->sdp_mid().c_str();
int candidateSdpMlineIndexName = candidate->sdp_mline_index();
std::string sdp;
candidate->ToString(&sdp);
godot::String candidateSdpName = sdp.c_str();
parent->queue_signal("new_ice_candidate",
3,
candidateSdpMidName,
candidateSdpMlineIndexName,
candidateSdpName);
}

View File

@@ -1,11 +0,0 @@
#include "WebRTCLibPeer.hpp"
using namespace godot_webrtc;
WebRTCLibPeer::GodotSSDO::GodotSSDO(WebRTCLibPeer *parent) {
this->parent = parent;
}
void WebRTCLibPeer::GodotSSDO::OnSuccess(){};
void WebRTCLibPeer::GodotSSDO::OnFailure(const std::string &error){};

View File

@@ -0,0 +1,215 @@
/*************************************************************************/
/* 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"
#include "GDNativeLibrary.hpp"
#include "NativeScript.hpp"
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) {
// Invalid channel result in NULL return
ERR_FAIL_COND_V(p_channel.get() == nullptr, NULL);
// 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));
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;
}
void WebRTCLibDataChannel::bind_channel(rtc::scoped_refptr<webrtc::DataChannelInterface> p_channel) {
ERR_FAIL_COND(p_channel.get() == nullptr);
channel = p_channel;
label = p_channel->label();
protocol = p_channel->protocol();
channel->RegisterObserver(&observer);
}
void WebRTCLibDataChannel::queue_packet(const uint8_t *data, uint32_t size) {
mutex->lock();
godot::PoolByteArray packet;
packet.resize(size);
{
godot::PoolByteArray::Write w = packet.write();
memcpy(w.ptr(), data, size);
}
packet_queue.push(packet);
mutex->unlock();
}
void WebRTCLibDataChannel::set_write_mode(godot_int mode) {
}
godot_int WebRTCLibDataChannel::get_write_mode() const {
return 0;
}
bool WebRTCLibDataChannel::was_string_packet() const {
return false;
}
WebRTCLibDataChannel::ChannelState WebRTCLibDataChannel::get_ready_state() const {
ERR_FAIL_COND_V(channel.get() == nullptr, STATE_CLOSED);
return (ChannelState)channel->state();
}
const char *WebRTCLibDataChannel::get_label() const {
ERR_FAIL_COND_V(channel.get() == nullptr, "");
return label.c_str();
}
bool WebRTCLibDataChannel::is_ordered() const {
ERR_FAIL_COND_V(channel.get() == nullptr, false);
return channel->ordered();
}
int WebRTCLibDataChannel::get_id() const {
ERR_FAIL_COND_V(channel.get() == nullptr, -1);
return channel->id();
}
int WebRTCLibDataChannel::get_max_packet_life_time() const {
ERR_FAIL_COND_V(channel.get() == nullptr, 0);
return channel->maxRetransmitTime();
}
int WebRTCLibDataChannel::get_max_retransmits() const {
ERR_FAIL_COND_V(channel.get() == nullptr, 0);
return channel->maxRetransmits();
}
const char *WebRTCLibDataChannel::get_protocol() const {
ERR_FAIL_COND_V(channel.get() == nullptr, "");
return protocol.c_str();
}
bool WebRTCLibDataChannel::is_negotiated() const {
ERR_FAIL_COND_V(channel.get() == nullptr, false);
return channel->negotiated();
}
int WebRTCLibDataChannel::get_buffered_amount() const {
ERR_FAIL_COND_V(channel.get() == nullptr, 0);
return channel->buffered_amount();
}
godot_error WebRTCLibDataChannel::poll() {
return GODOT_OK;
}
void WebRTCLibDataChannel::close() {
if (channel.get() != nullptr) {
channel->Close();
channel->UnregisterObserver();
}
}
godot_error WebRTCLibDataChannel::get_packet(const uint8_t **r_buffer, int *r_len) {
ERR_FAIL_COND_V(packet_queue.empty(), GODOT_ERR_UNAVAILABLE);
mutex->lock();
// Update current packet and pop queue
current_packet = packet_queue.front();
packet_queue.pop();
// Set out buffer and size (buffer will be gone at next get_packet or close)
*r_buffer = current_packet.read().ptr();
*r_len = current_packet.size();
mutex->unlock();
return GODOT_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;
}
godot_int WebRTCLibDataChannel::get_available_packet_count() const {
return packet_queue.size();
}
godot_int WebRTCLibDataChannel::get_max_packet_size() const {
return 1200;
}
void WebRTCLibDataChannel::_register_methods() {
}
void WebRTCLibDataChannel::_init() {
register_interface(&interface);
}
WebRTCLibDataChannel::WebRTCLibDataChannel() :
observer(this) {
mutex = new std::mutex;
}
WebRTCLibDataChannel::~WebRTCLibDataChannel() {
close();
if (_owner) {
register_interface(NULL);
}
delete mutex;
}

View File

@@ -0,0 +1,107 @@
/*************************************************************************/
/* 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
#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 "PoolArrays.hpp"
#include "net/WebRTCDataChannelNative.hpp"
#include <mutex>
namespace godot_webrtc {
class WebRTCLibDataChannel : public WebRTCDataChannelNative {
GODOT_CLASS(WebRTCLibDataChannel, WebRTCDataChannelNative);
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;
std::mutex *mutex;
std::queue<godot::PoolByteArray> packet_queue;
godot::PoolByteArray current_packet;
std::string label;
std::string protocol;
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;
int get_buffered_amount() const;
godot_error poll();
void close();
/* 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;
WebRTCLibDataChannel();
~WebRTCLibDataChannel();
};
} // namespace godot_webrtc
#endif // WEBRTC_DATA_CHANNEL_H

View File

@@ -1,202 +0,0 @@
#include "WebRTCLibPeer.hpp"
using namespace godot_webrtc;
void WebRTCLibPeer::set_write_mode(godot_int mode) {
}
godot_int WebRTCLibPeer::get_write_mode() const {
return 0;
}
bool WebRTCLibPeer::was_string_packet() const {
return false;
}
godot_int WebRTCLibPeer::get_connection_state() const {
return 0;
}
godot_error WebRTCLibPeer::create_offer() {
peer_connection->CreateOffer(
ptr_csdo, // CreateSessionDescriptionObserver* observer,
nullptr // webrtc::PeerConnectionInterface::RTCOfferAnswerOptions() // const MediaConstraintsInterface* constraints
);
return GODOT_OK;
}
godot_error WebRTCLibPeer::set_remote_description(const char *type, const char *sdp) {
godot_error err = set_description(type, sdp, false); //false meaning !isLocal because it is remote
peer_connection->CreateAnswer(ptr_csdo, webrtc::PeerConnectionInterface::RTCOfferAnswerOptions());
return err;
}
godot_error WebRTCLibPeer::set_local_description(const char *type, const char *sdp) {
return set_description(type, sdp, true); // isLocal == true
}
godot_error WebRTCLibPeer::add_ice_candidate(const char *sdpMidName, int sdpMlineIndexName, const char *sdpName) {
webrtc::SdpParseError *error = nullptr;
webrtc::IceCandidateInterface *candidate = webrtc::CreateIceCandidate(
sdpMidName,
sdpMlineIndexName,
sdpName,
error);
// @TODO do something if there's an error (if error, or if !candidate)
if (error || !candidate)
std::cout << "ERROR with creating ICE candidate (" << error << ")\n";
if (!peer_connection->AddIceCandidate(candidate))
ERR_PRINT("Error with adding ICE candidate");
return GODOT_OK;
}
godot_error WebRTCLibPeer::poll() {
std::function<void()> signal;
while (!signal_queue.empty()) {
mutex_signal_queue->lock();
signal = signal_queue.front();
signal_queue.pop();
mutex_signal_queue->unlock();
signal();
}
return GODOT_OK;
}
godot_error WebRTCLibPeer::get_packet(const uint8_t **r_buffer, int *r_len) {
if (packet_queue_size == 0)
return GODOT_ERR_UNAVAILABLE;
mutex_packet_queue->lock();
uint8_t *current_packet = packet_queue.front();
*r_buffer = current_packet;
*r_len = packet_sizes_queue.front();
packet_queue.pop();
packet_sizes_queue.pop();
mutex_packet_queue->unlock();
--packet_queue_size;
return GODOT_OK;
}
godot_error WebRTCLibPeer::put_packet(const uint8_t *p_buffer, int p_len) {
webrtc::DataBuffer webrtc_buffer(rtc::CopyOnWriteBuffer(p_buffer, p_len), true);
data_channel->Send(webrtc_buffer);
return GODOT_OK; // @TODO properly return any Error we may get.
}
godot_int WebRTCLibPeer::get_available_packet_count() const {
return packet_queue_size;
}
godot_int WebRTCLibPeer::get_max_packet_size() const {
return 1200;
}
void WebRTCLibPeer::_register_methods() {
}
void WebRTCLibPeer::_init() {
register_interface(&interface);
// initialize variables:
mutex_signal_queue = new std::mutex;
mutex_packet_queue = new std::mutex;
packet_queue_size = 0;
// create a PeerConnectionFactoryInterface:
signaling_thread = new rtc::Thread;
signaling_thread->Start();
pc_factory = webrtc::CreateModularPeerConnectionFactory(
nullptr, // rtc::Thread* network_thread,
nullptr, // rtc::Thread* worker_thread,
signaling_thread,
nullptr, // std::unique_ptr<cricket::MediaEngineInterface> media_engine,
nullptr, // std::unique_ptr<CallFactoryInterface> call_factory,
nullptr // std::unique_ptr<RtcEventLogFactoryInterface> event_log_factory
);
if (pc_factory.get() == nullptr) { // PeerConnectionFactory couldn't be created. Fail the method call.
ERR_PRINT("PeerConnectionFactory could not be created");
// return GODOT_FAILED;
}
// create PeerConnection configuration and add the ice servers:
webrtc::PeerConnectionInterface::RTCConfiguration configuration;
//webrtc::PeerConnectionInterface::IceServer ice_server;
//ice_server.uri = "stun:stun.l.google.com:19302"; // @FIXME allow user to input ice servers
//configuration.servers.push_back(ice_server);
// create a PeerConnection object:
peer_connection = pc_factory->CreatePeerConnection(configuration, nullptr, nullptr, &pco);
if (peer_connection.get() == nullptr) { // PeerConnection couldn't be created. Fail the method call.
ERR_PRINT("PeerConnection could not be created");
// return GODOT_FAILED;
}
// create a DataChannel
webrtc::DataChannelInit data_channel_config;
data_channel_config.negotiated = true; // True if the channel has been externally negotiated
data_channel_config.id = 0;
data_channel = peer_connection->CreateDataChannel("channel", &data_channel_config);
// @TODO (NONESSENTIAL) create data_channel check. fail function call if data_channel isn't created
data_channel->RegisterObserver(&dco);
}
WebRTCLibPeer::WebRTCLibPeer() :
dco(this),
pco(this),
ptr_csdo(new rtc::RefCountedObject<GodotCSDO>(this)),
ptr_ssdo(new rtc::RefCountedObject<GodotSSDO>(this)) {
}
WebRTCLibPeer::~WebRTCLibPeer() {
if (_owner) {
register_interface(NULL);
}
delete mutex_signal_queue;
delete mutex_packet_queue;
}
void WebRTCLibPeer::queue_signal(godot::String p_name, int p_argc, const godot::Variant &p_arg1, const godot::Variant &p_arg2, const godot::Variant &p_arg3) {
mutex_signal_queue->lock();
signal_queue.push(
[this, p_name, p_argc, p_arg1, p_arg2, p_arg3] {
if (p_argc == 2)
emit_signal(p_name, p_arg1, p_arg2);
else
emit_signal(p_name, p_arg1, p_arg2, p_arg3);
});
mutex_signal_queue->unlock();
}
void WebRTCLibPeer::queue_packet(uint8_t *buffer, int buffer_size) {
mutex_packet_queue->lock();
packet_queue.push(buffer);
packet_sizes_queue.push(buffer_size);
++packet_queue_size;
mutex_packet_queue->unlock();
}
godot_error WebRTCLibPeer::set_description(const char *type, const char *sdp, bool isLocal) {
// webrtc::SdpType type = (isOffer) ? webrtc::SdpType::kOffer : webrtc::SdpType::kAnswer;
godot::String string_sdp = sdp;
webrtc::SdpType sdptype = (godot::String(type) == godot::String("offer")) ? webrtc::SdpType::kOffer : webrtc::SdpType::kAnswer;
std::unique_ptr<webrtc::SessionDescriptionInterface> desc =
webrtc::CreateSessionDescription(sdptype, sdp);
if (isLocal) {
peer_connection->SetLocalDescription(
ptr_ssdo, // @TODO (NONESSENTIAL, OPTIONAL) replace this with DummySetSessionDescriptionObserver::Create()
desc.release());
} else {
peer_connection->SetRemoteDescription(
ptr_ssdo, // @TODO (NONESSENTIAL, OPTIONAL) replace this with DummySetSessionDescriptionObserver::Create()
desc.release());
}
return GODOT_OK;
}

View File

@@ -1,117 +0,0 @@
#ifndef WEBRTC_PEER_H
#define WEBRTC_PEER_H
#include <Godot.hpp> // Godot.hpp must go first, or windows builds breaks
#include "api/peerconnectioninterface.h" // interface for all things needed from WebRTC
#include "media/base/mediaengine.h" // needed for CreateModularPeerConnectionFactory
#include <functional> // std::function
#include <mutex> // mutex @TODO replace std::mutex with Godot mutex
#include "net/WebRTCPeerNative.hpp"
namespace godot_webrtc {
class WebRTCLibPeer : public WebRTCPeerNative {
GODOT_CLASS(WebRTCLibPeer, WebRTCPeerNative);
public:
static void _register_methods();
void _init();
void set_write_mode(godot_int mode);
godot_int get_write_mode() const;
bool was_string_packet() const;
godot_int get_connection_state() const;
godot_error create_offer();
godot_error set_remote_description(const char *type, const char *sdp);
godot_error set_local_description(const char *type, const char *sdp);
godot_error add_ice_candidate(const char *sdpMidName, int sdpMlineIndexName, const char *sdpName);
godot_error poll();
/* WebRTCPeer */
virtual godot_error get_packet(const uint8_t **r_buffer, int *r_len);
virtual godot_error put_packet(const uint8_t *p_buffer, int p_len);
virtual godot_int get_available_packet_count() const;
virtual godot_int get_max_packet_size() const;
WebRTCLibPeer();
~WebRTCLibPeer();
/* helper functions */
void queue_signal(godot::String p_name, int p_argc, const godot::Variant &p_arg1 = godot::Variant(), const godot::Variant &p_arg2 = godot::Variant(), const godot::Variant &p_arg3 = godot::Variant());
// void queue_signal(godot::StringName p_name, Variant_ARG_LIST);
void queue_packet(uint8_t *, int);
godot_error set_description(const char *type, const char *sdp, bool isLocal);
/** DataChannelObserver callback functions **/
class GodotDCO : public webrtc::DataChannelObserver {
public:
WebRTCLibPeer *parent;
GodotDCO(WebRTCLibPeer *parent);
void OnMessage(const webrtc::DataBuffer &buffer) override;
void OnStateChange() override; // UNUSED
void OnBufferedAmountChange(uint64_t previous_amount) override; // UNUSED
};
/** PeerConnectionObserver callback functions **/
class GodotPCO : public webrtc::PeerConnectionObserver {
public:
WebRTCLibPeer *parent;
GodotPCO(WebRTCLibPeer *parent);
void OnSignalingChange(webrtc::PeerConnectionInterface::SignalingState new_state) override;
void OnAddStream(rtc::scoped_refptr<webrtc::MediaStreamInterface> stream) override;
void OnRemoveStream(rtc::scoped_refptr<webrtc::MediaStreamInterface> stream) override;
void OnDataChannel(rtc::scoped_refptr<webrtc::DataChannelInterface> data_channel) override;
void OnRenegotiationNeeded() override;
void OnIceConnectionChange(webrtc::PeerConnectionInterface::IceConnectionState new_state) override;
void OnIceGatheringChange(webrtc::PeerConnectionInterface::IceGatheringState new_state) override;
void OnIceCandidate(const webrtc::IceCandidateInterface *candidate) override;
};
/** CreateSessionDescriptionObserver callback functions **/
class GodotCSDO : public webrtc::CreateSessionDescriptionObserver {
public:
WebRTCLibPeer *parent;
GodotCSDO(WebRTCLibPeer *parent);
void OnSuccess(webrtc::SessionDescriptionInterface *desc) override;
void OnFailure(const std::string &error) override;
};
/** SetSessionDescriptionObserver callback functions **/
class GodotSSDO : public webrtc::SetSessionDescriptionObserver {
public:
WebRTCLibPeer *parent;
GodotSSDO(WebRTCLibPeer *parent);
void OnSuccess() override;
void OnFailure(const std::string &error) override;
};
GodotDCO dco;
GodotPCO pco;
rtc::scoped_refptr<GodotSSDO> ptr_ssdo;
rtc::scoped_refptr<GodotCSDO> ptr_csdo;
std::mutex *mutex_signal_queue;
std::mutex *mutex_packet_queue;
int packet_queue_size;
std::queue<uint8_t *> packet_queue;
std::queue<int> packet_sizes_queue;
std::queue<std::function<void()> > signal_queue;
rtc::Thread *signaling_thread;
rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> pc_factory;
rtc::scoped_refptr<webrtc::PeerConnectionInterface> peer_connection;
rtc::scoped_refptr<webrtc::DataChannelInterface> data_channel;
};
} // namespace godot_webrtc
#endif // WEBRTC_PEER_H

View File

@@ -0,0 +1,312 @@
/*************************************************************************/
/* 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 "WebRTCDataChannel.hpp"
#include "WebRTCDataChannelGDNative.hpp"
#include "WebRTCLibDataChannel.hpp"
using namespace godot_webrtc;
std::unique_ptr<rtc::Thread> WebRTCLibPeerConnection::signaling_thread = nullptr;
// PeerConnectionObserver
void WebRTCLibPeerConnection::GodotPCO::OnIceCandidate(const webrtc::IceCandidateInterface *candidate) {
godot::Dictionary candidateSDP;
godot::String candidateSdpMidName = candidate->sdp_mid().c_str();
int candidateSdpMlineIndexName = candidate->sdp_mline_index();
std::string sdp;
candidate->ToString(&sdp);
godot::String candidateSdpName = sdp.c_str();
parent->queue_signal("ice_candidate_created", 3, candidateSdpMidName, candidateSdpMlineIndexName, candidateSdpName);
}
// SetSessionDescriptionObserver
void WebRTCLibPeerConnection::GodotSSDO::OnSuccess() {
if (make_offer) {
make_offer = false;
parent->peer_connection->CreateAnswer(parent->ptr_csdo, webrtc::PeerConnectionInterface::RTCOfferAnswerOptions());
}
}
// CreateSessionDescriptionObserver
void WebRTCLibPeerConnection::GodotCSDO::OnSuccess(webrtc::SessionDescriptionInterface *desc) {
// serialize this offer and send it to the remote peer:
std::string sdp;
desc->ToString(&sdp);
parent->queue_signal("session_description_created", 2, desc->type().c_str(), sdp.c_str());
}
void WebRTCLibPeerConnection::initialize_signaling() {
if (signaling_thread.get() == nullptr) {
signaling_thread = rtc::Thread::Create();
}
signaling_thread->Start();
}
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);
// 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());
}
} else {
ERR_FAIL_V(GODOT_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();
}
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();
}
r_config.servers.push_back(ice_server);
return GODOT_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();
}
// 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;
}
WebRTCLibPeerConnection::ConnectionState WebRTCLibPeerConnection::get_connection_state() const {
ERR_FAIL_COND_V(peer_connection.get() == nullptr, STATE_CLOSED);
webrtc::PeerConnectionInterface::IceConnectionState state = peer_connection->ice_connection_state();
switch (state) {
case webrtc::PeerConnectionInterface::kIceConnectionNew:
return STATE_NEW;
case webrtc::PeerConnectionInterface::kIceConnectionChecking:
return STATE_CONNECTING;
case webrtc::PeerConnectionInterface::kIceConnectionConnected:
return STATE_CONNECTED;
case webrtc::PeerConnectionInterface::kIceConnectionCompleted:
return STATE_CONNECTED;
case webrtc::PeerConnectionInterface::kIceConnectionFailed:
return STATE_FAILED;
case webrtc::PeerConnectionInterface::kIceConnectionDisconnected:
return STATE_DISCONNECTED;
case webrtc::PeerConnectionInterface::kIceConnectionClosed:
return STATE_CLOSED;
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;
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);
}
}
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);
// 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);
WebRTCLibDataChannel *wrapper = WebRTCLibDataChannel::new_data_channel(peer_connection->CreateDataChannel(p_channel, &config));
ERR_FAIL_COND_V(wrapper == NULL, NULL);
return wrapper->_owner;
}
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;
}
#define _MAKE_DESC(TYPE, SDP) webrtc::CreateSessionDescription((godot::String(TYPE) == godot::String("offer") ? webrtc::SdpType::kOffer : webrtc::SdpType::kAnswer), SDP)
godot_error WebRTCLibPeerConnection::set_remote_description(const char *type, const char *sdp) {
ERR_FAIL_COND_V(peer_connection.get() == nullptr, GODOT_ERR_UNCONFIGURED);
std::unique_ptr<webrtc::SessionDescriptionInterface> desc = _MAKE_DESC(type, sdp);
if (desc->GetType() == webrtc::SdpType::kOffer) {
ptr_ssdo->make_offer = true;
}
peer_connection->SetRemoteDescription(ptr_ssdo, desc.release());
return GODOT_OK;
}
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;
}
godot_error WebRTCLibPeerConnection::poll() {
ERR_FAIL_COND_V(peer_connection.get() == nullptr, GODOT_ERR_UNCONFIGURED);
while (!signal_queue.empty()) {
mutex_signal_queue->lock();
Signal signal = signal_queue.front();
signal_queue.pop();
mutex_signal_queue->unlock();
signal.emit(this);
}
return GODOT_OK;
}
void WebRTCLibPeerConnection::close() {
if (peer_connection.get() != nullptr) {
peer_connection->Close();
}
peer_connection = nullptr;
while (!signal_queue.empty()) {
signal_queue.pop();
}
}
void WebRTCLibPeerConnection::_register_methods() {
}
void WebRTCLibPeerConnection::_init() {
register_interface(&interface);
// initialize variables:
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);
}
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;
}
WebRTCLibPeerConnection::WebRTCLibPeerConnection() :
pco(this),
ptr_csdo(new rtc::RefCountedObject<GodotCSDO>(this)),
ptr_ssdo(new rtc::RefCountedObject<GodotSSDO>(this)) {
}
WebRTCLibPeerConnection::~WebRTCLibPeerConnection() {
if (_owner) {
register_interface(NULL);
}
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) {
mutex_signal_queue->lock();
const godot::Variant argv[3] = { p_arg1, p_arg2, p_arg3 };
signal_queue.push(Signal(p_name, p_argc, argv));
mutex_signal_queue->unlock();
}

View File

@@ -0,0 +1,167 @@
/*************************************************************************/
/* 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
#include <Godot.hpp> // Godot.hpp must go first, or windows builds breaks
#include "api/peer_connection_interface.h" // interface for all things needed from WebRTC
#include "media/base/media_engine.h" // needed for CreateModularPeerConnectionFactory
#include <mutex>
#include "net/WebRTCPeerConnectionNative.hpp"
namespace godot_webrtc {
class WebRTCLibPeerConnection : public WebRTCPeerConnectionNative {
GODOT_CLASS(WebRTCLibPeerConnection, WebRTCPeerConnectionNative);
private:
godot_error _create_pc(webrtc::PeerConnectionInterface::RTCConfiguration &config);
static std::unique_ptr<rtc::Thread> signaling_thread;
public:
static void _register_methods();
static void initialize_signaling();
static void deinitialize_signaling();
void _init();
ConnectionState get_connection_state() const;
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();
WebRTCLibPeerConnection();
~WebRTCLibPeerConnection();
/* helper functions */
private:
void queue_signal(godot::String p_name, int p_argc, const godot::Variant &p_arg1 = godot::Variant(), const godot::Variant &p_arg2 = godot::Variant(), const godot::Variant &p_arg3 = godot::Variant());
void queue_packet(uint8_t *, int);
/** PeerConnectionObserver callback functions **/
class GodotPCO : public webrtc::PeerConnectionObserver {
public:
WebRTCLibPeerConnection *parent;
GodotPCO(WebRTCLibPeerConnection *p_parent) {
parent = p_parent;
}
void OnIceCandidate(const webrtc::IceCandidateInterface *candidate) override;
void OnSignalingChange(webrtc::PeerConnectionInterface::SignalingState new_state) override {}
void OnAddStream(rtc::scoped_refptr<webrtc::MediaStreamInterface> stream) override {}
void OnRemoveStream(rtc::scoped_refptr<webrtc::MediaStreamInterface> stream) override {}
void OnDataChannel(rtc::scoped_refptr<webrtc::DataChannelInterface> data_channel) override {}
void OnRenegotiationNeeded() override {}
void OnIceConnectionChange(webrtc::PeerConnectionInterface::IceConnectionState new_state) override {}
void OnIceGatheringChange(webrtc::PeerConnectionInterface::IceGatheringState new_state) override {}
};
/** CreateSessionDescriptionObserver callback functions **/
class GodotCSDO : public webrtc::CreateSessionDescriptionObserver {
public:
WebRTCLibPeerConnection *parent = nullptr;
GodotCSDO(WebRTCLibPeerConnection *p_parent) {
parent = p_parent;
}
void OnSuccess(webrtc::SessionDescriptionInterface *desc) override;
void OnFailure(webrtc::RTCError error) override {
ERR_PRINT(godot::String(error.message()));
}
};
/** SetSessionDescriptionObserver callback functions **/
class GodotSSDO : public webrtc::SetSessionDescriptionObserver {
public:
WebRTCLibPeerConnection *parent = nullptr;
bool make_offer = false;
GodotSSDO(WebRTCLibPeerConnection *p_parent) {
parent = p_parent;
}
void OnSuccess() override;
void OnFailure(webrtc::RTCError error) override {
make_offer = false;
ERR_PRINT(godot::String(error.message()));
}
};
class Signal {
godot::String method;
godot::Variant argv[3];
int argc = 0;
public:
Signal(godot::String p_method, int p_argc, const godot::Variant *p_argv) {
method = p_method;
argc = p_argc;
for (int i = 0; i < argc; i++) {
argv[i] = p_argv[i];
}
}
void emit(godot::Object *p_object) {
if (argc == 0) {
p_object->emit_signal(method);
} else if (argc == 1) {
p_object->emit_signal(method, argv[0]);
} else if (argc == 2) {
p_object->emit_signal(method, argv[0], argv[1]);
} else if (argc == 3) {
p_object->emit_signal(method, argv[0], argv[1], argv[2]);
}
}
};
GodotPCO pco;
rtc::scoped_refptr<GodotSSDO> ptr_ssdo;
rtc::scoped_refptr<GodotCSDO> ptr_csdo;
std::mutex *mutex_signal_queue = nullptr;
std::queue<Signal> signal_queue;
rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> pc_factory;
rtc::scoped_refptr<webrtc::PeerConnectionInterface> peer_connection;
};
} // namespace godot_webrtc
#endif // WEBRTC_PEER_H

View File

@@ -1,12 +1,107 @@
#include "WebRTCLibPeer.hpp"
#include "net/WebRTCPeerNative.hpp"
/*************************************************************************/
/* init.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>
/* Singleton */
static bool _singleton = false;
static const godot_object *_singleton_lib = NULL;
static const godot_gdnative_core_api_struct *_singleton_api = NULL;
static godot_class_constructor _create_ns_cb = NULL;
static godot_method_bind *_set_script_mb = NULL;
static godot_method_bind *_set_class_name_mb = NULL;
static godot_method_bind *_set_library_mb = NULL;
void unregistered() {
_singleton = false; // We are no longer the active singleton
}
godot_error create_peer_connection_wp(godot_object *out) {
ERR_FAIL_COND_V(!_singleton, GODOT_FAILED);
// Create Script
godot_object *script = _create_ns_cb();
ERR_FAIL_COND_V(!script, GODOT_FAILED);
const void *args[] = { (void *)_singleton_lib };
_singleton_api->godot_method_bind_ptrcall(_set_library_mb, script, args, nullptr);
godot_string s;
_singleton_api->godot_string_new(&s);
_singleton_api->godot_string_parse_utf8(&s, "WebRTCLibPeerConnection");
const void *args2[] = { (void *)&s };
_singleton_api->godot_method_bind_ptrcall(_set_class_name_mb, script, args2, nullptr);
_singleton_api->godot_string_destroy(&s);
// Bind script to Object
const void *args3[] = { (void *)script };
_singleton_api->godot_method_bind_ptrcall(_set_script_mb, out, args3, nullptr);
return GODOT_OK;
}
godot_net_webrtc_library library = {
{ 3, 2 },
&unregistered,
&create_peer_connection_wp,
NULL,
};
extern "C" void GDN_EXPORT godot_gdnative_singleton() {
if (WebRTCPeerConnectionNative::_net_api) {
ERR_FAIL_COND(!godot::gdnlib);
_singleton_lib = godot::gdnlib;
ERR_FAIL_COND(!godot::api);
_singleton_api = godot::api;
_create_ns_cb = godot::api->godot_get_class_constructor("NativeScript");
ERR_FAIL_COND(!_create_ns_cb);
_set_script_mb = godot::api->godot_method_bind_get_method("Object", "set_script");
ERR_FAIL_COND(!_set_script_mb);
_set_class_name_mb = godot::api->godot_method_bind_get_method("NativeScript", "set_class_name");
ERR_FAIL_COND(!_set_class_name_mb);
_set_library_mb = godot::api->godot_method_bind_get_method("NativeScript", "set_library");
ERR_FAIL_COND(!_set_library_mb);
// If registration is successful _singleton will be set to true
_singleton = WebRTCPeerConnectionNative::_net_api->godot_net_set_webrtc_library(&library) == GODOT_OK;
if (!_singleton)
ERR_PRINT("Failed initializing webrtc singleton library");
}
}
/* Godot export stuff */
extern "C" void GDN_EXPORT godot_gdnative_init(godot_gdnative_init_options *o) {
const godot_gdnative_core_api_struct *api = o->api_struct;
for (int i = 0; i < api->num_extensions; i++) {
if (api->extensions[i]->type != GDNATIVE_EXT_NET)
continue;
@@ -16,19 +111,25 @@ 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) {
WebRTCPeerNative::_net_api = (const godot_gdnative_ext_net_3_2_api_struct *)net_api->next;
WebRTCPeerConnectionNative::_net_api = (const godot_gdnative_ext_net_3_2_api_struct *)net_api->next;
}
}
godot_webrtc::WebRTCLibPeerConnection::initialize_signaling();
godot::Godot::gdnative_init(o);
}
extern "C" void GDN_EXPORT godot_gdnative_terminate(godot_gdnative_terminate_options *o) {
if (_singleton) { // If we are the active singleton, unregister
WebRTCPeerConnectionNative::_net_api->godot_net_set_webrtc_library(NULL);
}
godot_webrtc::WebRTCLibPeerConnection::deinitialize_signaling();
godot::Godot::gdnative_terminate(o);
}
extern "C" void GDN_EXPORT godot_nativescript_init(void *handle) {
godot::Godot::nativescript_init(handle);
godot::register_class<godot_webrtc::WebRTCLibPeer>();
godot::register_class<godot_webrtc::WebRTCLibPeerConnection>();
godot::register_class<godot_webrtc::WebRTCLibDataChannel>();
}

View File

@@ -0,0 +1,126 @@
/*************************************************************************/
/* 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"
void WebRTCDataChannelNative::register_interface(const godot_net_webrtc_data_channel *p_interface) {
ERR_FAIL_COND(!WebRTCPeerConnectionNative::_net_api);
WebRTCPeerConnectionNative::_net_api->godot_net_bind_webrtc_data_channel(_owner, p_interface);
}
void WebRTCDataChannelNative::_register_methods() {}
void WebRTCDataChannelNative::_init() {
register_interface(&interface);
}
WebRTCDataChannelNative::~WebRTCDataChannelNative() {
if (_owner) {
register_interface(NULL);
}
}
/*
* The C interface that implements WebRTCDataChannel.
* In this case it forwards calls to our C++ class, but could be plain C,
* and you could use void *user for any kind of state struct pointer you have.
*/
godot_error get_packet_wdc(void *user, const uint8_t **r_buffer, int *r_len) {
return ((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);
}
godot_int get_available_packet_count_wdc(const void *user) {
return ((WebRTCDataChannelNative *)user)->get_available_packet_count();
}
godot_int get_max_packet_size_wdc(const void *user) {
return ((WebRTCDataChannelNative *)user)->get_max_packet_size();
}
void set_write_mode_wdc(void *user, godot_int write_mode) {
((WebRTCDataChannelNative *)user)->set_write_mode(write_mode);
}
godot_int get_write_mode_wdc(const void *user) {
return ((WebRTCDataChannelNative *)user)->get_write_mode();
}
bool was_string_packet_wdc(const void *user) {
return ((WebRTCDataChannelNative *)user)->was_string_packet();
}
godot_int get_ready_state_wdc(const void *user) {
return (godot_int)(((WebRTCDataChannelNative *)user)->get_ready_state());
}
const char *get_label_wdc(const void *user) {
return ((WebRTCDataChannelNative *)user)->get_label();
}
bool is_ordered_wdc(const void *user) {
return ((WebRTCDataChannelNative *)user)->is_ordered();
}
int get_id_wdc(const void *user) {
return ((WebRTCDataChannelNative *)user)->get_id();
}
int get_max_packet_life_time_wdc(const void *user) {
return ((WebRTCDataChannelNative *)user)->get_max_packet_life_time();
}
int get_max_retransmits_wdc(const void *user) {
return ((WebRTCDataChannelNative *)user)->get_max_retransmits();
}
const char *get_protocol_wdc(const void *user) {
return ((WebRTCDataChannelNative *)user)->get_protocol();
}
bool is_negotiated_wdc(const void *user) {
return ((WebRTCDataChannelNative *)user)->is_negotiated();
}
int get_buffered_amount_wdc(const void *user) {
return ((WebRTCDataChannelNative *)user)->get_buffered_amount();
}
godot_error poll_wdc(void *user) {
return ((WebRTCDataChannelNative *)user)->poll();
}
void close_wdc(void *user) {
((WebRTCDataChannelNative *)user)->close();
}

View File

@@ -0,0 +1,139 @@
/*************************************************************************/
/* 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
#include <Godot.hpp>
#include <Reference.hpp>
#include <WebRTCDataChannelGDNative.hpp>
#include <net/godot_net.h>
/* Forward declare interface functions */
godot_error get_packet_wdc(void *, const uint8_t **, int *);
godot_error put_packet_wdc(void *, const uint8_t *, int);
godot_int get_available_packet_count_wdc(const void *);
godot_int get_max_packet_size_wdc(const void *);
void set_write_mode_wdc(void *, godot_int);
godot_int get_write_mode_wdc(const void *);
bool was_string_packet_wdc(const void *);
godot_int get_ready_state_wdc(const void *);
const char *get_label_wdc(const void *);
bool is_ordered_wdc(const void *);
int get_id_wdc(const void *);
int get_max_packet_life_time_wdc(const void *);
int get_max_retransmits_wdc(const void *);
const char *get_protocol_wdc(const void *);
bool is_negotiated_wdc(const void *);
int get_buffered_amount_wdc(const void *);
godot_error poll_wdc(void *);
void close_wdc(void *);
#if GODOT_NET_WEBRTC_API_MAJOR == 3 && GODOT_NET_WEBRTC_API_MINOR < 4
extern "C" {
/* Extensions to WebRTCDataChannel */
typedef struct {
int (*get_buffered_amount)(const void *);
void *next; /* For extension? */
} godot_net_webrtc_data_channel_ext;
}
#endif
class WebRTCDataChannelNative : public godot::WebRTCDataChannelGDNative {
GODOT_CLASS(WebRTCDataChannelNative, godot::WebRTCDataChannelGDNative);
protected:
godot_net_webrtc_data_channel_ext interface_ext = {
&get_buffered_amount_wdc,
NULL,
};
godot_net_webrtc_data_channel interface = {
{ 3, 1 },
this,
&get_packet_wdc,
&put_packet_wdc,
&get_available_packet_count_wdc,
&get_max_packet_size_wdc,
&set_write_mode_wdc,
&get_write_mode_wdc,
&was_string_packet_wdc,
&get_ready_state_wdc,
&get_label_wdc,
&is_ordered_wdc,
&get_id_wdc,
&get_max_packet_life_time_wdc,
&get_max_retransmits_wdc,
&get_protocol_wdc,
&is_negotiated_wdc,
&poll_wdc,
&close_wdc,
&interface_ext,
};
public:
static void _register_methods();
void _init();
void register_interface(const godot_net_webrtc_data_channel *interface);
virtual void set_write_mode(godot_int mode) = 0;
virtual godot_int 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 int get_buffered_amount() const = 0;
virtual godot_error poll() = 0;
virtual void close() = 0;
/* PacketPeer */
virtual godot_error get_packet(const uint8_t **r_buffer, 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;
~WebRTCDataChannelNative();
};
#endif // WEBRTC_DATA_CHANNEL_NATIVE

View File

@@ -0,0 +1,95 @@
/*************************************************************************/
/* 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"
const godot_gdnative_ext_net_3_2_api_struct *WebRTCPeerConnectionNative::_net_api = NULL;
void WebRTCPeerConnectionNative::register_interface(const godot_net_webrtc_peer_connection *p_interface) {
ERR_FAIL_COND(!_net_api);
_net_api->godot_net_bind_webrtc_peer_connection(_owner, p_interface);
}
void WebRTCPeerConnectionNative::_register_methods() {}
void WebRTCPeerConnectionNative::_init() {
register_interface(&interface);
}
WebRTCPeerConnectionNative::~WebRTCPeerConnectionNative() {
if (_owner) {
register_interface(NULL);
}
}
/*
* The C interface that implements WebRTCPeerConnection.
* In this case it forwards calls to our C++ class, but could be plain C,
* and you could use void *user for any kind of state struct pointer you have.
*/
godot_int get_connection_state_wp(const void *user) {
return (godot_int)((WebRTCPeerConnectionNative *)user)->get_connection_state();
}
godot_error initialize_wp(void *user, const godot_dictionary *p_config) {
return ((WebRTCPeerConnectionNative *)user)->initialize(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);
}
godot_error create_offer_wp(void *user) {
return ((WebRTCPeerConnectionNative *)user)->create_offer();
}
godot_error create_answer_wp(void *user) {
return GODOT_ERR_UNAVAILABLE; // Not implemented, not used yet.
}
godot_error set_remote_description_wp(void *user, const char *type, const char *sdp) {
return ((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);
}
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);
}
godot_error poll_wp(void *user) {
return ((WebRTCPeerConnectionNative *)user)->poll();
}
void close_wp(void *user) {
((WebRTCPeerConnectionNative *)user)->close();
}

View File

@@ -0,0 +1,96 @@
/*************************************************************************/
/* 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
#include <Godot.hpp>
#include <Reference.hpp>
#include <WebRTCPeerConnectionGDNative.hpp>
#include <net/godot_net.h>
/* Forward declare interface functions */
godot_int get_connection_state_wp(const void *);
godot_error initialize_wp(void *, const godot_dictionary *);
godot_object *create_data_channel_wp(void *, const char *, const godot_dictionary *);
godot_error create_offer_wp(void *);
godot_error create_answer_wp(void *);
godot_error set_remote_description_wp(void *, const char *, const char *);
godot_error set_local_description_wp(void *, const char *, const char *);
godot_error add_ice_candidate_wp(void *, const char *, int, const char *);
godot_error poll_wp(void *);
void close_wp(void *);
class WebRTCPeerConnectionNative : public godot::WebRTCPeerConnectionGDNative {
GODOT_CLASS(WebRTCPeerConnectionNative, godot::WebRTCPeerConnectionGDNative);
protected:
godot_net_webrtc_peer_connection interface = {
{ 3, 1 },
this,
&get_connection_state_wp,
&initialize_wp,
&create_data_channel_wp,
&create_offer_wp,
&create_answer_wp,
&set_remote_description_wp,
&set_local_description_wp,
&add_ice_candidate_wp,
&poll_wp,
&close_wp,
NULL,
};
public:
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 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;
~WebRTCPeerConnectionNative();
};
#endif // WEBRTC_PEER_NATIVE

View File

@@ -1,77 +0,0 @@
#include "WebRTCPeerNative.hpp"
const godot_gdnative_ext_net_3_2_api_struct *WebRTCPeerNative::_net_api = NULL;
void WebRTCPeerNative::register_interface(const godot_net_webrtc_peer *p_interface) {
ERR_FAIL_COND(!_net_api);
_net_api->godot_net_bind_webrtc_peer(_owner, p_interface);
}
void WebRTCPeerNative::_register_methods() {}
void WebRTCPeerNative::_init() {
register_interface(&interface);
}
WebRTCPeerNative::~WebRTCPeerNative() {
if (_owner) {
register_interface(NULL);
}
}
/*
* The C interface that implements WebRTCPeer.
* In this case it forwards calls to our C++ class, but could be plain C,
* and you could use void *user for any kind of state struct pointer you have.
*/
godot_error get_packet_wp(void *user, const uint8_t **r_buffer, int *r_len) {
return ((WebRTCPeerNative *)user)->get_packet(r_buffer, r_len);
}
godot_error put_packet_wp(void *user, const uint8_t *p_buffer, int p_len) {
return ((WebRTCPeerNative *)user)->put_packet(p_buffer, p_len);
}
godot_int get_available_packet_count_wp(const void *user) {
return ((WebRTCPeerNative *)user)->get_available_packet_count();
}
godot_int get_max_packet_size_wp(const void *user) {
return ((WebRTCPeerNative *)user)->get_max_packet_size();
}
void set_write_mode_wp(void *user, godot_int write_mode) {
((WebRTCPeerNative *)user)->set_write_mode(write_mode);
}
godot_int get_write_mode_wp(const void *user) {
return ((WebRTCPeerNative *)user)->get_write_mode();
}
bool was_string_packet_wp(const void *user) {
return ((WebRTCPeerNative *)user)->was_string_packet();
}
godot_int get_connection_state_wp(const void *user) {
return ((WebRTCPeerNative *)user)->get_connection_state();
}
godot_error create_offer_wp(void *user) {
return ((WebRTCPeerNative *)user)->create_offer();
}
godot_error set_remote_description_wp(void *user, const char *type, const char *sdp) {
return ((WebRTCPeerNative *)user)->set_remote_description(type, sdp);
}
godot_error set_local_description_wp(void *user, const char *type, const char *sdp) {
return ((WebRTCPeerNative *)user)->set_local_description(type, sdp);
}
godot_error add_ice_candidate_wp(void *user, const char *sdpMidName, int sdpMlineIndexName, const char *sdpName) {
return ((WebRTCPeerNative *)user)->add_ice_candidate(sdpMidName, sdpMlineIndexName, sdpName);
}
godot_error poll_wp(void *user) {
return ((WebRTCPeerNative *)user)->poll();
}

View File

@@ -1,80 +0,0 @@
#ifndef WEBRTC_PEER_NATIVE
#define WEBRTC_PEER_NATIVE
#include <Godot.hpp>
#include <Reference.hpp>
#include <WebRTCPeerGDNative.hpp>
#include <net/godot_net.h>
/* Forward declare interface functions */
godot_error get_packet_wp(void *, const uint8_t **, int *);
godot_error put_packet_wp(void *, const uint8_t *, int);
godot_int get_available_packet_count_wp(const void *);
godot_int get_max_packet_size_wp(const void *);
void set_write_mode_wp(void *, godot_int);
godot_int get_write_mode_wp(const void *);
bool was_string_packet_wp(const void *);
godot_int get_connection_state_wp(const void *);
godot_error create_offer_wp(void *);
godot_error set_remote_description_wp(void *, const char *, const char *);
godot_error set_local_description_wp(void *, const char *, const char *);
godot_error add_ice_candidate_wp(void *, const char *, int, const char *);
godot_error poll_wp(void *);
class WebRTCPeerNative : public godot::WebRTCPeerGDNative {
GODOT_CLASS(WebRTCPeerNative, godot::WebRTCPeerGDNative);
protected:
godot_net_webrtc_peer interface = {
{ 3, 1 },
this,
&get_packet_wp,
&put_packet_wp,
&get_available_packet_count_wp,
&get_max_packet_size_wp,
&set_write_mode_wp,
&get_write_mode_wp,
&was_string_packet_wp,
&get_connection_state_wp,
&create_offer_wp,
&set_remote_description_wp,
&set_local_description_wp,
&add_ice_candidate_wp,
&poll_wp,
NULL,
};
public:
static void _register_methods();
static const godot_gdnative_ext_net_3_2_api_struct *_net_api;
void _init();
void register_interface(const godot_net_webrtc_peer *interface);
virtual void set_write_mode(godot_int mode) = 0;
virtual godot_int get_write_mode() const = 0;
virtual bool was_string_packet() const = 0;
virtual godot_int get_connection_state() const = 0;
virtual godot_error create_offer() = 0;
virtual godot_error set_remote_description(const char *type, const char *sdp) = 0;
virtual godot_error set_local_description(const char *type, const char *sdp) = 0;
virtual godot_error add_ice_candidate(const char *sdpMidName, int sdpMlineIndexName, const char *sdpName) = 0;
virtual godot_error poll() = 0;
/* PacketPeer */
virtual godot_error get_packet(const uint8_t **r_buffer, int *r_len) = 0;
virtual godot_error put_packet(const uint8_t *p_buffer, int p_len) = 0;
virtual godot_int get_available_packet_count() const = 0;
virtual godot_int get_max_packet_size() const = 0;
~WebRTCPeerNative();
};
#endif // WEBRTC_PEER_NATIVE