├── .clang-format ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── PULL_REQUEST_TEMPLATE.md └── workflows │ ├── cpp-python-tests.yml │ ├── gen-doc-and-release.yml │ └── github-stats.yml ├── .gitignore ├── .gitmodules ├── BUILD_INSTRUCTIONS.md ├── CMakeLists.txt ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── VERSION ├── cmake ├── macos_get_version.cmake ├── macos_get_version_script.cmake ├── pip_install.cmake.in └── pip_utils.cmake ├── doc ├── .nojekyll ├── README.md ├── cpp │ ├── Doxyfile │ └── mainpage.dox ├── footer.html ├── header.html ├── index.html ├── js │ ├── Doxyfile │ └── mainpage.dox └── stylesheet.css ├── examples ├── cpp-camera-stream-client │ ├── .gitignore │ ├── AlsaPcmDevice.cpp │ ├── AlsaPcmDevice.h │ ├── CMakeLists.txt │ ├── README.md │ └── main.cpp ├── cpp-data-channel-client-reliability-tests │ ├── .gitignore │ ├── CMakeLists.txt │ ├── README.md │ ├── iceServers.json │ ├── main.cpp │ └── start_server.bash ├── cpp-data-channel-client │ ├── .gitignore │ ├── CMakeLists.txt │ ├── README.md │ └── main.cpp ├── cpp-video-stream-client │ ├── .gitignore │ ├── CMakeLists.txt │ ├── README.md │ └── main.cpp ├── python-data-channel-client │ ├── README.md │ └── python_data_channel_client.py ├── python-stream-client │ ├── README.md │ ├── frame.png │ ├── python_stream_client.py │ └── requirements.txt ├── web-data-channel-client │ ├── .gitignore │ ├── README.md │ ├── client.html │ ├── client.js │ ├── iceServers.json │ └── start_server.bash ├── web-stream-client │ ├── .gitignore │ ├── README.md │ ├── client.html │ ├── client.js │ ├── iceServers.json │ └── start_server.bash └── web-stream-data-channel-client │ ├── .gitignore │ ├── README.md │ ├── client.html │ ├── client.js │ ├── iceServers.json │ └── start_server.bash ├── images └── IntRoLab.png ├── opentera-webrtc-native-client ├── .gitignore ├── 3rdParty │ ├── .clang-format │ ├── CMakeLists.txt │ └── webrtc_native │ │ ├── .gitignore │ │ └── CMakeLists.txt ├── CMakeLists.txt ├── OpenteraWebrtcNativeClient │ ├── CMakeLists.txt │ ├── README.md │ ├── include │ │ └── OpenteraWebrtcNativeClient │ │ │ ├── Codecs │ │ │ └── VideoCodecFactories.h │ │ │ ├── Configurations │ │ │ ├── AudioSourceConfiguration.h │ │ │ ├── DataChannelConfiguration.h │ │ │ ├── SignalingServerConfiguration.h │ │ │ ├── VideoSourceConfiguration.h │ │ │ ├── VideoStreamConfiguration.h │ │ │ └── WebrtcConfiguration.h │ │ │ ├── DataChannelClient.h │ │ │ ├── Handlers │ │ │ ├── DataChannelPeerConnectionHandler.h │ │ │ ├── PeerConnectionHandler.h │ │ │ └── StreamPeerConnectionHandler.h │ │ │ ├── OpenteraAudioDeviceModule.h │ │ │ ├── Signaling │ │ │ ├── SignalingClient.h │ │ │ └── WebSocketSignalingClient.h │ │ │ ├── Sinks │ │ │ ├── AudioSink.h │ │ │ ├── EncodedVideoSink.h │ │ │ └── VideoSink.h │ │ │ ├── Sources │ │ │ ├── AudioSource.h │ │ │ └── VideoSource.h │ │ │ ├── StreamClient.h │ │ │ ├── Utils │ │ │ ├── ClassMacro.h │ │ │ ├── Client.h │ │ │ ├── FunctionTask.h │ │ │ ├── Http.h │ │ │ ├── IceServer.h │ │ │ └── thread.h │ │ │ ├── WebrtcClient.h │ │ │ └── version.h │ ├── python │ │ ├── CMakeLists.txt │ │ ├── include │ │ │ └── OpenteraWebrtcNativeClientPython │ │ │ │ ├── Configurations │ │ │ │ ├── AudioSourceConfigurationPython.h │ │ │ │ ├── DataChannelConfigurationPython.h │ │ │ │ ├── SignalingServerConfigurationPython.h │ │ │ │ ├── VideoSourceConfigurationPython.h │ │ │ │ ├── VideoStreamConfigurationPython.h │ │ │ │ └── WebrtcConfigurationPython.h │ │ │ │ ├── DataChannelClientPython.h │ │ │ │ ├── Json.h │ │ │ │ ├── PyBindUtils.h │ │ │ │ ├── Sources │ │ │ │ ├── AudioSourcePython.h │ │ │ │ └── VideoSourcePython.h │ │ │ │ ├── StreamClientPython.h │ │ │ │ ├── Utils │ │ │ │ ├── ClientPython.h │ │ │ │ └── IceServerPython.h │ │ │ │ └── WebrtcClientPython.h │ │ ├── package │ │ │ ├── CMakeLists.txt │ │ │ ├── MANIFEST.in.in │ │ │ ├── README.md.in │ │ │ ├── __init__.py.in │ │ │ ├── _source │ │ │ │ ├── conf.py.in │ │ │ │ ├── index.rst │ │ │ │ └── theme │ │ │ │ │ └── requirements.txt │ │ │ ├── post-process-doc.sh │ │ │ ├── post-process-stub.sh │ │ │ └── setup.py.in │ │ ├── src │ │ │ ├── Configurations │ │ │ │ ├── AudioSourceConfigurationPython.cpp │ │ │ │ ├── DataChannelConfigurationPython.cpp │ │ │ │ ├── SignalingServerConfigurationPython.cpp │ │ │ │ ├── VideoSourceConfigurationPython.cpp │ │ │ │ ├── VideoStreamConfigurationPython.cpp │ │ │ │ └── WebrtcConfigurationPython.cpp │ │ │ ├── DataChannelClientPython.cpp │ │ │ ├── Json.cpp │ │ │ ├── Sources │ │ │ │ ├── AudioSourcePython.cpp │ │ │ │ └── VideoSourcePython.cpp │ │ │ ├── StreamClientPython.cpp │ │ │ ├── Utils │ │ │ │ ├── ClientPython.cpp │ │ │ │ └── IceServerPython.cpp │ │ │ ├── WebrtcClientPython.cpp │ │ │ └── opentera_webrtc_native_client.cpp │ │ └── test │ │ │ ├── .gitignore │ │ │ ├── callback_awaiter.py │ │ │ ├── configurations │ │ │ ├── __init__.py │ │ │ ├── audio_source_configuration_test.py │ │ │ ├── data_channel_configuration_test.py │ │ │ ├── signaling_server_configuration_test.py │ │ │ ├── video_source_configuration_test.py │ │ │ ├── video_stream_configuration_test.py │ │ │ └── webrtc_configuration_test.py │ │ │ ├── data_channel_client_test.py │ │ │ ├── failure_test_case.py │ │ │ ├── requirements.txt │ │ │ ├── resources │ │ │ └── iceServers.json │ │ │ ├── signaling_server_runner.py │ │ │ ├── sources │ │ │ ├── __init__.py │ │ │ ├── audio_source_test.py │ │ │ └── video_source_test.py │ │ │ ├── start_tests.bash │ │ │ ├── stream_client_test.py │ │ │ ├── utils │ │ │ ├── __init__.py │ │ │ ├── client_test.py │ │ │ └── ice_server_test.py │ │ │ └── websocket_inactive_client_test.py │ ├── src │ │ ├── Codecs │ │ │ └── VideoCodecFactories.cpp │ │ ├── Configurations │ │ │ ├── AudioSourceConfiguration.cpp │ │ │ ├── DataChannelConfiguration.cpp │ │ │ ├── SignalingServerConfiguration.cpp │ │ │ ├── VideoSourceConfiguration.cpp │ │ │ ├── VideoStreamConfiguration.cpp │ │ │ └── WebrtcConfiguration.cpp │ │ ├── DataChannelClient.cpp │ │ ├── Handlers │ │ │ ├── DataChannelPeerConnectionHandler.cpp │ │ │ ├── PeerConnectionHandler.cpp │ │ │ └── StreamPeerConnectionHandler.cpp │ │ ├── OpenteraAudioDeviceModule.cpp │ │ ├── Signaling │ │ │ ├── SignalingClient.cpp │ │ │ └── WebSocketSignalingClient.cpp │ │ ├── Sinks │ │ │ ├── AudioSink.cpp │ │ │ ├── EncodedVideoSink.cpp │ │ │ └── VideoSink.cpp │ │ ├── Sources │ │ │ ├── AudioSource.cpp │ │ │ └── VideoSource.cpp │ │ ├── StreamClient.cpp │ │ ├── Utils │ │ │ ├── Client.cpp │ │ │ ├── Http.cpp │ │ │ ├── IceServer.cpp │ │ │ └── thread.cpp │ │ ├── WebrtcClient.cpp │ │ └── version.cpp │ └── test │ │ ├── CMakeLists.txt │ │ ├── include │ │ └── OpenteraWebrtcNativeClientTests │ │ │ └── CallbackAwaiter.h │ │ ├── resources │ │ ├── cert.pem │ │ ├── iceServers.json │ │ └── key.pem │ │ └── src │ │ ├── CallbackAwaiter.cpp │ │ ├── Codecs │ │ └── VideoCodecFactoriesTests.cpp │ │ ├── Configurations │ │ ├── AudioSourceConfigurationTests.cpp │ │ ├── DataChannelConfigurationTests.cpp │ │ ├── SignalingServerConfigurationTests.cpp │ │ ├── VideoSourceConfigurationTests.cpp │ │ ├── VideoStreamConfigurationTests.cpp │ │ └── WebrtcConfigurationTests.cpp │ │ ├── DataChannelClientTests.cpp │ │ ├── Sinks │ │ └── EncodedVideoSinkTests.cpp │ │ ├── Sources │ │ └── AudioSourceTests.cpp │ │ ├── StreamClientTests.cpp │ │ ├── Utils │ │ ├── ClientTests.cpp │ │ ├── FunctionTaskTests.cpp │ │ ├── HttpTests.cpp │ │ └── IceServerTests.cpp │ │ └── main.cpp ├── OpenteraWebrtcNativeGStreamer │ ├── CMakeLists.txt │ ├── LICENSE_APACHE-2.0 │ ├── LICENSE_GPL-3.0 │ ├── LICENSE_LGPL-3.0 │ ├── README.md │ ├── include │ │ └── OpenteraWebrtcNativeGStreamer │ │ │ ├── Decoders │ │ │ ├── GStreamerVideoDecoder.h │ │ │ ├── H264GStreamerVideoDecoders.h │ │ │ ├── Vp8GStreamerVideoDecoders.h │ │ │ └── Vp9GStreamerVideoDecoders.h │ │ │ ├── Encoders │ │ │ ├── GStreamerVideoEncoder.h │ │ │ ├── H264GStreamerVideoEncoders.h │ │ │ ├── Vp8GStreamerVideoEncoders.h │ │ │ └── Vp9GStreamerVideoEncoders.h │ │ │ ├── Factories │ │ │ ├── WebRtcGStreamerVideoDecoderFactory.h │ │ │ └── WebRtcGStreamerVideoEncoderFactory.h │ │ │ ├── Pipeline │ │ │ ├── GStreamerDecoderPipeline.h │ │ │ └── GStreamerEncoderPipeline.h │ │ │ └── Utils │ │ │ ├── ClassMacro.h │ │ │ ├── GStreamerBufferPool.h │ │ │ ├── GStreamerHelpers.h │ │ │ ├── GStreamerMessageHandling.h │ │ │ ├── GStreamerSupport.h │ │ │ ├── GstMappedBuffer.h │ │ │ ├── GstMappedFrame.h │ │ │ └── out_ptr.h │ └── src │ │ ├── Decoders │ │ ├── GStreamerVideoDecoder.cpp │ │ ├── H264GStreamerVideoDecoders.cpp │ │ ├── Vp8GStreamerVideoDecoders.cpp │ │ └── Vp9GStreamerVideoDecoders.cpp │ │ ├── Encoders │ │ ├── GStreamerVideoEncoder.cpp │ │ ├── H264GStreamerVideoEncoders.cpp │ │ ├── Vp8GStreamerVideoEncoders.cpp │ │ └── Vp9GStreamerVideoEncoders.cpp │ │ ├── Factories │ │ ├── WebRtcGStreamerVideoDecoderFactory.cpp │ │ └── WebRtcGStreamerVideoEncoderFactory.cpp │ │ ├── Pipeline │ │ ├── GStreamerDecoderPipeline.cpp │ │ └── GStreamerEncoderPipeline.cpp │ │ └── Utils │ │ ├── GStreamerBufferPool.cpp │ │ ├── GStreamerHelpers.cpp │ │ └── GStreamerSupport.cpp └── README.md ├── opentera-webrtc-web-client ├── .eslintrc.js ├── .gitignore ├── README.md ├── browser-tests │ ├── .gitignore │ ├── DataChannelClient │ │ ├── disconnectedDataChannelClient.spec.js │ │ ├── rightPasswordDataChannelClient.spec.js │ │ └── wrongPasswordDataChannelClient.spec.js │ ├── iceServers.json │ ├── iceServers.spec.js │ ├── run_browser_tests.bash │ └── tests.html ├── index.js ├── package.json ├── src │ ├── DataChannelClient.js │ ├── Signaling │ │ ├── SignalingClient.js │ │ └── WebSocketSignalingClient.js │ ├── StreamClient.js │ ├── StreamDataChannelClient.js │ ├── WebrtcClient.js │ ├── devices.js │ ├── iceServers.js │ └── index.js └── webpack.config.js ├── requirements.txt └── signaling-server ├── .gitignore ├── CMakeLists.txt ├── README.md ├── _source ├── conf.py.in ├── index.rst └── theme │ └── requirements.txt ├── opentera-signaling-server ├── opentera_webrtc ├── signaling_server │ ├── __init__.py │ ├── room_manager.py │ ├── signaling_server.py │ └── web_socket_client_manager.py └── tests │ ├── __init__.py │ ├── test_room_manager.py │ └── test_web_socket_client_manager.py ├── requirements.txt ├── setup.py.in └── tools └── generate_certificate.sh /.clang-format: -------------------------------------------------------------------------------- 1 | # LLVM 12 2 | --- 3 | BasedOnStyle: LLVM 4 | AccessModifierOffset: -4 5 | AlignAfterOpenBracket: AlwaysBreak 6 | AlignConsecutiveAssignments: None 7 | AlignConsecutiveBitFields: None 8 | AlignConsecutiveDeclarations: None 9 | AlignConsecutiveMacros: AcrossComments 10 | AlignEscapedNewlines: Right 11 | AlignOperands: Align 12 | AlignTrailingComments: false 13 | AllowAllArgumentsOnNextLine: false 14 | AllowAllConstructorInitializersOnNextLine: false 15 | AllowAllParametersOfDeclarationOnNextLine: false 16 | AllowShortBlocksOnASingleLine: Always 17 | AllowShortCaseLabelsOnASingleLine: false 18 | AllowShortEnumsOnASingleLine: false 19 | AllowShortFunctionsOnASingleLine: Inline 20 | AllowShortIfStatementsOnASingleLine: Never 21 | AllowShortLambdasOnASingleLine: All 22 | AllowShortLoopsOnASingleLine: false 23 | AlwaysBreakAfterReturnType: None 24 | AlwaysBreakBeforeMultilineStrings: false 25 | AlwaysBreakTemplateDeclarations: Yes 26 | AttributeMacros: [] 27 | BinPackArguments: false 28 | BinPackParameters: false 29 | BitFieldColonSpacing: After 30 | BreakBeforeBraces: Allman 31 | BreakBeforeBinaryOperators: None 32 | BreakBeforeConceptDeclarations: true 33 | BreakBeforeTernaryOperators: false 34 | BreakConstructorInitializers: BeforeColon 35 | BreakInheritanceList: BeforeColon 36 | BreakStringLiterals: true 37 | ColumnLimit: 120 38 | CompactNamespaces: false 39 | ConstructorInitializerAllOnOneLineOrOnePerLine: true 40 | ConstructorInitializerIndentWidth: 4 41 | ContinuationIndentWidth: 4 42 | Cpp11BracedListStyle: true 43 | DeriveLineEnding: false 44 | DerivePointerAlignment: false 45 | EmptyLineBeforeAccessModifier: LogicalBlock 46 | FixNamespaceComments: false 47 | ForEachMacros: [] 48 | IncludeBlocks: Preserve 49 | IndentCaseBlocks: false 50 | IndentCaseLabels: true 51 | IndentExternBlock: NoIndent 52 | IndentGotoLabels: true 53 | IndentPPDirectives: None 54 | IndentWidth: 4 55 | IndentWrappedFunctionNames: true 56 | KeepEmptyLinesAtTheStartOfBlocks: false 57 | Language: Cpp 58 | MaxEmptyLinesToKeep: 2 59 | NamespaceIndentation: All 60 | PointerAlignment: Left 61 | ReflowComments: true 62 | SortIncludes: false 63 | SortUsingDeclarations: false 64 | SpaceAfterCStyleCast: false 65 | SpaceAfterLogicalNot: false 66 | SpaceAfterTemplateKeyword: false 67 | SpaceAroundPointerQualifiers: Default 68 | SpaceBeforeAssignmentOperators: true 69 | SpaceBeforeCaseColon: false 70 | SpaceBeforeCpp11BracedList: false 71 | SpaceBeforeCtorInitializerColon: true 72 | SpaceBeforeInheritanceColon: true 73 | SpaceBeforeParens: ControlStatements 74 | SpaceBeforeRangeBasedForLoopColon: true 75 | SpaceBeforeSquareBrackets: false 76 | SpaceInEmptyBlock: false 77 | SpaceInEmptyParentheses: false 78 | SpacesBeforeTrailingComments: 2 79 | SpacesInAngles: Never 80 | SpacesInCStyleCastParentheses: false 81 | SpacesInConditionalStatement: false 82 | SpacesInContainerLiterals: false 83 | SpacesInParentheses: false 84 | SpacesInSquareBrackets: false 85 | Standard: c++14 86 | StatementAttributeLikeMacros: [emit] 87 | StatementMacros: [Q_UNUSED, Q_OBJECT] 88 | TabWidth: 4 89 | UseCRLF: false 90 | UseTab: Never 91 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | The document is based on [this template](https://github.com/auth0/open-source-template/blob/master/.github/PULL_REQUEST_TEMPLATE.md) 2 | 3 | By submitting a PR to this repository, you agree to the terms within the [Code of Conduct](https://github.com/introlab/opentera-webrtc/blob/main/CODE_OF_CONDUCT.md). 4 | Please see the [contributing guidelines](https://github.com/introlab/opentera-webrtc/blob/main/CONTRIBUTING.md) for how to create and submit a high-quality PR for this repo. 5 | 6 | ### Description 7 | 8 | > Describe the purpose of this PR along with any background information and the impacts of the proposed change. 9 | > For the benefit of the community, please do not assume prior context. 10 | > 11 | > Provide details that support your chosen implementation, including: breaking changes, alternatives considered, changes to the API, etc. 12 | 13 | 14 | ### References 15 | 16 | > Include any links supporting this change such as a: 17 | > 18 | > - GitHub Issue/PR number addressed or fixed 19 | > - Related pull requests/issues from other repos 20 | > 21 | > If there are no references, simply delete this section. 22 | 23 | ### Testing 24 | 25 | > Describe how this can be tested by reviewers. Be specific about anything not tested and reasons why. 26 | > Tests should be added for new functionality and existing tests should complete without errors. 27 | > 28 | > Please include any manual steps for testing end-to-end or functionality not covered by unit/integration tests. 29 | 30 | - [ ] This change adds test coverage for new/changed/fixed functionality 31 | 32 | ### Checklist 33 | 34 | - [ ] I have added documentation for new/changed functionality in this PR 35 | - [ ] I have formatted the files 36 | - [ ] All active GitHub checks for tests are passing 37 | - [ ] The correct base branch is being used, if not `main` 38 | -------------------------------------------------------------------------------- /.github/workflows/github-stats.yml: -------------------------------------------------------------------------------- 1 | name: Scheduled Stats Extraction From GitHub 2 | 3 | on: 4 | workflow_dispatch: 5 | schedule: 6 | - cron: '0 5 * * *' 7 | jobs: 8 | get_stats: 9 | runs-on: ubuntu-22.04 10 | steps: 11 | - name: Update Stats 12 | uses: introlab/github-stats-action@v1 13 | with: 14 | github-stats-token: ${{ secrets.STATS_TOKEN }} 15 | google-application-credentials: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }} 16 | spreadsheet-id: ${{ secrets.SPREADSHEET_ID }} 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | build 3 | cmake-build-* 4 | compile_commands.json 5 | .gdbinit 6 | doc/cpp/html 7 | doc/js/html 8 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "opentera-webrtc-native-client/3rdParty/googletest"] 2 | path = opentera-webrtc-native-client/3rdParty/googletest 3 | url = https://github.com/google/googletest.git 4 | [submodule "opentera-webrtc-native-client/3rdParty/cpp-subprocess"] 5 | path = opentera-webrtc-native-client/3rdParty/cpp-subprocess 6 | url = https://github.com/arun11299/cpp-subprocess.git 7 | [submodule "opentera-webrtc-native-client/3rdParty/pybind11"] 8 | path = opentera-webrtc-native-client/3rdParty/pybind11 9 | url = https://github.com/pybind/pybind11.git 10 | [submodule "opentera-webrtc-native-client/3rdParty/cpp-httplib"] 11 | path = opentera-webrtc-native-client/3rdParty/cpp-httplib 12 | url = https://github.com/yhirose/cpp-httplib.git 13 | [submodule "opentera-webrtc-native-client/3rdParty/opencv"] 14 | path = opentera-webrtc-native-client/3rdParty/opencv 15 | url = https://github.com/opencv/opencv.git 16 | [submodule "opentera-webrtc-native-client/3rdParty/json"] 17 | path = opentera-webrtc-native-client/3rdParty/json 18 | url = https://github.com/nlohmann/json 19 | [submodule "opentera-webrtc-native-client/3rdParty/IXWebSocket"] 20 | path = opentera-webrtc-native-client/3rdParty/IXWebSocket 21 | url = https://github.com/machinezone/IXWebSocket.git 22 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to opentera-webrtc 2 | This document is based on [this template](https://github.com/auth0/open-source-template/blob/master/GENERAL-CONTRIBUTING.md). 3 | 4 | Reading and following these guidelines will help us make the contribution process easy and effective for everyone involved. 5 | It also communicates that you agree to respect the time of the developers managing and developing these open source projects. 6 | In return, we will reciprocate that respect by addressing your issue, assessing changes, and helping you finalize your pull requests. 7 | 8 | ## Quick Links 9 | - [Code of Conduct](#code-of-conduct) 10 | - [Getting Started](#getting-started) 11 | - [Issues](#issues) 12 | - [Pull Requests](#pull-requests) 13 | 14 | ## Code of Conduct 15 | We take our open source community seriously and hold ourselves and other contributors to high standards of communication. 16 | By participating and contributing to this project, you agree to uphold our Code of Conduct. 17 | 18 | ## Getting Started 19 | Contributions are made to this repo via Issues and Pull Requests (PRs). A few general guidelines that cover both: 20 | - Search for existing Issues and PRs before creating your own. 21 | - 22 | 23 | ### Issues 24 | Issues should be used to report problems with the library, request a new feature, or to discuss potential changes before a PR is created. 25 | When you create a new Issue, a template will be loaded that will guide you through collecting and providing the information we need to investigate. 26 | 27 | If you find an Issue that addresses the problem you're having, please add your own reproduction information to the existing issue rather than creating a new one. 28 | Adding a reaction can also help be indicating to our maintainers that a particular problem is affecting more than just the reporter. 29 | 30 | ### Pull Requests 31 | 32 | PRs to our libraries are always welcome and can be a quick way to get your fix or improvement slated for the next release. 33 | In general, PRs should: 34 | - Only fix/add the functionality in question OR address wide-spread whitespace/style issues, not both. 35 | - Add unit or integration tests for fixed or changed functionality (if a test suite already exists). 36 | - Address a single concern in the least number of changed lines as possible. 37 | - Include documentation in the repo or on our docs site. 38 | - Be accompanied by a complete Pull Request template (loaded automatically when a PR is created). 39 | 40 | For changes that address core functionality or would require breaking changes (e.g. a major release), it's best to open an Issue to discuss your proposal first. 41 | This is not required but can save time creating and reviewing changes. 42 | 43 | In general, we follow the "fork-and-pull" Git workflow 44 | 45 | 1. Fork the repository to your own Github account 46 | 2. Clone the project to your machine 47 | 3. Create a branch locally with a succinct but descriptive name 48 | 4. Commit changes to the branch 49 | 5. Following any formatting and testing guidelines specific to this repo 50 | 6. Push changes to your fork 51 | 7. Open a PR in our repository and follow the PR template so that we can efficiently review the changes. 52 | 53 | 54 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 1.2.6 2 | -------------------------------------------------------------------------------- /cmake/macos_get_version.cmake: -------------------------------------------------------------------------------- 1 | # Inspired from : https://cmake.org/pipermail/cmake/2007-October/017290.html 2 | function(get_macos_sw_vers_product_version) 3 | find_program(SW_VERS_EXEC sw_vers) 4 | if(NOT SW_VERS_EXEC) 5 | message(FATAL_ERROR "Could not detect sw_vers executable, can not gather required information") 6 | endif() 7 | 8 | execute_process(COMMAND "${SW_VERS_EXEC}" -productVersion OUTPUT_VARIABLE SW_VERS_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE) 9 | 10 | string(REGEX REPLACE [[^([0-9]+(\.[0-9]+)?)\.[0-9]+$]] "\\1" SW_VERS_VERSION_SHORT "${SW_VERS_VERSION}") 11 | string(REGEX REPLACE [[^([0-9]+)(\.[0-9]+)+$]] "\\1" SW_VERS_VERSION_MAJOR "${SW_VERS_VERSION}") 12 | if ("${SW_VERS_VERSION_MAJOR}" STREQUAL "10") 13 | set(SW_VERS_VERSION_SHORT "${SW_VERS_VERSION_SHORT}" PARENT_SCOPE) 14 | else() 15 | set(SW_VERS_VERSION_SHORT "${SW_VERS_VERSION_MAJOR}" PARENT_SCOPE) 16 | endif() 17 | endfunction() 18 | -------------------------------------------------------------------------------- /cmake/macos_get_version_script.cmake: -------------------------------------------------------------------------------- 1 | include(cmake/macos_get_version.cmake) 2 | 3 | function(echo) 4 | execute_process(COMMAND ${CMAKE_COMMAND} -E echo "${ARGN}") 5 | endfunction() 6 | 7 | get_macos_sw_vers_product_version() 8 | echo("${SW_VERS_VERSION_SHORT}") 9 | -------------------------------------------------------------------------------- /cmake/pip_install.cmake.in: -------------------------------------------------------------------------------- 1 | set(MV OFF) 2 | set(PIP_INSTALL_OPTIONS "") 3 | 4 | if("${PIP_INSTALL_PREFIX}" STREQUAL "--user") 5 | set(PIP_INSTALL_OPTIONS "--user") 6 | elseif(NOT "${PIP_INSTALL_PREFIX}" STREQUAL "") 7 | set(PIP_INSTALL_OPTIONS "--prefix=${PIP_INSTALL_PREFIX}") 8 | if(NOT "@USE_EXACT_LIB_SUBPATH@" STREQUAL "") 9 | set(MV ON) 10 | endif() 11 | endif() 12 | 13 | execute_process( 14 | COMMAND @PIP_PYTHON_EXECUTABLE@ -m pip install --upgrade --force-reinstall --no-deps --no-cache-dir --no-index ${PIP_INSTALL_OPTIONS} --find-links=@PYTHON_PACKAGE_DIR@/dist opentera_webrtc.@PYTHON_SUBPACKAGE_NAME@ 15 | WORKING_DIRECTORY @PYTHON_PACKAGE_DIR@ 16 | ) 17 | 18 | if(${MV} STREQUAL "ON") 19 | execute_process( 20 | # The format is the same between --user (where pip should be installed) and --prefix (where the package is installed) 21 | COMMAND bash -c "rsync -a --remove-source-files ${PIP_INSTALL_PREFIX}/lib/@USE_EXACT_LIB_SUBPATH_SOURCE@/ ${PIP_INSTALL_PREFIX}/lib/@USE_EXACT_LIB_SUBPATH@/ 2> /dev/null" 22 | WORKING_DIRECTORY @PYTHON_PACKAGE_DIR@ 23 | ) 24 | execute_process( 25 | COMMAND find ${PIP_INSTALL_PREFIX}/lib -depth -type d -empty -delete 26 | WORKING_DIRECTORY @PYTHON_PACKAGE_DIR@ 27 | ) 28 | endif() 29 | 30 | execute_process( 31 | COMMAND @CMAKE_COMMAND@ -E touch @WORKING_DIR@/install.stamp 32 | WORKING_DIRECTORY @PYTHON_PACKAGE_DIR@ 33 | ) 34 | -------------------------------------------------------------------------------- /doc/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/introlab/opentera-webrtc/458277e9c1d17e9e1e1e6fe15394dee7e1329aa3/doc/.nojekyll -------------------------------------------------------------------------------- /doc/README.md: -------------------------------------------------------------------------------- 1 | # OpenTera WebRTC API Documentation 2 | 3 | API Documentation is available [here](https://introlab.github.io/opentera-webrtc). 4 | -------------------------------------------------------------------------------- /doc/cpp/mainpage.dox: -------------------------------------------------------------------------------- 1 | /** 2 | \mainpage OpenTera WebRTC C++ Library API Documentation 3 | 4 | \tableofcontents 5 | 6 | \section examples Examples 7 | 8 | \subsection data_channel_client_example Data Channel Client Example 9 | \include{lineno} cpp-data-channel-client/main.cpp 10 | 11 | \subsection video_stream_client_example Video Stream Client Example 12 | \include{lineno} cpp-video-stream-client/main.cpp 13 | 14 | */ 15 | -------------------------------------------------------------------------------- /doc/footer.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /doc/header.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | $projectname: $title 10 | $title 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | $treeview 20 | $search 21 | $mathjax 22 | 23 | $extrastylesheet 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 | 32 |
33 | 34 | 35 |
36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 48 | 49 | 50 | 51 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 |
44 |
$projectname $projectnumber 45 |
46 |
$projectbrief
47 |
52 |
$projectbrief
53 |
$searchbox
$searchbox
71 |
72 | 73 | 74 | -------------------------------------------------------------------------------- /doc/index.html: -------------------------------------------------------------------------------- 1 | 2 | OpenTera WebRTC Documentation 3 | 4 | 5 | 6 | 7 |

OpenTera WebRTC Documentation

8 | 9 | 14 | 15 | 16 | OpenTera Logo 17 | 18 | -------------------------------------------------------------------------------- /doc/js/mainpage.dox: -------------------------------------------------------------------------------- 1 | /** 2 | \mainpage OpenTera WebRTC JavaScript Library API Documentation 3 | 4 | \tableofcontents 5 | 6 | \section examples Examples 7 | 8 | \subsection web_data_channel_client_example Data Channel Client Example 9 | client.html 10 | \include{lineno} web-data-channel-client/client.html 11 | client.js 12 | \include{lineno} web-data-channel-client/client.js 13 | 14 | \subsection web_stream_client_example Stream Client Example 15 | client.html 16 | \include{lineno} web-stream-client/client.html 17 | client.js 18 | \include{lineno} web-stream-client/client.js 19 | 20 | \subsection web_stream_data_channel_client_example Stream Data Channel Client Example 21 | client.html 22 | \include{lineno} web-stream-data-channel-client/client.html 23 | client.js 24 | \include{lineno} web-stream-data-channel-client/client.js 25 | 26 | */ 27 | -------------------------------------------------------------------------------- /examples/cpp-camera-stream-client/.gitignore: -------------------------------------------------------------------------------- 1 | cmake-build-debug 2 | cmake-build-release 3 | build 4 | .idea 5 | -------------------------------------------------------------------------------- /examples/cpp-camera-stream-client/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14.0) 2 | 3 | if (UNIX AND NOT APPLE) 4 | include_directories(${CMAKE_CURRENT_BINARY_DIR}) 5 | 6 | project(CppCameraStreamClient) 7 | 8 | set(LIBRARY_OUTPUT_PATH bin/${CMAKE_BUILD_TYPE}) 9 | 10 | include_directories(${OpenCV_INCLUDE_DIRS}) 11 | include_directories(BEFORE SYSTEM ${webrtc_native_INCLUDE}) 12 | include_directories(../../opentera-webrtc-native-client/3rdParty/json/include) 13 | include_directories(../../opentera-webrtc-native-client/3rdParty/IXWebSocket) 14 | include_directories(../../opentera-webrtc-native-client/3rdParty/cpp-httplib) 15 | include_directories(../../opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include) 16 | 17 | add_executable(CppCameraStreamClient main.cpp AlsaPcmDevice.cpp) 18 | 19 | target_link_libraries(CppCameraStreamClient 20 | OpenteraWebrtcNativeClient 21 | opencv_videoio 22 | opencv_highgui 23 | ) 24 | 25 | 26 | target_link_libraries(CppCameraStreamClient 27 | pthread 28 | asound 29 | ) 30 | 31 | if (NOT OPENTERA_WEBRTC_USE_SYSTEM_OPENCV) 32 | add_dependencies(CppCameraStreamClient opencv_highgui opencv_videoio) 33 | endif() 34 | 35 | set_property(TARGET CppCameraStreamClient PROPERTY CXX_STANDARD 17) 36 | endif() 37 | -------------------------------------------------------------------------------- /examples/cpp-camera-stream-client/README.md: -------------------------------------------------------------------------------- 1 | # cpp-camera-stream-client 2 | 3 | This example shows how to use the C++ library to create a client that sends and receives a video stream and an audio stream. 4 | The video source is the webcam, the audio source is the default capture device and the audio output is the default playback device. 5 | This example should be used with [web-stream-client](../web-stream-client). 6 | 7 | ## How to use 8 | 9 | ```bash 10 | cd ../.. 11 | mkdir build 12 | cd build 13 | cmake .. 14 | cmake --build . --config Release|Debug 15 | 16 | cd bin/Release 17 | ./CppCameraStreamClient 18 | ``` 19 | -------------------------------------------------------------------------------- /examples/cpp-data-channel-client-reliability-tests/.gitignore: -------------------------------------------------------------------------------- 1 | cmake-build-debug 2 | cmake-build-release 3 | build 4 | .idea 5 | -------------------------------------------------------------------------------- /examples/cpp-data-channel-client-reliability-tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14.0) 2 | 3 | include_directories(${CMAKE_CURRENT_BINARY_DIR}) 4 | 5 | project(CppDataChannelReliabilityTests) 6 | 7 | set(LIBRARY_OUTPUT_PATH bin/${CMAKE_BUILD_TYPE}) 8 | 9 | include_directories(${OpenCV_INCLUDE_DIRS}) 10 | include_directories(BEFORE SYSTEM ${webrtc_native_INCLUDE}) 11 | include_directories(../../opentera-webrtc-native-client/3rdParty/json/include) 12 | include_directories(../../opentera-webrtc-native-client/3rdParty/IXWebSocket) 13 | include_directories(../../opentera-webrtc-native-client/3rdParty/cpp-httplib) 14 | include_directories(../../opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include) 15 | 16 | add_executable(CppDataChannelReliabilityTests main.cpp) 17 | 18 | target_link_libraries(CppDataChannelReliabilityTests 19 | OpenteraWebrtcNativeClient 20 | ) 21 | 22 | if (NOT WIN32) 23 | target_link_libraries(CppDataChannelReliabilityTests 24 | pthread 25 | ) 26 | endif() 27 | 28 | set_property(TARGET CppDataChannelReliabilityTests PROPERTY CXX_STANDARD 17) 29 | -------------------------------------------------------------------------------- /examples/cpp-data-channel-client-reliability-tests/README.md: -------------------------------------------------------------------------------- 1 | # cpp-data-channel-client-reliability-tests 2 | 3 | This example tests the reliability of the data channel. 4 | 5 | ## How to use 6 | 7 | 1. Build the example. 8 | ```bash 9 | cd ../.. 10 | mkdir build 11 | cd build 12 | cmake .. 13 | cmake --build . --config Release|Debug 14 | ``` 15 | 16 | 2. Start the signaling server. 17 | ```bash 18 | ./start_server.bash 19 | ``` 20 | 21 | 3. Start a master client. 22 | ```bash 23 | cd ../../build/bin/Release 24 | ./CppDataChannelReliabilityTests http://localhost:8080 master abc true 25 | ``` 26 | 27 | 4. Start a slave client. 28 | ```bash 29 | cd ../../build/bin/Release 30 | ./CppDataChannelReliabilityTests http://localhost:8080 slave abc false 31 | ``` 32 | -------------------------------------------------------------------------------- /examples/cpp-data-channel-client-reliability-tests/iceServers.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "urls": "stun:stun.l.google.com:19302" 4 | } 5 | ] 6 | -------------------------------------------------------------------------------- /examples/cpp-data-channel-client-reliability-tests/start_server.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SCRIPT=`realpath $0` 4 | SCRIPT_PATH=`dirname $SCRIPT` 5 | 6 | cd $SCRIPT_PATH/../../signaling-server 7 | python3 opentera-signaling-server --port 8080 --password abc --ice_servers $SCRIPT_PATH/iceServers.json 8 | -------------------------------------------------------------------------------- /examples/cpp-data-channel-client/.gitignore: -------------------------------------------------------------------------------- 1 | cmake-build-debug 2 | cmake-build-release 3 | build 4 | .idea 5 | -------------------------------------------------------------------------------- /examples/cpp-data-channel-client/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14.0) 2 | 3 | include_directories(${CMAKE_CURRENT_BINARY_DIR}) 4 | 5 | project(CppDataChannelClient) 6 | 7 | set(LIBRARY_OUTPUT_PATH bin/${CMAKE_BUILD_TYPE}) 8 | 9 | include_directories(${OpenCV_INCLUDE_DIRS}) 10 | include_directories(BEFORE SYSTEM ${webrtc_native_INCLUDE}) 11 | include_directories(../../opentera-webrtc-native-client/3rdParty/json/include) 12 | include_directories(../../opentera-webrtc-native-client/3rdParty/IXWebSocket) 13 | include_directories(../../opentera-webrtc-native-client/3rdParty/cpp-httplib) 14 | include_directories(../../opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include) 15 | 16 | add_executable(CppDataChannelClient main.cpp) 17 | 18 | target_link_libraries(CppDataChannelClient 19 | OpenteraWebrtcNativeClient 20 | ) 21 | 22 | if (NOT WIN32) 23 | target_link_libraries(CppDataChannelClient 24 | pthread 25 | ) 26 | endif() 27 | 28 | set_property(TARGET CppDataChannelClient PROPERTY CXX_STANDARD 17) 29 | -------------------------------------------------------------------------------- /examples/cpp-data-channel-client/README.md: -------------------------------------------------------------------------------- 1 | # cpp-data-channel-client 2 | 3 | This example shows how to use the C++ library to create a client that communicates with another one by a WebRTC data channel. This example should be used with [web-data-channel-client](../web-data-channel-client). 4 | 5 | ## How to use 6 | 7 | ```bash 8 | cd ../.. 9 | mkdir build 10 | cd build 11 | cmake .. 12 | cmake --build . --config Release|Debug 13 | 14 | cd bin/Release 15 | ./CppDataChannelClient 16 | ``` 17 | -------------------------------------------------------------------------------- /examples/cpp-video-stream-client/.gitignore: -------------------------------------------------------------------------------- 1 | cmake-build-debug 2 | cmake-build-release 3 | build 4 | .idea 5 | -------------------------------------------------------------------------------- /examples/cpp-video-stream-client/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14.0) 2 | 3 | include_directories(${CMAKE_CURRENT_BINARY_DIR}) 4 | 5 | project(CppVideoStreamClient) 6 | 7 | set(LIBRARY_OUTPUT_PATH bin/${CMAKE_BUILD_TYPE}) 8 | 9 | include_directories(${OpenCV_INCLUDE_DIRS}) 10 | include_directories(BEFORE SYSTEM ${webrtc_native_INCLUDE}) 11 | include_directories(../../opentera-webrtc-native-client/3rdParty/json/include) 12 | include_directories(../../opentera-webrtc-native-client/3rdParty/IXWebSocket) 13 | include_directories(../../opentera-webrtc-native-client/3rdParty/cpp-httplib) 14 | include_directories(../../opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include) 15 | 16 | add_executable(CppVideoStreamClient main.cpp) 17 | 18 | target_link_libraries(CppVideoStreamClient 19 | OpenteraWebrtcNativeClient 20 | opencv_videoio 21 | opencv_highgui 22 | ) 23 | 24 | if (NOT WIN32) 25 | target_link_libraries(CppVideoStreamClient 26 | pthread 27 | ) 28 | endif() 29 | 30 | if (NOT OPENTERA_WEBRTC_USE_SYSTEM_OPENCV) 31 | add_dependencies(CppVideoStreamClient opencv_highgui opencv_videoio) 32 | endif() 33 | 34 | set_property(TARGET CppVideoStreamClient PROPERTY CXX_STANDARD 17) 35 | -------------------------------------------------------------------------------- /examples/cpp-video-stream-client/README.md: -------------------------------------------------------------------------------- 1 | # cpp-video-stream-client 2 | 3 | This example shows how to use the C++ library to create a client that sends and receives a video stream and an audio stream. 4 | The video source is a video file and the audio source is a sin wave. 5 | This example should be used with [web-stream-client](../web-stream-client). 6 | 7 | ## How to use 8 | 9 | ```bash 10 | cd ../.. 11 | mkdir build 12 | cd build 13 | cmake .. 14 | cmake --build . --config Release|Debug 15 | 16 | cd bin/Release 17 | ./CppVideoStreamClient video_path 18 | ``` 19 | -------------------------------------------------------------------------------- /examples/python-data-channel-client/README.md: -------------------------------------------------------------------------------- 1 | # python-data-channel-client 2 | This example shows how to use the Python library to create a client that communicates with another one by a WebRTC data channel. This example should be used with [web-data-channel-client](../web-data-channel-client). 3 | 4 | ## How to use 5 | ```bash 6 | cd ../.. 7 | mkdir build 8 | cd build 9 | cmake .. 10 | cmake --build . --config Release|Debug 11 | cmake --install . 12 | 13 | cd ../examples/python-data-channel-client/ 14 | python3 python_data_channel_client.py 15 | ``` 16 | -------------------------------------------------------------------------------- /examples/python-stream-client/README.md: -------------------------------------------------------------------------------- 1 | # python-stream-client 2 | This example shows how to use the Python library to create a client that sends and receives a video stream and an audio stream. This example should be used with [web-stream-client](../web-stream-client). 3 | 4 | ## How to use 5 | ```bash 6 | cd ../.. 7 | mkdir build 8 | cd build 9 | cmake .. 10 | cmake --build . --config Release|Debug 11 | cmake --install . 12 | 13 | cd ../examples/python-stream-client/ 14 | python3 -m pip install -r requirements.txt 15 | python3 python_stream_client.py 16 | ``` 17 | -------------------------------------------------------------------------------- /examples/python-stream-client/frame.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/introlab/opentera-webrtc/458277e9c1d17e9e1e1e6fe15394dee7e1329aa3/examples/python-stream-client/frame.png -------------------------------------------------------------------------------- /examples/python-stream-client/requirements.txt: -------------------------------------------------------------------------------- 1 | numpy 2 | opencv-python 3 | -------------------------------------------------------------------------------- /examples/web-data-channel-client/.gitignore: -------------------------------------------------------------------------------- 1 | openteraWebrtcWebClient.js* 2 | -------------------------------------------------------------------------------- /examples/web-data-channel-client/README.md: -------------------------------------------------------------------------------- 1 | # web-data-channel-client 2 | 3 | This example shows how to use the JavaScript library to create a client that communicates with another one by a WebRTC data channel. 4 | 5 | ## How to use 6 | 7 | ```bash 8 | ./start_server.bash 9 | ``` 10 | 11 | Open the link in many browser tabs [http://localhost:8080/client.html](http://localhost:8080/client.html). 12 | -------------------------------------------------------------------------------- /examples/web-data-channel-client/client.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Web Data Channel Client 5 | 6 | 7 | 8 | 9 | 10 | 11 |

Web Data Channel Client

12 | 13 |

Name:

14 | 15 | 16 |

Password:

17 | 18 | 19 |

Signaling Server Connection:

20 | 21 | 22 | 23 |

Clients:

24 | 25 | 26 |

Call All:

27 | 28 | 29 | 30 | 31 |

Call One:

32 | 33 | 34 | 35 |

Messages:

36 | 37 |

38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /examples/web-data-channel-client/iceServers.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "urls": "stun:stun.l.google.com:19302" 4 | } 5 | ] 6 | -------------------------------------------------------------------------------- /examples/web-data-channel-client/start_server.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SCRIPT=`realpath $0` 4 | SCRIPT_PATH=`dirname $SCRIPT` 5 | 6 | cd $SCRIPT_PATH/../../opentera-webrtc-web-client 7 | npm install 8 | npm run build:umd 9 | 10 | cp $SCRIPT_PATH/../../opentera-webrtc-web-client/dist/openteraWebrtcWebClient.js* $SCRIPT_PATH 11 | 12 | cd $SCRIPT_PATH/../../signaling-server 13 | python3 opentera-signaling-server --port 8080 --password abc --ice_servers $SCRIPT_PATH/iceServers.json --static_folder $SCRIPT_PATH 14 | -------------------------------------------------------------------------------- /examples/web-stream-client/.gitignore: -------------------------------------------------------------------------------- 1 | openteraWebrtcWebClient.js* 2 | -------------------------------------------------------------------------------- /examples/web-stream-client/README.md: -------------------------------------------------------------------------------- 1 | # web-stream-client 2 | 3 | This example shows how to use the JavaScript library to create a client that sends and receives a video stream and an audio stream. 4 | 5 | ## How to use 6 | 7 | ```bash 8 | ./start_server.bash 9 | ``` 10 | 11 | Open the link in many browser tabs [http://localhost:8080/client.html](http://localhost:8080/client.html). 12 | -------------------------------------------------------------------------------- /examples/web-stream-client/client.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Stream Client 5 | 6 | 7 | 8 | 9 | 10 | 11 |

Stream Client

12 | 13 |

Local Stream

14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 |

Remove Stream

22 |

Name:

23 | 24 | 25 |

Password:

26 | 27 | 28 |

Signaling Server Connection:

29 | 30 | 31 | 32 |

Clients:

33 | 34 | 35 |

Call All:

36 | 37 | 38 | 39 | 40 |

Call One:

41 | 42 | 43 | 44 |
45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /examples/web-stream-client/iceServers.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "urls": "stun:stun.l.google.com:19302" 4 | } 5 | ] 6 | -------------------------------------------------------------------------------- /examples/web-stream-client/start_server.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SCRIPT=`realpath $0` 4 | SCRIPT_PATH=`dirname $SCRIPT` 5 | 6 | cd $SCRIPT_PATH/../../opentera-webrtc-web-client 7 | npm install 8 | npm run build:umd 9 | 10 | cp $SCRIPT_PATH/../../opentera-webrtc-web-client/dist/openteraWebrtcWebClient.js* $SCRIPT_PATH 11 | 12 | cd $SCRIPT_PATH/../../signaling-server 13 | python3 opentera-signaling-server --port 8080 --password abc --ice_servers $SCRIPT_PATH/iceServers.json --static_folder $SCRIPT_PATH 14 | -------------------------------------------------------------------------------- /examples/web-stream-data-channel-client/.gitignore: -------------------------------------------------------------------------------- 1 | openteraWebrtcWebClient.js* 2 | -------------------------------------------------------------------------------- /examples/web-stream-data-channel-client/README.md: -------------------------------------------------------------------------------- 1 | # web-stream-data-channel-client 2 | 3 | This example shows how to use the JavaScript library to create a client that sends and receives a video stream and an audio stream and communicates with another one by a WebRTC data channel. 4 | 5 | ## How to use 6 | 7 | ```bash 8 | ./start_server.bash 9 | ``` 10 | 11 | Open the link in many browser tabs [http://localhost:8080/client.html](http://localhost:8080/client.html). 12 | -------------------------------------------------------------------------------- /examples/web-stream-data-channel-client/client.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Stream Client 5 | 6 | 7 | 8 | 9 | 10 | 11 |

Stream Client

12 | 13 |

Local Stream

14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 |

Remove Stream and Messages

22 |

Name:

23 | 24 | 25 |

Password:

26 | 27 | 28 |

Signaling Server Connection:

29 | 30 | 31 | 32 |

Clients:

33 | 34 | 35 |

Call All:

36 | 37 | 38 | 39 | 40 |

Call One:

41 | 42 | 43 | 44 |

Messages:

45 | 46 |

47 | 48 | 49 |

Remote Stream:

50 |
51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /examples/web-stream-data-channel-client/iceServers.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "urls": "stun:stun.l.google.com:19302" 4 | } 5 | ] 6 | -------------------------------------------------------------------------------- /examples/web-stream-data-channel-client/start_server.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SCRIPT=`realpath $0` 4 | SCRIPT_PATH=`dirname $SCRIPT` 5 | 6 | cd $SCRIPT_PATH/../../opentera-webrtc-web-client 7 | npm install 8 | npm run build:umd 9 | 10 | cp $SCRIPT_PATH/../../opentera-webrtc-web-client/dist/openteraWebrtcWebClient.js* $SCRIPT_PATH 11 | 12 | cd $SCRIPT_PATH/../../signaling-server 13 | python3 opentera-signaling-server --port 8080 --password abc --ice_servers $SCRIPT_PATH/iceServers.json --static_folder $SCRIPT_PATH 14 | -------------------------------------------------------------------------------- /images/IntRoLab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/introlab/opentera-webrtc/458277e9c1d17e9e1e1e6fe15394dee7e1329aa3/images/IntRoLab.png -------------------------------------------------------------------------------- /opentera-webrtc-native-client/.gitignore: -------------------------------------------------------------------------------- 1 | cmake-build-debug 2 | cmake-build-release 3 | build 4 | .idea 5 | __pycache__ 6 | dist/ 7 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/3rdParty/.clang-format: -------------------------------------------------------------------------------- 1 | # LLVM 12 2 | --- 3 | DisableFormat: true 4 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/3rdParty/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | if (POLICY CMP0048) 2 | cmake_policy(SET CMP0048 NEW) 3 | endif (POLICY CMP0048) 4 | 5 | set (BUILD_SHARED_LIBS OFF) 6 | 7 | # webrtc_native must be first 8 | add_subdirectory(webrtc_native) 9 | 10 | add_subdirectory(pybind11) 11 | add_subdirectory(json) 12 | 13 | set(USE_ZLIB OFF) 14 | set(USE_TLS ON) 15 | set(OPENSSL_FOUND TRUE) 16 | set(OPENSSL_DEFINITIONS "") 17 | set(OPENSSL_INCLUDE_DIR ${boringssl_INCLUDE}) 18 | set(OPENSSL_LIBRARIES ${boringssl_LIBRARY}) 19 | add_subdirectory(IXWebSocket) 20 | set_property(TARGET ixwebsocket PROPERTY CXX_STANDARD 17) 21 | target_compile_options(ixwebsocket PRIVATE -w) 22 | 23 | if (OPENTERA_WEBRTC_ENABLE_TESTS) 24 | add_subdirectory(googletest) 25 | endif() 26 | 27 | if(NOT OPENTERA_WEBRTC_USE_SYSTEM_OPENCV) 28 | # Set OpenCV flags 29 | set(OPENCV_FORCE_3RDPARTY_BUILD ON) 30 | set(BUILD_SHARED_LIBS OFF) 31 | 32 | # Enable/Disable modules : 33 | set(BUILD_opencv_core ON) 34 | set(BUILD_opencv_imgproc ON) 35 | set(BUILD_opencv_calib3d OFF) 36 | set(BUILD_opencv_dnn OFF) 37 | set(BUILD_opencv_features2d OFF) 38 | set(BUILD_opencv_flann OFF) 39 | set(BUILD_opencv_gapi OFF) 40 | set(BUILD_opencv_highgui ON) 41 | set(BUILD_opencv_imgcodecs ON) 42 | set(BUILD_opencv_ml OFF) 43 | set(BUILD_opencv_objdetect OFF) 44 | set(BUILD_opencv_photo OFF) 45 | set(BUILD_opencv_python2 OFF) 46 | set(BUILD_opencv_python3 OFF) 47 | set(BUILD_opencv_stitching OFF) 48 | set(BUILD_opencv_ts OFF) 49 | set(BUILD_opencv_video OFF) 50 | set(BUILD_opencv_videoio ON) 51 | 52 | set(BUILD_JAVA OFF) 53 | set(BUILD_OBJC OFF) 54 | 55 | set(BUILD_OPENEXR OFF) 56 | set(WITH_OPENEXR OFF) 57 | 58 | # Configure opencv 59 | add_subdirectory(opencv) 60 | 61 | endif() 62 | 63 | install(DIRECTORY json/include DESTINATION include FILES_MATCHING PATTERN "*.hpp") 64 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/3rdParty/webrtc_native/.gitignore: -------------------------------------------------------------------------------- 1 | webrtc-native-build* 2 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14.0) 2 | 3 | 4 | if (OPENTERA_WEBRTC_USE_SYSTEM_OPENCV) 5 | if(OPENTERA_WEBRTC_ENABLE_EXAMPLES) 6 | set(_OpenCV_extra_modules_examples "highgui" "imgcodecs") 7 | else() 8 | set(_OpenCV_extra_modules_examples "") 9 | endif() 10 | 11 | find_package(OpenCV REQUIRED core imgproc ${_OpenCV_extra_modules_examples}) 12 | message(STATUS "OpenCV library status:") 13 | message(STATUS " config: ${OpenCV_DIR}") 14 | message(STATUS " version: ${OpenCV_VERSION}") 15 | message(STATUS " libraries: ${OpenCV_LIBS}") 16 | message(STATUS " include path: ${OpenCV_INCLUDE_DIRS}") 17 | 18 | unset(_OpenCV_extra_modules_examples) 19 | endif() 20 | 21 | project(opentera-webrtc-native-client) 22 | 23 | set(CMAKE_INSTALL_PREFIX ${PROJECT_SOURCE_DIR}/dist/${CMAKE_BUILD_TYPE}/opentera-webrtc-native-client-${OPENTERA_WEBRTC_NATIVE_CLIENT_VERSION}) 24 | message(STATUS "CMAKE_INSTALL_PREFIX : ${CMAKE_INSTALL_PREFIX}") 25 | 26 | set_property(GLOBAL PROPERTY USE_FOLDERS ON) 27 | 28 | function(assign_source_group) 29 | foreach (_source IN ITEMS ${ARGN}) 30 | if (IS_ABSOLUTE "${_source}") 31 | file(RELATIVE_PATH _source_rel "${CMAKE_CURRENT_SOURCE_DIR}" "${_source}") 32 | else () 33 | set(_source_rel "${_source}") 34 | endif () 35 | get_filename_component(_source_path "${_source_rel}" PATH) 36 | string(REPLACE "/" "\\" _source_path_msvc "${_source_path}") 37 | source_group("${_source_path_msvc}" FILES "${_source}") 38 | endforeach () 39 | endfunction(assign_source_group) 40 | 41 | add_subdirectory(3rdParty) 42 | 43 | # Looked up again in case 3rdParty changed it 44 | find_package(Python ${OPENTERA_WEBRTC_NATIVE_CLIENT_PYTHON_VERSION} EXACT COMPONENTS Interpreter Development REQUIRED) 45 | if (Python_FOUND) 46 | set(PYTHON3_EXECUTABLE ${Python_EXECUTABLE} CACHE INTERNAL "") 47 | else() 48 | message(FATAL_ERROR "Python3 is not found") 49 | endif() 50 | 51 | if (OPENTERA_WEBRTC_ENABLE_GSTREAMER) 52 | add_subdirectory(OpenteraWebrtcNativeGStreamer) 53 | endif() 54 | 55 | add_subdirectory(OpenteraWebrtcNativeClient) 56 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/README.md: -------------------------------------------------------------------------------- 1 | # OpenteraWebrtcNativeClient 2 | 3 | ## Initialize submodules 4 | 5 | ```bash 6 | git submodule update --init --recursive 7 | ``` 8 | 9 | webrtc native will be downloaded by CMake at the next step! 10 | 11 | ## Prepare build with cmake 12 | 13 | ```bash 14 | cd opentera-webrtc-native-client 15 | mkdir build && cd build 16 | cmake .. 17 | ``` 18 | 19 | ## Install dependencies 20 | 21 | ### Linux - AMD64 22 | 23 | ```bash 24 | sudo apt install libboost-all-dev 25 | sudo apt install python-is-python3 26 | ./3rdParty/webrtc_native/webrtc/src/build/install-build-deps.sh 27 | ``` 28 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/Codecs/VideoCodecFactories.h: -------------------------------------------------------------------------------- 1 | #ifndef OPENTERA_WEBRTC_NATIVE_CLIENT_CODECS_VIDEO_CODEC_H 2 | #define OPENTERA_WEBRTC_NATIVE_CLIENT_CODECS_VIDEO_CODEC_H 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | namespace opentera 11 | { 12 | class ForcedCodecVideoDecoderFactory : public webrtc::VideoDecoderFactory 13 | { 14 | std::unique_ptr m_factory; 15 | std::unordered_set m_forcedCodecs; 16 | 17 | public: 18 | ForcedCodecVideoDecoderFactory( 19 | std::unique_ptr factory, 20 | std::unordered_set forcedCodecs); 21 | ~ForcedCodecVideoDecoderFactory() override = default; 22 | 23 | DECLARE_NOT_COPYABLE(ForcedCodecVideoDecoderFactory); 24 | DECLARE_NOT_MOVABLE(ForcedCodecVideoDecoderFactory); 25 | 26 | std::vector GetSupportedFormats() const override; 27 | CodecSupport QueryCodecSupport(const webrtc::SdpVideoFormat& format, bool referenceScaling) const override; 28 | std::unique_ptr Create( 29 | const webrtc::Environment& env, 30 | const webrtc::SdpVideoFormat& format) override; 31 | }; 32 | 33 | class ForcedCodecVideoEncoderFactory : public webrtc::VideoEncoderFactory 34 | { 35 | std::unique_ptr m_factory; 36 | std::unordered_set m_forcedCodecs; 37 | 38 | public: 39 | ForcedCodecVideoEncoderFactory( 40 | std::unique_ptr factory, 41 | std::unordered_set forcedCodecs); 42 | ~ForcedCodecVideoEncoderFactory() override = default; 43 | 44 | DECLARE_NOT_COPYABLE(ForcedCodecVideoEncoderFactory); 45 | DECLARE_NOT_MOVABLE(ForcedCodecVideoEncoderFactory); 46 | 47 | std::vector GetSupportedFormats() const override; 48 | 49 | CodecSupport QueryCodecSupport( 50 | const webrtc::SdpVideoFormat& format, 51 | absl::optional scalabilityMode) const override; 52 | 53 | // Creates a VideoEncoder for the specified format. 54 | std::unique_ptr Create( 55 | const webrtc::Environment& env, 56 | const webrtc::SdpVideoFormat& format) override; 57 | }; 58 | 59 | std::unique_ptr 60 | createVideoDecoderFactory(const VideoStreamConfiguration& configuration); 61 | std::unique_ptr 62 | createVideoEncoderFactory(const VideoStreamConfiguration& configuration); 63 | } 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/Configurations/VideoSourceConfiguration.h: -------------------------------------------------------------------------------- 1 | #ifndef OPENTERA_WEBRTC_NATIVE_CLIENT_CONFIGURATIONS_VIDEO_SOURCE_CONFIGURATION_H 2 | #define OPENTERA_WEBRTC_NATIVE_CLIENT_CONFIGURATIONS_VIDEO_SOURCE_CONFIGURATION_H 3 | 4 | namespace opentera 5 | { 6 | /** 7 | * @brief Represents a configuration of a video source that can be added to a WebRTC call. 8 | */ 9 | class VideoSourceConfiguration 10 | { 11 | bool m_needsDenoising; 12 | bool m_isScreencast; 13 | 14 | VideoSourceConfiguration(bool needsDenoising, bool isScreencast); 15 | 16 | public: 17 | VideoSourceConfiguration(const VideoSourceConfiguration& other) = default; 18 | VideoSourceConfiguration(VideoSourceConfiguration&& other) = default; 19 | virtual ~VideoSourceConfiguration() = default; 20 | 21 | static VideoSourceConfiguration create(bool needsDenoising, bool isScreencast); 22 | 23 | [[nodiscard]] bool needsDenoising() const; 24 | [[nodiscard]] bool isScreencast() const; 25 | 26 | VideoSourceConfiguration& operator=(const VideoSourceConfiguration& other) = default; 27 | VideoSourceConfiguration& operator=(VideoSourceConfiguration&& other) = default; 28 | }; 29 | 30 | /** 31 | * @brief Creates a video source configuration with the specified values. 32 | * 33 | * @param needsDenoising Indicates if this source needs denoising 34 | * @param isScreencast Indicates if this source is screencast 35 | * @return A video source configuration with the specified values 36 | */ 37 | inline VideoSourceConfiguration VideoSourceConfiguration::create(bool needsDenoising, bool isScreencast) 38 | { 39 | return {needsDenoising, isScreencast}; 40 | } 41 | 42 | /** 43 | * @brief Indicates if this source needs denoising. 44 | * @return true if this source needs denoising 45 | */ 46 | inline bool VideoSourceConfiguration::needsDenoising() const { return m_needsDenoising; } 47 | 48 | /** 49 | * @brief Indicates if this source is screencast. 50 | * @return true if this source is a screencast 51 | */ 52 | inline bool VideoSourceConfiguration::isScreencast() const { return m_isScreencast; } 53 | } 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/Configurations/WebrtcConfiguration.h: -------------------------------------------------------------------------------- 1 | #ifndef OPENTERA_WEBRTC_NATIVE_CLIENT_CONFIGURATIONS_WEBRTC_CONFIGURATION_H 2 | #define OPENTERA_WEBRTC_NATIVE_CLIENT_CONFIGURATIONS_WEBRTC_CONFIGURATION_H 3 | 4 | #include 5 | 6 | #include 7 | 8 | namespace opentera 9 | { 10 | /** 11 | * @brief Represents a WebRTC peer connection configuration. 12 | */ 13 | class WebrtcConfiguration 14 | { 15 | std::vector m_iceServers; 16 | 17 | explicit WebrtcConfiguration(std::vector&& iceServers); 18 | 19 | public: 20 | WebrtcConfiguration(const WebrtcConfiguration& other) = default; 21 | WebrtcConfiguration(WebrtcConfiguration&& other) = default; 22 | virtual ~WebrtcConfiguration() = default; 23 | 24 | static WebrtcConfiguration create(); 25 | static WebrtcConfiguration create(std::vector iceServers); 26 | 27 | [[nodiscard]] const std::vector& iceServers() const; 28 | 29 | explicit operator webrtc::PeerConnectionInterface::RTCConfiguration() const; 30 | 31 | WebrtcConfiguration& operator=(const WebrtcConfiguration& other) = default; 32 | WebrtcConfiguration& operator=(WebrtcConfiguration&& other) = default; 33 | }; 34 | 35 | /** 36 | * @brief Creates a WebRTC peer connection configuration with default values. 37 | * @return A WebRTC peer connection configuration with default values 38 | */ 39 | inline WebrtcConfiguration WebrtcConfiguration::create() { return WebrtcConfiguration({}); } 40 | 41 | /** 42 | * @brief Creates a WebRTC peer connection configuration with the specified value. 43 | * @param iceServers The ice servers 44 | * @return A WebRTC peer connection configuration with the specified value 45 | */ 46 | inline WebrtcConfiguration WebrtcConfiguration::create(std::vector iceServers) 47 | { 48 | return WebrtcConfiguration(std::move(iceServers)); 49 | } 50 | 51 | /** 52 | * Returns the ice servers. 53 | * @return The ice servers 54 | */ 55 | inline const std::vector& WebrtcConfiguration::iceServers() const { return m_iceServers; } 56 | } 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/Handlers/DataChannelPeerConnectionHandler.h: -------------------------------------------------------------------------------- 1 | #ifndef OPENTERA_WEBRTC_NATIVE_CLIENT_UTILS_FUNCTIONAL_DATA_CHANNEL_OBSERVER_H 2 | #define OPENTERA_WEBRTC_NATIVE_CLIENT_UTILS_FUNCTIONAL_DATA_CHANNEL_OBSERVER_H 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | 11 | namespace opentera 12 | { 13 | class DataChannelPeerConnectionHandler : public PeerConnectionHandler, public webrtc::DataChannelObserver 14 | { 15 | DataChannelConfiguration m_dataChannelConfiguration; 16 | 17 | std::function m_onDataChannelOpen; 18 | std::function m_onDataChannelClosed; 19 | std::function m_onDataChannelError; 20 | std::function m_onDataChannelMessageBinary; 21 | std::function m_onDataChannelMessageString; 22 | 23 | rtc::scoped_refptr m_dataChannel; 24 | 25 | bool m_onDataChannelClosedCalled; 26 | 27 | public: 28 | DataChannelPeerConnectionHandler( 29 | std::string id, 30 | Client peerClient, 31 | bool isCaller, 32 | SignalingClient& m_signalingClient, 33 | std::function onError, 34 | std::function onClientConnected, 35 | std::function onClientDisconnected, 36 | std::function onClientConnectionFailed, 37 | DataChannelConfiguration dataChannelConfiguration, 38 | std::function onDataChannelOpen, 39 | std::function onDataChannelClosed, 40 | std::function onDataChannelError, 41 | std::function onDataChannelMessageBinary, 42 | std::function onDataChannelMessageString); 43 | 44 | ~DataChannelPeerConnectionHandler() override; 45 | 46 | void setPeerConnection(const rtc::scoped_refptr& peerConnection) override; 47 | 48 | bool send(const webrtc::DataBuffer& buffer); 49 | 50 | // Observer methods 51 | void OnDataChannel(rtc::scoped_refptr dataChannel) override; 52 | 53 | void OnStateChange() override; 54 | void OnMessage(const webrtc::DataBuffer& buffer) override; 55 | 56 | protected: 57 | void createAnswer() override; 58 | }; 59 | } 60 | 61 | #endif 62 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/Signaling/WebSocketSignalingClient.h: -------------------------------------------------------------------------------- 1 | #ifndef OPENTERA_WEBRTC_NATIVE_CLIENT_SIGNALING_SIO_SIGNALING_CLIENT_H 2 | #define OPENTERA_WEBRTC_NATIVE_CLIENT_SIGNALING_SIO_SIGNALING_CLIENT_H 3 | 4 | #include 5 | 6 | #include 7 | 8 | namespace opentera 9 | { 10 | class WebSocketSignalingClient : public SignalingClient 11 | { 12 | ix::WebSocket m_ws; 13 | std::string m_sessionId; 14 | 15 | public: 16 | WebSocketSignalingClient(SignalingServerConfiguration configuration); 17 | ~WebSocketSignalingClient() override; 18 | 19 | DECLARE_NOT_COPYABLE(WebSocketSignalingClient); 20 | DECLARE_NOT_MOVABLE(WebSocketSignalingClient); 21 | 22 | void setTlsVerificationEnabled(bool isEnabled) override; 23 | 24 | bool isConnected() override; 25 | std::string sessionId() override; 26 | 27 | void connect() override; 28 | void close() override; 29 | void closeSync() override; 30 | 31 | void callAll() override; 32 | void callIds(const std::vector& ids) override; 33 | void closeAllRoomPeerConnections() override; 34 | 35 | void callPeer(const std::string& toId, const std::string& sdp) override; 36 | void makePeerCallAnswer(const std::string& toId, const std::string& sdp) override; 37 | void rejectCall(const std::string& toId) override; 38 | void sendIceCandidate( 39 | const std::string& sdpMid, 40 | int sdpMLineIndex, 41 | const std::string& candidate, 42 | const std::string& toId) override; 43 | 44 | private: 45 | void connectWsEvents(); 46 | 47 | void onWsOpenEvent(); 48 | void onWsCloseEvent(); 49 | void onWsErrorEvent(const std::string& error); 50 | void onWsMessage(const std::string& message); 51 | 52 | void onJoinRoomAnswerEvent(const nlohmann::json& data); 53 | 54 | void onRoomClientsEvent(const nlohmann::json& data); 55 | 56 | void onMakePeerCallEvent(const nlohmann::json& data); 57 | void onPeerCallReceivedEvent(const nlohmann::json& data); 58 | void onPeerCallAnswerReceivedEvent(const nlohmann::json& data); 59 | void onCloseAllPeerConnectionsRequestReceivedEvent(); 60 | void onIceCandidateReceivedEvent(const nlohmann::json& data); 61 | }; 62 | } 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/Sinks/AudioSink.h: -------------------------------------------------------------------------------- 1 | #ifndef OPENTERA_WEBRTC_NATIVE_CLIENT_AUDIO_SINK_H 2 | #define OPENTERA_WEBRTC_NATIVE_CLIENT_AUDIO_SINK_H 3 | 4 | #include 5 | 6 | namespace opentera 7 | { 8 | using AudioSinkCallback = std::function< 9 | void(const void* audioData, int bitsPerSample, int sampleRate, size_t numberOfChannels, size_t numberOfFrames)>; 10 | 11 | /** 12 | * @brief Class that sinks audio data from the WebRTC transport layer and feeds 13 | * it to the provided callback. 14 | */ 15 | class AudioSink : public webrtc::AudioTrackSinkInterface 16 | { 17 | AudioSinkCallback m_onAudioFrameReceived; 18 | 19 | public: 20 | explicit AudioSink(AudioSinkCallback onAudioFrameReceived); 21 | 22 | void OnData( 23 | const void* audioData, 24 | int bitsPerSample, 25 | int sampleRate, 26 | size_t numberOfChannels, 27 | size_t numberOfFrames) override; 28 | }; 29 | } 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/Sinks/EncodedVideoSink.h: -------------------------------------------------------------------------------- 1 | #ifndef OPENTERA_WEBRTC_NATIVE_CLIENT_ENCODED_VIDEO_SINK_H 2 | #define OPENTERA_WEBRTC_NATIVE_CLIENT_ENCODED_VIDEO_SINK_H 3 | 4 | #include 5 | #include 6 | 7 | namespace opentera 8 | { 9 | enum class VideoCodecType 10 | { 11 | Generic = 0, 12 | VP8, 13 | VP9, 14 | AV1, 15 | H264, 16 | Multiplex, 17 | }; 18 | 19 | using EncodedVideoSinkCallback = std::function; 27 | 28 | /** 29 | * @brief Class that sinks frame from a webrtc stream 30 | */ 31 | class EncodedVideoSink : public rtc::VideoSinkInterface 32 | { 33 | EncodedVideoSinkCallback m_onFrameReceived; 34 | 35 | public: 36 | explicit EncodedVideoSink(EncodedVideoSinkCallback onFrameReceived); 37 | 38 | void OnFrame(const webrtc::RecordableEncodedFrame& frame) override; 39 | }; 40 | } 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/Sinks/VideoSink.h: -------------------------------------------------------------------------------- 1 | #ifndef OPENTERA_WEBRTC_NATIVE_CLIENT_VIDEO_SINK_H 2 | #define OPENTERA_WEBRTC_NATIVE_CLIENT_VIDEO_SINK_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace opentera 10 | { 11 | 12 | using VideoSinkCallback = std::function; 13 | 14 | /** 15 | * @brief Class that sinks frame from a webrtc stream 16 | */ 17 | class VideoSink : public rtc::VideoSinkInterface 18 | { 19 | VideoSinkCallback m_onFrameReceived; 20 | rtc::VideoSinkWants m_wants; 21 | cv::Mat m_bgrImg; 22 | cv::Mat m_bgrRotatedImg; 23 | 24 | public: 25 | explicit VideoSink(VideoSinkCallback onFrameReceived); 26 | 27 | void OnFrame(const webrtc::VideoFrame& frame) override; 28 | [[nodiscard]] rtc::VideoSinkWants wants() const; 29 | }; 30 | 31 | /** 32 | * @brief get frame requirements for this sink 33 | * @return frame requirements for this sink 34 | */ 35 | inline rtc::VideoSinkWants VideoSink::wants() const { return m_wants; } 36 | 37 | } 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/Sources/AudioSource.h: -------------------------------------------------------------------------------- 1 | #ifndef OPENTERA_WEBRTC_NATIVE_CLIENT_SOURCES_AUDIO_SOURCE_H 2 | #define OPENTERA_WEBRTC_NATIVE_CLIENT_SOURCES_AUDIO_SOURCE_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | namespace opentera 16 | { 17 | 18 | /** 19 | * @brief Represents an audio source that can be added to a WebRTC call. 20 | * 21 | * Pass a shared_ptr to an instance of this to the StreamClient and call 22 | * sendFrame for each of your audio frame. 23 | */ 24 | class AudioSource : public webrtc::Notifier 25 | { 26 | AudioSourceConfiguration m_configuration; 27 | int m_bitsPerSample; 28 | int m_sampleRate; 29 | size_t m_numberOfChannels; 30 | size_t m_bytesPerFrame; 31 | 32 | size_t m_dataIndex; 33 | std::vector m_data; // 10 ms audio frame 34 | size_t m_dataNumberOfFrames; 35 | 36 | std::mutex m_audioDeviceModuleMutex; 37 | rtc::scoped_refptr m_audioDeviceModule; 38 | 39 | public: 40 | AudioSource(AudioSourceConfiguration configuration, int bitsPerSample, int sampleRate, size_t numberOfChannels); 41 | 42 | DECLARE_NOT_COPYABLE(AudioSource); 43 | DECLARE_NOT_MOVABLE(AudioSource); 44 | 45 | void AddSink(webrtc::AudioTrackSinkInterface* sink) override; 46 | void RemoveSink(webrtc::AudioTrackSinkInterface* sink) override; 47 | 48 | bool remote() const override; 49 | SourceState state() const override; 50 | const cricket::AudioOptions options() const override; 51 | 52 | AudioSourceConfiguration configuration() const; 53 | size_t bytesPerSample() const; 54 | size_t bytesPerFrame() const; 55 | 56 | void setAudioDeviceModule(const rtc::scoped_refptr& audioDeviceModule); 57 | void sendFrame(const void* audioData, size_t numberOfFrames); 58 | void sendFrame(const void* audioData, size_t numberOfFrames, bool isTyping); 59 | 60 | // Methods to fake a ref counted object, so the Python binding is easier to 61 | // make because we can use a shared_ptr 62 | void AddRef() const override; 63 | rtc::RefCountReleaseStatus Release() const override; 64 | }; 65 | 66 | /** 67 | * @return The audio source configuration 68 | */ 69 | inline AudioSourceConfiguration AudioSource::configuration() const { return m_configuration; } 70 | 71 | /** 72 | * Send an audio frame 73 | * @param audioData The audio data 74 | * @param numberOfFrames The number of frames 75 | */ 76 | inline void AudioSource::sendFrame(const void* audioData, size_t numberOfFrames) 77 | { 78 | sendFrame(audioData, numberOfFrames, false); 79 | } 80 | } 81 | 82 | #endif 83 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/Sources/VideoSource.h: -------------------------------------------------------------------------------- 1 | #ifndef OPENTERA_WEBRTC_NATIVE_CLIENT_SOURCES_VIDEO_SOURCE_H 2 | #define OPENTERA_WEBRTC_NATIVE_CLIENT_SOURCES_VIDEO_SOURCE_H 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | namespace opentera 12 | { 13 | 14 | /** 15 | * @brief Represents a video source that can be added to a WebRTC call. 16 | * 17 | * Pass a shared_ptr to an instance of this to the StreamClient and call 18 | * sendFrame for each of your frame. 19 | */ 20 | class VideoSource : public rtc::AdaptedVideoTrackSource 21 | { 22 | VideoSourceConfiguration m_configuration; 23 | cv::Mat m_yuvImg; 24 | cv::Mat m_resizedImg; 25 | 26 | public: 27 | explicit VideoSource(VideoSourceConfiguration configuration); 28 | ~VideoSource() override = default; 29 | 30 | DECLARE_NOT_COPYABLE(VideoSource); 31 | DECLARE_NOT_MOVABLE(VideoSource); 32 | 33 | void sendFrame(const cv::Mat& bgrImg, int64_t timestampUs); 34 | 35 | bool is_screencast() const override; 36 | absl::optional needs_denoising() const override; 37 | bool remote() const override; 38 | webrtc::MediaSourceInterface::SourceState state() const override; 39 | 40 | // Methods to fake a ref counted object, so the Python binding is easier to 41 | // make because we can use a shared_ptr 42 | void AddRef() const override; 43 | rtc::RefCountReleaseStatus Release() const override; 44 | }; 45 | 46 | /** 47 | * @brief Indicates if this source is screencast. 48 | * @return true if this source is a screencast 49 | */ 50 | inline bool VideoSource::is_screencast() const { return m_configuration.isScreencast(); } 51 | 52 | /** 53 | * @brief Indicates if this source needs denoising. 54 | * @return true if this source needs denoising 55 | */ 56 | inline absl::optional VideoSource::needs_denoising() const { return m_configuration.needsDenoising(); } 57 | 58 | /** 59 | * @brief Indicates if this source is remote. 60 | * @return Always false, the source is local 61 | */ 62 | inline bool VideoSource::remote() const { return false; } 63 | 64 | /** 65 | * @brief Indicates if this source is live. 66 | * @return Always kLive, the source is live 67 | */ 68 | inline webrtc::MediaSourceInterface::SourceState VideoSource::state() const 69 | { 70 | return webrtc::MediaSourceInterface::kLive; 71 | } 72 | } 73 | 74 | #endif 75 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/Utils/ClassMacro.h: -------------------------------------------------------------------------------- 1 | #ifndef OPENTERA_WEBRTC_NATIVE_CLIENT_UTILS_CLASS_MACRO_H 2 | #define OPENTERA_WEBRTC_NATIVE_CLIENT_UTILS_CLASS_MACRO_H 3 | 4 | #define DECLARE_NOT_COPYABLE(className) \ 5 | className(const className&) = delete; \ 6 | className& operator=(const className&) = delete 7 | 8 | #define DECLARE_NOT_MOVABLE(className) \ 9 | className(className&&) = delete; \ 10 | className& operator=(className&&) = delete 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/Utils/FunctionTask.h: -------------------------------------------------------------------------------- 1 | #ifndef OPENTERA_WEBRTC_NATIVE_CLIENT_UTILS_QUEUED_TASK_UTILS_H 2 | #define OPENTERA_WEBRTC_NATIVE_CLIENT_UTILS_QUEUED_TASK_UTILS_H 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | namespace opentera 10 | { 11 | template 12 | using enable_if_void_result_t = std::enable_if_t>::value, void>; 13 | 14 | template 15 | using enable_if_not_void_result_t = 16 | std::enable_if_t>::value, std::invoke_result_t>; 17 | 18 | template 19 | enable_if_void_result_t callSync(rtc::Thread* thread, F&& function) 20 | { 21 | if (thread->IsCurrent()) 22 | { 23 | return function(); 24 | } 25 | else 26 | { 27 | rtc::Event event; 28 | thread->PostTask( 29 | [&, function = std::forward(function)]() 30 | { 31 | function(); 32 | event.Set(); 33 | }); 34 | event.Wait(rtc::Event::kForever); 35 | } 36 | } 37 | 38 | template 39 | enable_if_not_void_result_t callSync(rtc::Thread* thread, F&& function) 40 | { 41 | if (thread->IsCurrent()) 42 | { 43 | return function(); 44 | } 45 | else 46 | { 47 | rtc::Event event; 48 | std::invoke_result_t returnedValue; 49 | thread->PostTask( 50 | [&, function = std::forward(function)]() 51 | { 52 | returnedValue = std::move(function()); 53 | event.Set(); 54 | }); 55 | event.Wait(rtc::Event::kForever); 56 | return returnedValue; 57 | } 58 | } 59 | 60 | template 61 | inline void callAsync(rtc::Thread* thread, F&& function) 62 | { 63 | thread->PostTask([function = std::forward(function)]() { function(); }); 64 | } 65 | } 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/Utils/Http.h: -------------------------------------------------------------------------------- 1 | #ifndef OPENTERA_WEBRTC_NATIVE_CLIENT_UTILS_HTTP_H 2 | #define OPENTERA_WEBRTC_NATIVE_CLIENT_UTILS_HTTP_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace opentera 10 | { 11 | class Http 12 | { 13 | public: 14 | static bool 15 | get(const std::string& url, 16 | std::string& response, 17 | std::multimap headers, 18 | bool verifyCertificate = true); 19 | static bool splitUrl(const std::string& url, std::string& host, std::string& target); 20 | }; 21 | } 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/Utils/IceServer.h: -------------------------------------------------------------------------------- 1 | #ifndef OPENTERA_WEBRTC_NATIVE_CLIENT_UTILS_ICE_SERVER_H 2 | #define OPENTERA_WEBRTC_NATIVE_CLIENT_UTILS_ICE_SERVER_H 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | namespace opentera 10 | { 11 | /** 12 | * @brief Represents an ice server configuration. 13 | */ 14 | class IceServer 15 | { 16 | std::vector m_urls; 17 | std::string m_username; 18 | std::string m_credential; 19 | 20 | public: 21 | explicit IceServer(std::string url); 22 | IceServer(std::string url, std::string username, std::string credential); 23 | explicit IceServer(std::vector urls); 24 | IceServer(std::vector urls, std::string username, std::string credential); 25 | virtual ~IceServer() = default; 26 | 27 | const std::vector& urls() const; 28 | const std::string& username() const; 29 | const std::string& credential() const; 30 | 31 | explicit operator webrtc::PeerConnectionInterface::IceServer() const; 32 | 33 | static bool fetchFromServer( 34 | const std::string& url, 35 | const std::string& password, 36 | std::vector& iceServers, 37 | bool verifyCertificate = true); 38 | static bool fromJson(const std::string& json, std::vector& iceServers); 39 | }; 40 | 41 | /** 42 | * @brief Returns the ice server urls. 43 | * @return The ice server urls 44 | */ 45 | inline const std::vector& IceServer::urls() const { return m_urls; } 46 | 47 | /** 48 | * @brief Returns the ice server username. 49 | * @return The ice server username 50 | */ 51 | inline const std::string& IceServer::username() const { return m_username; } 52 | 53 | /** 54 | * @brief Returns the ice server credential. 55 | * @return The ice server credential 56 | */ 57 | inline const std::string& IceServer::credential() const { return m_credential; } 58 | 59 | inline IceServer::operator webrtc::PeerConnectionInterface::IceServer() const 60 | { 61 | webrtc::PeerConnectionInterface::IceServer iceServer; 62 | iceServer.urls = m_urls; 63 | iceServer.username = m_username; 64 | iceServer.password = m_credential; 65 | return iceServer; 66 | } 67 | } 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/Utils/thread.h: -------------------------------------------------------------------------------- 1 | #ifndef OPENTERA_WEBRTC_NATIVE_CLIENT_UTILS_THREAD_H 2 | #define OPENTERA_WEBRTC_NATIVE_CLIENT_UTILS_THREAD_H 3 | 4 | #include 5 | 6 | #if defined(WIN32) || defined(_WIN32) 7 | 8 | enum class ThreadPriority : int 9 | { 10 | Normal = 0x00000020, 11 | RealTime = 0x00000100, 12 | }; 13 | 14 | #elif defined(UNIX) || defined(__unix__) || defined(LINUX) || defined(__linux__) || defined(__APPLE__) 15 | 16 | enum class ThreadPriority : int 17 | { 18 | Normal, 19 | RealTime, 20 | }; 21 | 22 | #else 23 | 24 | #error "The OS is not supported." 25 | 26 | #endif 27 | 28 | bool setThreadPriority(std::thread& thread, ThreadPriority priority); 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/version.h: -------------------------------------------------------------------------------- 1 | #ifndef OPENTERA_WEBRTC_NATIVE_CLIENT_VERSION_H 2 | #define OPENTERA_WEBRTC_NATIVE_CLIENT_VERSION_H 3 | 4 | #include 5 | 6 | namespace opentera 7 | { 8 | std::string getVersion(); 9 | } 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14.0) 2 | 3 | project(opentera_webrtc_native_client) 4 | 5 | set(LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bin) 6 | 7 | include_directories(../../3rdParty/pybind11/include) 8 | include_directories(../include) 9 | include_directories(include) 10 | 11 | file(GLOB_RECURSE 12 | source_files 13 | src/* 14 | include/* 15 | ) 16 | 17 | pybind11_add_module(_opentera_webrtc_native_client 18 | MODULE 19 | ${source_files} 20 | ) 21 | 22 | target_link_libraries(_opentera_webrtc_native_client PRIVATE 23 | OpenteraWebrtcNativeClient 24 | ${webrtc_native_LIBRARY} 25 | ${PYTHON_LIBRARIES} 26 | ) 27 | 28 | set_property(TARGET _opentera_webrtc_native_client PROPERTY CXX_STANDARD 17) 29 | 30 | assign_source_group(${source_files}) 31 | 32 | add_subdirectory(package) 33 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/include/OpenteraWebrtcNativeClientPython/Configurations/AudioSourceConfigurationPython.h: -------------------------------------------------------------------------------- 1 | #ifndef OPENTERA_WEBRTC_NATIVE_CLIENT_PYTHON_CONFIGURATIONS_AUDIO_SOURCE_CONFIGURATION_PYTHON_H 2 | #define OPENTERA_WEBRTC_NATIVE_CLIENT_PYTHON_CONFIGURATIONS_AUDIO_SOURCE_CONFIGURATION_PYTHON_H 3 | 4 | #include 5 | 6 | namespace opentera 7 | { 8 | PYBIND11_EXPORT void initAudioSourceConfigurationPython(pybind11::module& m); 9 | } 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/include/OpenteraWebrtcNativeClientPython/Configurations/DataChannelConfigurationPython.h: -------------------------------------------------------------------------------- 1 | #ifndef OPENTERA_WEBRTC_NATIVE_CLIENT_PYTHON_CONFIGURATIONS_DATA_CHANNEL_CONFIGURATION_PYTHON_H 2 | #define OPENTERA_WEBRTC_NATIVE_CLIENT_PYTHON_CONFIGURATIONS_DATA_CHANNEL_CONFIGURATION_PYTHON_H 3 | 4 | #include 5 | 6 | namespace opentera 7 | { 8 | PYBIND11_EXPORT void initDataChannelConfigurationPython(pybind11::module& m); 9 | } 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/include/OpenteraWebrtcNativeClientPython/Configurations/SignalingServerConfigurationPython.h: -------------------------------------------------------------------------------- 1 | #ifndef OPENTERA_WEBRTC_NATIVE_CLIENT_PYTHON_CONFIGURATIONS_SIGNALING_SERVER_CONFIGURATION_PYTHON_H 2 | #define OPENTERA_WEBRTC_NATIVE_CLIENT_PYTHON_CONFIGURATIONS_SIGNALING_SERVER_CONFIGURATION_PYTHON_H 3 | 4 | #include 5 | 6 | namespace opentera 7 | { 8 | PYBIND11_EXPORT void initSignalingServerConfigurationPython(pybind11::module& m); 9 | } 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/include/OpenteraWebrtcNativeClientPython/Configurations/VideoSourceConfigurationPython.h: -------------------------------------------------------------------------------- 1 | #ifndef OPENTERA_WEBRTC_NATIVE_CLIENT_PYTHON_CONFIGURATIONS_VIDEO_SOURCE_CONFIGURATION_PYTHON_H 2 | #define OPENTERA_WEBRTC_NATIVE_CLIENT_PYTHON_CONFIGURATIONS_VIDEO_SOURCE_CONFIGURATION_PYTHON_H 3 | 4 | #include 5 | 6 | namespace opentera 7 | { 8 | PYBIND11_EXPORT void initVideoSourceConfigurationPython(pybind11::module& m); 9 | } 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/include/OpenteraWebrtcNativeClientPython/Configurations/VideoStreamConfigurationPython.h: -------------------------------------------------------------------------------- 1 | #ifndef OPENTERA_WEBRTC_NATIVE_CLIENT_PYTHON_CONFIGURATIONS_VIDEO_STREAM_CONFIGURATION_PYTHON_H 2 | #define OPENTERA_WEBRTC_NATIVE_CLIENT_PYTHON_CONFIGURATIONS_VIDEO_STREAM_CONFIGURATION_PYTHON_H 3 | 4 | #include 5 | 6 | namespace opentera 7 | { 8 | PYBIND11_EXPORT void initVideoStreamConfigurationPython(pybind11::module& m); 9 | } 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/include/OpenteraWebrtcNativeClientPython/Configurations/WebrtcConfigurationPython.h: -------------------------------------------------------------------------------- 1 | #ifndef OPENTERA_WEBRTC_NATIVE_CLIENT_PYTHON_CONFIGURATIONS_WEBRTC_CONFIGURATION_PYTHON_H 2 | #define OPENTERA_WEBRTC_NATIVE_CLIENT_PYTHON_CONFIGURATIONS_WEBRTC_CONFIGURATION_PYTHON_H 3 | 4 | #include 5 | 6 | namespace opentera 7 | { 8 | PYBIND11_EXPORT void initWebrtcConfigurationPython(pybind11::module& m); 9 | } 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/include/OpenteraWebrtcNativeClientPython/DataChannelClientPython.h: -------------------------------------------------------------------------------- 1 | #ifndef OPENTERA_WEBRTC_NATIVE_CLIENT_PYTHON_DATA_CHANNEL_CLIENT_PYTHON_H 2 | #define OPENTERA_WEBRTC_NATIVE_CLIENT_PYTHON_DATA_CHANNEL_CLIENT_PYTHON_H 3 | 4 | #include 5 | 6 | namespace opentera 7 | { 8 | PYBIND11_EXPORT void initDataChannelClientPython(pybind11::module& m); 9 | } 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/include/OpenteraWebrtcNativeClientPython/Json.h: -------------------------------------------------------------------------------- 1 | #ifndef OPENTERA_WEBRTC_NATIVE_CLIENT_PYTHON_SIO_MESSAGE_H 2 | #define OPENTERA_WEBRTC_NATIVE_CLIENT_PYTHON_SIO_MESSAGE_H 3 | 4 | #include 5 | 6 | #include 7 | 8 | namespace opentera 9 | { 10 | PYBIND11_EXPORT nlohmann::json pyObjectToJson(const pybind11::object& message); 11 | PYBIND11_EXPORT pybind11::object jsonToPyObject(const nlohmann::json& json); 12 | } 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/include/OpenteraWebrtcNativeClientPython/PyBindUtils.h: -------------------------------------------------------------------------------- 1 | #ifndef OPENTERA_WEBRTC_NATIVE_CLIENT_PYTHON_PY_BIND_UTILS_H 2 | #define OPENTERA_WEBRTC_NATIVE_CLIENT_PYTHON_PY_BIND_UTILS_H 3 | 4 | #include 5 | 6 | #include 7 | 8 | template 9 | struct GilScopedRelease 10 | { 11 | template 12 | static pybind11::cpp_function guard(const F& f) 13 | { 14 | return pybind11::cpp_function( 15 | pybind11::method_adaptor(f), 16 | pybind11::call_guard()); 17 | } 18 | }; 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/include/OpenteraWebrtcNativeClientPython/Sources/AudioSourcePython.h: -------------------------------------------------------------------------------- 1 | #ifndef OPENTERA_WEBRTC_NATIVE_CLIENT_PYTHON_SOURCES_AUDIO_SOURCE_PYTHON_H 2 | #define OPENTERA_WEBRTC_NATIVE_CLIENT_PYTHON_SOURCES_AUDIO_SOURCE_PYTHON_H 3 | 4 | #include 5 | 6 | namespace opentera 7 | { 8 | PYBIND11_EXPORT void initAudioSourcePython(pybind11::module& m); 9 | } 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/include/OpenteraWebrtcNativeClientPython/Sources/VideoSourcePython.h: -------------------------------------------------------------------------------- 1 | #ifndef OPENTERA_WEBRTC_NATIVE_CLIENT_SOURCES_PYTHON_VIDEO_SOURCE_PYTHON_H 2 | #define OPENTERA_WEBRTC_NATIVE_CLIENT_SOURCES_PYTHON_VIDEO_SOURCE_PYTHON_H 3 | 4 | #include 5 | 6 | namespace opentera 7 | { 8 | PYBIND11_EXPORT void initVideoSourcePython(pybind11::module& m); 9 | } 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/include/OpenteraWebrtcNativeClientPython/StreamClientPython.h: -------------------------------------------------------------------------------- 1 | #ifndef OPENTERA_WEBRTC_NATIVE_CLIENT_PYTHON_STREAM_CLIENT_PYTHON_H 2 | #define OPENTERA_WEBRTC_NATIVE_CLIENT_PYTHON_STREAM_CLIENT_PYTHON_H 3 | 4 | #include 5 | 6 | namespace opentera 7 | { 8 | PYBIND11_EXPORT void initStreamClientPython(pybind11::module& m); 9 | } 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/include/OpenteraWebrtcNativeClientPython/Utils/ClientPython.h: -------------------------------------------------------------------------------- 1 | #ifndef OPENTERA_WEBRTC_NATIVE_CLIENT_PYTHON_UTILS_CLIENT_PYTHON_H 2 | #define OPENTERA_WEBRTC_NATIVE_CLIENT_PYTHON_UTILS_CLIENT_PYTHON_H 3 | 4 | #include 5 | 6 | namespace opentera 7 | { 8 | PYBIND11_EXPORT void initClientPython(pybind11::module& m); 9 | } 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/include/OpenteraWebrtcNativeClientPython/Utils/IceServerPython.h: -------------------------------------------------------------------------------- 1 | #ifndef OPENTERA_WEBRTC_NATIVE_CLIENT_PYTHON_UTILS_ICE_SERVER_PYTHON_H 2 | #define OPENTERA_WEBRTC_NATIVE_CLIENT_PYTHON_UTILS_ICE_SERVER_PYTHON_H 3 | 4 | #include 5 | 6 | namespace opentera 7 | { 8 | PYBIND11_EXPORT void initIceServerPython(pybind11::module& m); 9 | } 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/include/OpenteraWebrtcNativeClientPython/WebrtcClientPython.h: -------------------------------------------------------------------------------- 1 | #ifndef OPENTERA_WEBRTC_NATIVE_CLIENT_PYTHON_WEBRTC_CLIENT_PYTHON_H 2 | #define OPENTERA_WEBRTC_NATIVE_CLIENT_PYTHON_WEBRTC_CLIENT_PYTHON_H 3 | 4 | #include 5 | 6 | namespace opentera 7 | { 8 | PYBIND11_EXPORT void initWebrtcClientPython(pybind11::module& m); 9 | } 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/package/MANIFEST.in.in: -------------------------------------------------------------------------------- 1 | global-include *.pyi 2 | global-include *.typed 3 | global-include *.@PYTHON_SO_EXTENSION@ 4 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/package/README.md.in: -------------------------------------------------------------------------------- 1 | # opentera-webrtc-client ${OPENTERA_WEBRTC_NATIVE_CLIENT_VERSION} 2 | 3 | Python package information. 4 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/package/__init__.py.in: -------------------------------------------------------------------------------- 1 | from opentera_webrtc.native_client.${PYTHON_LIB_NAME} import * 2 | 3 | def _patch(): 4 | 5 | __all_imports = { 6 | _k: _v 7 | for _k, _v 8 | in globals().items() 9 | if isinstance(_v, type) and isinstance(_k, str) 10 | and _v.__module__ == 'opentera_webrtc.native_client._opentera_webrtc_native_client' 11 | } 12 | 13 | __all = [] 14 | 15 | for _k, _v in __all_imports.items(): 16 | _v.__module__ = _v.__module__.replace( 17 | '.${PYTHON_LIB_NAME}', '') 18 | __all.append(_k) 19 | 20 | return __all 21 | 22 | 23 | __all__ = _patch() 24 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/package/_source/index.rst: -------------------------------------------------------------------------------- 1 | .. OpenTera documentation master file, created by 2 | sphinx-quickstart on Thu Mar 3 16:11:36 2022. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to OpenTera's documentation! 7 | ==================================== 8 | 9 | .. autosummary:: 10 | :toctree: _autosummary 11 | :recursive: 12 | 13 | opentera_webrtc 14 | 15 | 16 | Indices and tables 17 | ================== 18 | 19 | * :ref:`genindex` 20 | * :ref:`modindex` 21 | * :ref:`search` 22 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/package/_source/theme/requirements.txt: -------------------------------------------------------------------------------- 1 | sphinx-rtd-theme==1.1.1 2 | charset-normalizer<3.0,>=2.0 3 | sphinx==5.3.0 4 | urllib3<2.0 5 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/package/post-process-doc.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | # Remove opentera_webrtc.native_client._opentera_webrtc_native_client as a prefix for fully-qualified names 3 | find . -type f -name '*.html' | xargs sed -i.bak 's/opentera_webrtc\.native_client\._opentera_webrtc_native_client\.//g' && find . -type f -name '*.html.bak' | xargs rm 4 | 5 | # Remove _opentera_webrtc_native_client 6 | find . -type f -name '*.html' | xargs sed -i.bak 's/opentera_webrtc\.native_client\._opentera_webrtc_native_client/opentera_webrtc.native_client/g' && find . -type f -name '*.html.bak' | xargs rm 7 | 8 | # Fix opentera:: prefix 9 | find . -type f -name '*.html' | xargs sed -i.bak 's/opentera:://g' && find . -type f -name '*.html.bak' | xargs rm 10 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/package/post-process-stub.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | sed -i.bak 's/_opentera_webrtc_native_client\.//g' $1 && rm $1.bak 3 | sed -i.bak 's/opentera:://g' $1 && rm $1.bak 4 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/package/setup.py.in: -------------------------------------------------------------------------------- 1 | from setuptools import setup, dist, find_packages 2 | from setuptools.command.install import install 3 | import os 4 | 5 | def read_file(name): 6 | with open(name, "r", encoding="utf-8") as fh: 7 | return fh.read() 8 | 9 | 10 | def get_doc_files(): 11 | files = {} 12 | for root, _, filenames in os.walk('_doc'): 13 | for filename in filenames: 14 | rootless = root.replace('_doc', os.path.join('doc', 'opentera_webrtc', 'native_client')) 15 | if not rootless in files.keys(): 16 | files[rootless] = [] 17 | files[rootless].append(os.path.join(root, filename)) 18 | return list(files.items()) 19 | 20 | 21 | long_description = read_file("README.md") 22 | 23 | 24 | class BinaryDistribution(dist.Distribution): 25 | """Force setuptools to recognize that this is actually a binary distribution""" 26 | def has_ext_modules(self): 27 | return True 28 | 29 | 30 | setup( 31 | name="opentera_webrtc_native_client", 32 | version="${OPENTERA_WEBRTC_NATIVE_CLIENT_VERSION}", 33 | author="Marc-Antoine Maheux, Cedric Godin, Dominic Letourneau", 34 | author_email="marc-antoine.maheux@usherbrooke.ca, cedric.godin@usherbrooke.ca, dominic.letourneau@usherbrooke.ca", 35 | description="OpenTera WebRTC Client Library for Python", 36 | long_description=long_description, 37 | long_description_content_type="text/markdown", 38 | url="https://github.com/introlab/opentera-webrtc", 39 | packages=['opentera_webrtc.native_client'], 40 | classifiers=[ 41 | "Programming Language :: Python :: 3", 42 | "Development Status :: 4 - Beta", 43 | "License :: OSI Approved :: Apache Software License", 44 | "Operating System :: POSIX", 45 | ], 46 | license="Apache Software License", 47 | distclass=BinaryDistribution, 48 | platforms=['linux_x86_64'], 49 | # python_requires='==3.8', 50 | package_data={ 51 | 'opentera_webrtc.native_client': [ 52 | "$", 53 | $,"${GSTREAMER_TARGET_FILE_NAME}"$,> 54 | $,"opentera_webrtc/native_client/py.typed"$,> 55 | $,"opentera_webrtc/native_client/__init__.pyi"$,> 56 | ], 57 | }, 58 | $,data_files=get_doc_files()$,> 59 | include_package_data=True, 60 | zip_safe=False, 61 | ) 62 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/src/Configurations/VideoSourceConfigurationPython.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | using namespace opentera; 6 | using namespace std; 7 | namespace py = pybind11; 8 | 9 | void opentera::initVideoSourceConfigurationPython(py::module& m) 10 | { 11 | py::class_( 12 | m, 13 | "VideoSourceConfiguration", 14 | "Represents a configuration of a video source that can be added to a " 15 | "WebRTC call.") 16 | .def_static( 17 | "create", 18 | py::overload_cast(&VideoSourceConfiguration::create), 19 | "Creates a video source configuration with the specified values.\n" 20 | "\n" 21 | ":param needs_denoising: Indicates if this source needs denoising\n" 22 | ":param is_screencast: Indicates if this source is screencast\n" 23 | "\n" 24 | ":return: A video source configuration with the specified values", 25 | py::arg("needs_denoising"), 26 | py::arg("is_screencast")) 27 | 28 | .def_property_readonly( 29 | "needs_denoising", 30 | &VideoSourceConfiguration::needsDenoising, 31 | "Indicates if this source needs denoising.\n" 32 | "\n" 33 | ":return: True if this source needs denoising") 34 | .def_property_readonly( 35 | "is_screencast", 36 | &VideoSourceConfiguration::isScreencast, 37 | "Indicates if this source is screencast.\n" 38 | "\n" 39 | ":return: True if this source is a screencast"); 40 | } 41 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/src/Configurations/WebrtcConfigurationPython.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | 7 | using namespace opentera; 8 | using namespace std; 9 | namespace py = pybind11; 10 | 11 | void opentera::initWebrtcConfigurationPython(pybind11::module& m) 12 | { 13 | py::class_(m, "WebrtcConfiguration", "Represents a WebRTC peer connection configuration.") 14 | .def_static( 15 | "create", 16 | py::overload_cast<>(&WebrtcConfiguration::create), 17 | "Creates a WebRTC peer connection configuration with default " 18 | "values.\n" 19 | "\n" 20 | ":return: A WebRTC peer connection configuration with default values") 21 | .def_static( 22 | "create", 23 | py::overload_cast>(&WebrtcConfiguration::create), 24 | "Creates a WebRTC peer connection configuration with the specified " 25 | "value.\n" 26 | "\n" 27 | ":param ice_servers: The ice servers\n" 28 | "\n" 29 | ":return: A WebRTC peer connection configuration with the specified " 30 | "value", 31 | py::arg("ice_servers")) 32 | 33 | .def_property_readonly( 34 | "ice_servers", 35 | &WebrtcConfiguration::iceServers, 36 | "Returns the ice servers.\n" 37 | "\n" 38 | ":return: The ice servers"); 39 | } 40 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/src/Sources/VideoSourcePython.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | 7 | using namespace opentera; 8 | using namespace std; 9 | namespace py = pybind11; 10 | 11 | void sendFrame(const shared_ptr& self, const py::array_t& bgrImg, int64_t timestampUs) 12 | { 13 | if (bgrImg.ndim() != 3) 14 | { 15 | throw py::value_error("The image must have 3 dimensions."); 16 | } 17 | int height = static_cast(bgrImg.shape(0)); 18 | int width = bgrImg.shape(1); 19 | size_t channelCount = bgrImg.shape(2); 20 | if (channelCount != 3) 21 | { 22 | throw py::value_error("The channel count must be 3."); 23 | } 24 | 25 | self->sendFrame( 26 | cv::Mat(height, width, CV_8UC3, const_cast(bgrImg.data()), bgrImg.strides(0)), 27 | timestampUs); 28 | } 29 | 30 | void opentera::initVideoSourcePython(pybind11::module& m) 31 | { 32 | py::class_>( 33 | m, 34 | "VideoSource", 35 | "Represents a video source that can be added to a WebRTC call.\n" 36 | "\n" 37 | "Pass an instance of this to the StreamClient and call sendFrame for " 38 | "each of your frame.") 39 | .def( 40 | py::init(), 41 | "Creates a VideoSource\n" 42 | "\n" 43 | ":param configuration: The configuration applied to the video " 44 | "stream by the image transport layer", 45 | py::arg("configuration")) 46 | .def( 47 | "send_frame", 48 | &sendFrame, 49 | py::call_guard(), 50 | "Sends a frame to the WebRTC transport layer\n" 51 | "\n" 52 | "The frame may or may not be sent depending of the transport layer " 53 | "state\n" 54 | "Frame will be resized to match the transport layer request\n" 55 | "\n" 56 | ":param bgr_img: BGR8 encoded frame data\n" 57 | ":param timestamp_us: Frame timestamp in microseconds", 58 | py::arg("bgr_img"), 59 | py::arg("timestamp_us")); 60 | } 61 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/src/opentera_webrtc_native_client.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | using namespace opentera; 19 | namespace py = pybind11; 20 | 21 | PYBIND11_MODULE(_opentera_webrtc_native_client, m) 22 | { 23 | initAudioSourceConfigurationPython(m); 24 | initDataChannelConfigurationPython(m); 25 | initSignalingServerConfigurationPython(m); 26 | initVideoSourceConfigurationPython(m); 27 | initVideoStreamConfigurationPython(m); 28 | initWebrtcConfigurationPython(m); 29 | 30 | initClientPython(m); 31 | initIceServerPython(m); 32 | 33 | initAudioSourcePython(m); 34 | initVideoSourcePython(m); 35 | 36 | initWebrtcClientPython(m); 37 | initDataChannelClientPython(m); 38 | initStreamClientPython(m); 39 | 40 | #ifdef OPENTERA_WEBRTC_NATIVE_CLIENT_VERSION 41 | m.attr("__version__") = OPENTERA_WEBRTC_NATIVE_CLIENT_VERSION; 42 | #else 43 | m.attr("__version__") = "dev"; 44 | #endif 45 | } 46 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/test/.gitignore: -------------------------------------------------------------------------------- 1 | opentera_webrtc_native_client.*.so 2 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/test/callback_awaiter.py: -------------------------------------------------------------------------------- 1 | import threading 2 | import time 3 | 4 | 5 | class CallbackAwaiter: 6 | def __init__(self, max_count, timeout_seconds): 7 | self._count = 0 8 | self._max_count = max_count 9 | self._timeout_seconds = timeout_seconds 10 | self._lock = threading.Lock() 11 | 12 | def wait(self): 13 | def get_count(): 14 | with self._lock: 15 | return self._count 16 | 17 | start_time = time.time() 18 | while get_count() < self._max_count: 19 | time.sleep(0.05) 20 | 21 | if time.time() - start_time > self._timeout_seconds: 22 | raise TimeoutError() 23 | 24 | def done(self): 25 | with self._lock: 26 | self._count += 1 27 | return self._count >= self._max_count 28 | 29 | def is_finished(self): 30 | with self._lock: 31 | return self._count >= self._max_count 32 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/test/configurations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/introlab/opentera-webrtc/458277e9c1d17e9e1e1e6fe15394dee7e1329aa3/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/test/configurations/__init__.py -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/test/configurations/audio_source_configuration_test.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | import opentera_webrtc.native_client as webrtc 4 | 5 | 6 | class AudioSourceConfigurationTestCase(unittest.TestCase): 7 | def test_create__should_set_none(self): 8 | testee = webrtc.AudioSourceConfiguration.create(10) 9 | 10 | self.assertEqual(testee.sound_card_total_delay_ms, 10) 11 | self.assertEqual(testee.echo_cancellation, None) 12 | self.assertEqual(testee.auto_gain_control, None) 13 | self.assertEqual(testee.noise_suppression, None) 14 | self.assertEqual(testee.highpass_filter, None) 15 | self.assertEqual(testee.stereo_swapping, None) 16 | self.assertEqual(testee.transient_suppression, None) 17 | 18 | def test_create__echo_cancellation_auto_gain_control__should_set_the_attributes(self): 19 | testee = webrtc.AudioSourceConfiguration.create(10, True, False, None, None, None, None) 20 | 21 | self.assertEqual(testee.sound_card_total_delay_ms, 10) 22 | self.assertEqual(testee.echo_cancellation, True) 23 | self.assertEqual(testee.auto_gain_control, False) 24 | self.assertEqual(testee.noise_suppression, None) 25 | self.assertEqual(testee.highpass_filter, None) 26 | self.assertEqual(testee.stereo_swapping, None) 27 | self.assertEqual(testee.transient_suppression, None) 28 | 29 | def test_create__noise_suppression_highpass_filter__should_set_the_attributes(self): 30 | testee = webrtc.AudioSourceConfiguration.create(10, None, None, True, False, None, None) 31 | 32 | self.assertEqual(testee.sound_card_total_delay_ms, 10) 33 | self.assertEqual(testee.echo_cancellation, None) 34 | self.assertEqual(testee.auto_gain_control, None) 35 | self.assertEqual(testee.noise_suppression, True) 36 | self.assertEqual(testee.highpass_filter, False) 37 | self.assertEqual(testee.stereo_swapping, None) 38 | self.assertEqual(testee.transient_suppression, None) 39 | 40 | def test_create__stereo_swapping__should_set_the_attributes(self): 41 | testee = webrtc.AudioSourceConfiguration.create(10, None, None, None, None, True, None) 42 | 43 | self.assertEqual(testee.sound_card_total_delay_ms, 10) 44 | self.assertEqual(testee.echo_cancellation, None) 45 | self.assertEqual(testee.auto_gain_control, None) 46 | self.assertEqual(testee.noise_suppression, None) 47 | self.assertEqual(testee.highpass_filter, None) 48 | self.assertEqual(testee.stereo_swapping, True) 49 | self.assertEqual(testee.transient_suppression, None) 50 | 51 | def test_create__transient_suppression__should_set_the_attributes(self): 52 | testee = webrtc.AudioSourceConfiguration.create(10, None, None, None, None, None, False) 53 | 54 | self.assertEqual(testee.sound_card_total_delay_ms, 10) 55 | self.assertEqual(testee.echo_cancellation, None) 56 | self.assertEqual(testee.auto_gain_control, None) 57 | self.assertEqual(testee.noise_suppression, None) 58 | self.assertEqual(testee.highpass_filter, None) 59 | self.assertEqual(testee.stereo_swapping, None) 60 | self.assertEqual(testee.transient_suppression, False) 61 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/test/configurations/video_source_configuration_test.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | import opentera_webrtc.native_client as webrtc 4 | 5 | 6 | class VideoSourceConfigurationTestCase(unittest.TestCase): 7 | def test_create__should_set_the_attributes(self): 8 | testee = webrtc.VideoSourceConfiguration.create(True, False) 9 | 10 | self.assertEqual(testee.needs_denoising, True) 11 | self.assertEqual(testee.is_screencast, False) 12 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/test/configurations/video_stream_configuration_test.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | import opentera_webrtc.native_client as webrtc 4 | 5 | 6 | class VideoStreamConfigurationTestCase(unittest.TestCase): 7 | def test_create__should_set_the_attributes(self): 8 | testee = webrtc.VideoStreamConfiguration.create() 9 | 10 | self.assertEqual(testee.forced_codecs, set()) 11 | self.assertEqual(testee.force_gstreamer_hardware_acceleration, False) 12 | self.assertEqual(testee.use_gstreamer_software_encoder_decoder, False) 13 | 14 | def test_create__forced_codecs__should_set_the_attributes(self): 15 | testee = webrtc.VideoStreamConfiguration.create({webrtc.VideoStreamCodec.VP8}) 16 | 17 | self.assertEqual(testee.forced_codecs, {webrtc.VideoStreamCodec.VP8}) 18 | self.assertEqual(testee.force_gstreamer_hardware_acceleration, False) 19 | self.assertEqual(testee.use_gstreamer_software_encoder_decoder, False) 20 | 21 | def test_create__all__should_set_the_attributes(self): 22 | testee = webrtc.VideoStreamConfiguration.create({webrtc.VideoStreamCodec.VP9, webrtc.VideoStreamCodec.H264}, 23 | True, False) 24 | 25 | self.assertEqual(testee.forced_codecs, {webrtc.VideoStreamCodec.VP9, webrtc.VideoStreamCodec.H264}) 26 | self.assertEqual(testee.force_gstreamer_hardware_acceleration, True) 27 | self.assertEqual(testee.use_gstreamer_software_encoder_decoder, False) 28 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/test/configurations/webrtc_configuration_test.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | import opentera_webrtc.native_client as webrtc 4 | 5 | 6 | class WebrtcConfigurationTestCase(unittest.TestCase): 7 | def test_create__should_set_the_attributes(self): 8 | testee = webrtc.WebrtcConfiguration.create() 9 | 10 | self.assertEqual(testee.ice_servers, []) 11 | 12 | def test_create__ice_servers__should_set_the_attributes(self): 13 | testee = webrtc.WebrtcConfiguration.create([webrtc.IceServer('url1')]) 14 | 15 | self.assertEqual(len(testee.ice_servers), 1) 16 | self.assertEqual(testee.ice_servers[0].urls, ['url1']) 17 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/test/failure_test_case.py: -------------------------------------------------------------------------------- 1 | import traceback 2 | import unittest 3 | 4 | 5 | class FailureTestCase(unittest.TestCase): 6 | def setUp(self): 7 | super(FailureTestCase, self).setUp() 8 | print(self.__class__.__name__, self._testMethodName) 9 | self._failures = [] 10 | 11 | def tearDown(self): 12 | if len(self._failures) > 0: 13 | self.fail(str(self._failures)) 14 | super(FailureTestCase, self).tearDown() 15 | 16 | def add_failure(self, msg): 17 | self._failures.append(msg + '\n' + '\n'.join(traceback.format_stack())) 18 | 19 | def add_failure_assert_equal(self, a, b): 20 | if a != b: 21 | self.add_failure('{} != {}'.format(a, b)) 22 | 23 | def add_failure_assert_true(self, a): 24 | if not a: 25 | self.add_failure('{} != True'.format(a)) 26 | 27 | def add_failure_assert_false(self, a): 28 | if a: 29 | self.add_failure('{} != False'.format(a)) 30 | 31 | def add_failure_assert_in(self, a, b): 32 | if a not in b: 33 | self.add_failure('{} not in {}'.format(a, b)) 34 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/test/requirements.txt: -------------------------------------------------------------------------------- 1 | numpy 2 | websocket-client==1.7.0 3 | requests 4 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/test/resources/iceServers.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "urls": "stun:stun.l.google.com:19302" 4 | } 5 | ] 6 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/test/signaling_server_runner.py: -------------------------------------------------------------------------------- 1 | import pathlib 2 | import subprocess 3 | import time 4 | import sys 5 | 6 | signaling_server_path = pathlib.Path(__file__).parent.parent.parent.parent.parent.joinpath('signaling-server') \ 7 | .joinpath('opentera-signaling-server').absolute() 8 | ice_server_path = pathlib.Path(__file__).parent.joinpath('resources').joinpath('iceServers.json').absolute() 9 | 10 | 11 | class SignalingServerRunner: 12 | def __init__(self): 13 | # Use same interpreter 14 | self._process = subprocess.Popen([sys.executable, signaling_server_path, '--port', '8080', '--password', 'abc', 15 | '--ice_servers', ice_server_path]) 16 | time.sleep(3) 17 | 18 | def __enter__(self): 19 | return self 20 | 21 | def __exit__(self, exc_type, exc_value, traceback): 22 | self.close() 23 | 24 | def close(self): 25 | self._process.kill() 26 | self._process.wait() 27 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/test/sources/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/introlab/opentera-webrtc/458277e9c1d17e9e1e1e6fe15394dee7e1329aa3/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/test/sources/__init__.py -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/test/sources/audio_source_test.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | import numpy as np 4 | import opentera_webrtc.native_client as webrtc 5 | 6 | 7 | class AudioSourceTestCase(unittest.TestCase): 8 | def test_constructor__should_only_support_valid_bits_per_sample(self): 9 | webrtc.AudioSource(webrtc.AudioSourceConfiguration.create(10), 8, 48000, 1) 10 | webrtc.AudioSource(webrtc.AudioSourceConfiguration.create(10), 16, 48000, 1) 11 | webrtc.AudioSource(webrtc.AudioSourceConfiguration.create(10), 32, 48000, 1) 12 | 13 | with self.assertRaises(RuntimeError): 14 | webrtc.AudioSource(webrtc.AudioSourceConfiguration.create(10), 7, 48000, 1) 15 | 16 | def test_send_frame__should_only_support_valid_frame(self): 17 | testee = webrtc.AudioSource(webrtc.AudioSourceConfiguration.create(10), 8, 48000, 2) 18 | 19 | with self.assertRaises(ValueError) as cm: 20 | testee.send_frame(np.zeros(10, dtype=np.int16)) 21 | self.assertEqual(str(cm.exception), 'Invalid frame data type.') 22 | 23 | with self.assertRaises(ValueError) as cm: 24 | testee.send_frame(np.zeros((1, 10), dtype=np.int8)) 25 | self.assertEqual(str(cm.exception), 'The frame must have 1 dimension.') 26 | 27 | with self.assertRaises(ValueError) as cm: 28 | testee.send_frame(np.zeros(11, dtype=np.int8)) 29 | self.assertEqual(str(cm.exception), 30 | 'The frame size must be a multiple of (bytes_per_sample * number_of_channels).') 31 | 32 | testee.send_frame(np.zeros(10, dtype=np.int8)) 33 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/test/sources/video_source_test.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | import numpy as np 4 | import opentera_webrtc.native_client as webrtc 5 | 6 | 7 | class VideoSourceTestCase(unittest.TestCase): 8 | 9 | def test_send_frame__should_only_support_valid_frame(self): 10 | testee = webrtc.VideoSource(webrtc.VideoSourceConfiguration.create(False, False)) 11 | 12 | with self.assertRaises(ValueError) as cm: 13 | testee.send_frame(np.zeros((10, 10), dtype=np.int8), 0) 14 | self.assertEqual(str(cm.exception), 'The image must have 3 dimensions.') 15 | 16 | with self.assertRaises(ValueError) as cm: 17 | testee.send_frame(np.zeros((10, 10, 4), dtype=np.int8), 1000) 18 | self.assertEqual(str(cm.exception), 'The channel count must be 3.') 19 | 20 | testee.send_frame(np.zeros((10, 10, 3), dtype=np.int8), 2000) 21 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/test/start_tests.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copy library 4 | cp ../../../build/OpenteraWebrtcNativeClient/python/bin/Release/opentera_webrtc_native_client.cpython-*.so . 5 | 6 | # Discover tests and run them 7 | python3 -m unittest discover . "*_test.py" 8 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/test/utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/introlab/opentera-webrtc/458277e9c1d17e9e1e1e6fe15394dee7e1329aa3/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/test/utils/__init__.py -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/test/utils/client_test.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | import opentera_webrtc.native_client as webrtc 4 | 5 | 6 | class ClientTestCase(unittest.TestCase): 7 | def test_constructor__client__should_set_the_attributes(self): 8 | testee = webrtc.Client('id1', 'name1', {'flag': 10}) 9 | 10 | self.assertEqual(testee.id, 'id1') 11 | self.assertEqual(testee.name, 'name1') 12 | self.assertEqual(testee.data, {'flag': 10}) 13 | 14 | def test_constructor__room_client__should_set_the_attributes(self): 15 | testee = webrtc.RoomClient('id1', 'name1', {'flag': 10}, True) 16 | 17 | self.assertEqual(testee.id, 'id1') 18 | self.assertEqual(testee.name, 'name1') 19 | self.assertEqual(testee.data, {'flag': 10}) 20 | self.assertEqual(testee.is_connected, True) 21 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/test/utils/ice_server_test.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | import opentera_webrtc.native_client as webrtc 4 | 5 | from signaling_server_runner import SignalingServerRunner 6 | 7 | 8 | class IceServerTestCase(unittest.TestCase): 9 | @classmethod 10 | def setUpClass(cls): 11 | super(IceServerTestCase, cls).setUpClass() 12 | cls._signaling_server_runner = SignalingServerRunner() 13 | 14 | @classmethod 15 | def tearDownClass(cls): 16 | cls._signaling_server_runner.close() 17 | super(IceServerTestCase, cls).tearDownClass() 18 | 19 | def test_constructor__url__should_set_the_attributes(self): 20 | testee = webrtc.IceServer('url1') 21 | 22 | self.assertEqual(testee.urls, ['url1']) 23 | self.assertEqual(testee.username, '') 24 | self.assertEqual(testee.credential, '') 25 | 26 | def test_constructor__url_username_credential__should_set_the_attributes(self): 27 | testee = webrtc.IceServer('url1', 'user', 'password') 28 | 29 | self.assertEqual(testee.urls, ['url1']) 30 | self.assertEqual(testee.username, 'user') 31 | self.assertEqual(testee.credential, 'password') 32 | 33 | def test_constructor__urls__should_set_the_attributes(self): 34 | testee = webrtc.IceServer(['url1', 'url2']) 35 | 36 | self.assertEqual(testee.urls, ['url1', 'url2']) 37 | self.assertEqual(testee.username, '') 38 | self.assertEqual(testee.credential, '') 39 | 40 | def test_constructor__urls__should_set_the_attributes(self): 41 | testee = webrtc.IceServer(['url1', 'url2'], 'user', 'password') 42 | 43 | self.assertEqual(testee.urls, ['url1', 'url2']) 44 | self.assertEqual(testee.username, 'user') 45 | self.assertEqual(testee.credential, 'password') 46 | 47 | def test_fetch_from_server__invalid_url__should(self): 48 | with self.assertRaises(RuntimeError): 49 | webrtc.IceServer.fetch_from_server('http://localhost:8080/ice', '') 50 | 51 | def test_fetch_from_server__wrong_password__should_return_an_empty_list(self): 52 | ice_servers = webrtc.IceServer.fetch_from_server('http://localhost:8080/iceservers', '') 53 | self.assertEqual(ice_servers, []) 54 | 55 | def test_fetch_from_server__right_password__should_return_the_server_ice_servers(self): 56 | ice_servers = webrtc.IceServer.fetch_from_server('http://localhost:8080/iceservers', 'abc') 57 | self.assertEqual(len(ice_servers), 1) 58 | self.assertEqual(ice_servers[0].urls, ['stun:stun.l.google.com:19302']) 59 | self.assertEqual(ice_servers[0].username, '') 60 | self.assertEqual(ice_servers[0].credential, '') 61 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/test/websocket_inactive_client_test.py: -------------------------------------------------------------------------------- 1 | import threading 2 | 3 | import websocket 4 | 5 | from callback_awaiter import CallbackAwaiter 6 | from failure_test_case import FailureTestCase 7 | from signaling_server_runner import SignalingServerRunner 8 | 9 | 10 | class WebSocketInactiveClientTestCase(FailureTestCase): 11 | @classmethod 12 | def setUpClass(cls): 13 | super(WebSocketInactiveClientTestCase, cls).setUpClass() 14 | cls._signaling_server_runner = SignalingServerRunner() 15 | 16 | @classmethod 17 | def tearDownClass(cls): 18 | cls._signaling_server_runner.close() 19 | super(WebSocketInactiveClientTestCase, cls).tearDownClass() 20 | 21 | def test_socketio_inactive_is_disconnected_after_timeout(self): 22 | awaiter = CallbackAwaiter(2, 15) 23 | 24 | def on_open(ws): 25 | awaiter.done() 26 | 27 | def on_message(ws, message): 28 | pass 29 | 30 | def on_error(ws, error): 31 | awaiter.done() 32 | awaiter.done() 33 | self.add_failure(error) 34 | 35 | def on_close(ws, close_status_code, close_msg): 36 | awaiter.done() 37 | 38 | websocket.enableTrace(True) 39 | ws = websocket.WebSocketApp('ws://localhost:8080/signaling', 40 | on_open=on_open, on_message=on_message, on_error=on_error, on_close=on_close) 41 | 42 | thread = threading.Thread(target=ws.run_forever) 43 | thread.start() 44 | 45 | awaiter.wait() 46 | ws.close() 47 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/Configurations/AudioSourceConfiguration.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace opentera; 4 | using namespace std; 5 | 6 | AudioSourceConfiguration::AudioSourceConfiguration( 7 | uint32_t soundCardTotalDelayMs, 8 | absl::optional echoCancellation, 9 | absl::optional autoGainControl, 10 | absl::optional noiseSuppression, 11 | absl::optional highpassFilter, 12 | absl::optional stereoSwapping, 13 | absl::optional transientSuppression) 14 | : m_soundCardTotalDelayMs(soundCardTotalDelayMs), 15 | m_echoCancellation(echoCancellation), 16 | m_autoGainControl(autoGainControl), 17 | m_noiseSuppression(noiseSuppression), 18 | m_highpassFilter(highpassFilter), 19 | m_stereoSwapping(stereoSwapping), 20 | m_transientSuppression(transientSuppression) 21 | { 22 | } 23 | 24 | /** 25 | * Converts a AudioSourceConfiguration to a cricket::AudioOptions. 26 | * @return The converted cricket::AudioOptions 27 | */ 28 | AudioSourceConfiguration::operator cricket::AudioOptions() const 29 | { 30 | cricket::AudioOptions options; 31 | options.echo_cancellation = m_echoCancellation; 32 | options.auto_gain_control = m_autoGainControl; 33 | options.noise_suppression = m_noiseSuppression; 34 | options.highpass_filter = m_highpassFilter; 35 | options.stereo_swapping = m_stereoSwapping; 36 | 37 | return options; 38 | } 39 | 40 | /** 41 | * Converts a AudioSourceConfiguration to a webrtc::AudioProcessing::Config. 42 | * @return The converted webrtc::AudioProcessing::Config 43 | */ 44 | AudioSourceConfiguration::operator webrtc::AudioProcessing::Config() const 45 | { 46 | webrtc::AudioProcessing::Config config; 47 | if (m_echoCancellation.has_value()) 48 | { 49 | config.echo_canceller.enabled = m_echoCancellation.value(); 50 | } 51 | if (m_autoGainControl.has_value()) 52 | { 53 | config.gain_controller2.enabled = m_autoGainControl.value(); 54 | } 55 | if (m_noiseSuppression.has_value()) 56 | { 57 | config.noise_suppression.enabled = m_noiseSuppression.value(); 58 | } 59 | if (m_highpassFilter.has_value()) 60 | { 61 | config.high_pass_filter.enabled = m_highpassFilter.value(); 62 | } 63 | if (m_transientSuppression.has_value()) 64 | { 65 | config.transient_suppression.enabled = m_transientSuppression.value(); 66 | } 67 | 68 | return config; 69 | } 70 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/Configurations/DataChannelConfiguration.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace opentera; 4 | using namespace std; 5 | 6 | DataChannelConfiguration::DataChannelConfiguration( 7 | bool ordered, 8 | absl::optional maxPacketLifeTime, 9 | absl::optional maxRetransmits, 10 | string&& protocol) 11 | : m_ordered(ordered), 12 | m_maxPacketLifeTime(maxPacketLifeTime), 13 | m_maxRetransmits(maxRetransmits), 14 | m_protocol(move(protocol)) 15 | { 16 | } 17 | 18 | /** 19 | * Converts a AudioSourceConfiguration to a webrtc::DataChannelInit. 20 | * @return The converted webrtc::DataChannelInit 21 | */ 22 | DataChannelConfiguration::operator webrtc::DataChannelInit() const 23 | { 24 | webrtc::DataChannelInit configuration; 25 | configuration.ordered = m_ordered; 26 | if (m_maxPacketLifeTime) 27 | { 28 | configuration.maxRetransmitTime = m_maxPacketLifeTime.value(); 29 | } 30 | if (m_maxRetransmits) 31 | { 32 | configuration.maxRetransmits = m_maxRetransmits.value(); 33 | } 34 | configuration.protocol = m_protocol; 35 | 36 | return configuration; 37 | } 38 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/Configurations/SignalingServerConfiguration.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace opentera; 4 | using namespace std; 5 | 6 | SignalingServerConfiguration::SignalingServerConfiguration( 7 | string&& url, 8 | string&& clientName, 9 | nlohmann::json&& clientData, 10 | string&& room, 11 | string&& password) 12 | : m_url(move(url)), 13 | m_clientName(move(clientName)), 14 | m_clientData(move(clientData)), 15 | m_room(move(room)), 16 | m_password(move(password)) 17 | { 18 | } 19 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/Configurations/VideoSourceConfiguration.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace opentera; 4 | using namespace std; 5 | 6 | VideoSourceConfiguration::VideoSourceConfiguration(bool needsDenoising, bool isScreencast) 7 | : m_needsDenoising(needsDenoising), 8 | m_isScreencast(isScreencast) 9 | { 10 | } 11 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/Configurations/VideoStreamConfiguration.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace opentera; 4 | using namespace std; 5 | 6 | absl::optional opentera::stringToVideoStreamCodec(string_view value) 7 | { 8 | if (value == "VP8" || value == "vp8" || value == "vP8" || value == "Vp8") 9 | { 10 | return VideoStreamCodec::VP8; 11 | } 12 | else if (value == "VP9" || value == "vp9" || value == "vP9" || value == "Vp9") 13 | { 14 | return VideoStreamCodec::VP9; 15 | } 16 | else if (value == "H264" || value == "h264") 17 | { 18 | return VideoStreamCodec::H264; 19 | } 20 | else 21 | { 22 | return absl::nullopt; 23 | } 24 | } 25 | 26 | VideoStreamConfiguration::VideoStreamConfiguration( 27 | unordered_set forcedCodecs, 28 | bool forceGStreamerHardwareAcceleration, 29 | bool useGStreamerSoftwareEncoderDecoder) 30 | : m_forcedCodecs(move(forcedCodecs)), 31 | m_forceGStreamerHardwareAcceleration(forceGStreamerHardwareAcceleration), 32 | m_useGStreamerSoftwareEncoderDecoder(useGStreamerSoftwareEncoderDecoder) 33 | { 34 | } 35 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/Configurations/WebrtcConfiguration.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace opentera; 4 | using namespace std; 5 | 6 | WebrtcConfiguration::WebrtcConfiguration(vector&& iceServers) : m_iceServers(move(iceServers)) {} 7 | 8 | /** 9 | * Converts a AudioSourceConfiguration to a 10 | * webrtc::PeerConnectionInterface::RTCConfiguration. 11 | * @return The converted webrtc::PeerConnectionInterface::RTCConfiguration 12 | */ 13 | WebrtcConfiguration::operator webrtc::PeerConnectionInterface::RTCConfiguration() const 14 | { 15 | webrtc::PeerConnectionInterface::RTCConfiguration configuration; 16 | for (const auto& iceServer : m_iceServers) 17 | { 18 | configuration.servers.push_back(static_cast(iceServer)); 19 | } 20 | 21 | configuration.sdp_semantics = webrtc::SdpSemantics::kUnifiedPlan; 22 | 23 | return configuration; 24 | } 25 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/Signaling/SignalingClient.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace opentera; 4 | using namespace std; 5 | 6 | SignalingClient::SignalingClient(SignalingServerConfiguration configuration) : m_configuration(move(configuration)) {} 7 | 8 | SignalingClient::~SignalingClient() {} 9 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/Sinks/AudioSink.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | using namespace std; 6 | using namespace opentera; 7 | 8 | /** 9 | * @brief Construct an AudioStream object 10 | * @param onAudioDataReceived callback function to consume audio data received 11 | * on the WebRTC transport layer 12 | */ 13 | AudioSink::AudioSink(AudioSinkCallback onAudioDataReceived) : m_onAudioFrameReceived(move(onAudioDataReceived)) {} 14 | 15 | /** 16 | * @brief Called by the WebRTC transport layer when audio data is available 17 | * 18 | * @param audioData audio data buffer 19 | * @param bitsPerSample number of bits per audio sample 20 | * @param sampleRate sample rate of the audio data 21 | * @param numberOfChannels number of channel of the audio data 22 | * @param numberOfFrames number of audio frame in the received data 23 | */ 24 | void AudioSink::OnData( 25 | const void* audioData, 26 | int bitsPerSample, 27 | int sampleRate, 28 | size_t numberOfChannels, 29 | size_t numberOfFrames) 30 | { 31 | if (m_onAudioFrameReceived) 32 | { 33 | m_onAudioFrameReceived(audioData, bitsPerSample, sampleRate, numberOfChannels, numberOfFrames); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/Sinks/EncodedVideoSink.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | using namespace opentera; 6 | using namespace rtc; 7 | using namespace std; 8 | 9 | /** 10 | * @brief Construct a VideoSink 11 | * 12 | * @param onFrameReceived callback function that gets called whenever a frame is 13 | * received 14 | */ 15 | EncodedVideoSink::EncodedVideoSink(EncodedVideoSinkCallback onFrameReceived) : m_onFrameReceived(move(onFrameReceived)) 16 | { 17 | } 18 | 19 | /** 20 | * @brief Process incoming frames from webrtc 21 | * 22 | * This function is called by the webrtc transport layer whenever a frame is 23 | * available. It convert YUV frame data from the I420 buffer to BGR data and 24 | * call the callback function with a cv::Mat 25 | * 26 | * @param frame available webrtc frame 27 | */ 28 | void EncodedVideoSink::OnFrame(const webrtc::RecordableEncodedFrame& frame) 29 | { 30 | if (m_onFrameReceived) 31 | { 32 | auto encodedBuffer = frame.encoded_buffer(); 33 | auto resolution = frame.resolution(); 34 | m_onFrameReceived( 35 | encodedBuffer->data(), 36 | encodedBuffer->size(), 37 | static_cast(frame.codec()), 38 | frame.is_key_frame(), 39 | resolution.width, 40 | resolution.height, 41 | frame.render_time().us()); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/Sinks/VideoSink.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace opentera; 8 | using namespace rtc; 9 | using namespace std; 10 | 11 | /** 12 | * @brief Construct a VideoSink 13 | * 14 | * @param onFrameReceived callback function that gets called whenever a frame is 15 | * received 16 | */ 17 | VideoSink::VideoSink(VideoSinkCallback onFrameReceived) : m_onFrameReceived(move(onFrameReceived)) 18 | { 19 | m_wants.rotation_applied = false; 20 | 21 | // Specify we want resolution to be multiple of 2 for I420 22 | m_wants.resolution_alignment = 2; 23 | } 24 | 25 | /** 26 | * @brief Process incoming frames from webrtc 27 | * 28 | * This function is called by the webrtc transport layer whenever a frame is 29 | * available. It convert YUV frame data from the I420 buffer to BGR data and 30 | * call the callback function with a cv::Mat 31 | * 32 | * @param frame available webrtc frame 33 | */ 34 | void VideoSink::OnFrame(const webrtc::VideoFrame& frame) 35 | { 36 | if (!m_onFrameReceived) 37 | { 38 | return; 39 | } 40 | 41 | // Transform data from 3 array in I420 buffer to one cv::Mat in yuv 42 | m_bgrImg.create(frame.height(), frame.width(), CV_8UC3); 43 | 44 | int err = libyuv::ConvertFromI420( 45 | frame.video_frame_buffer()->GetI420()->DataY(), 46 | frame.video_frame_buffer()->GetI420()->StrideY(), 47 | frame.video_frame_buffer()->GetI420()->DataU(), 48 | frame.video_frame_buffer()->GetI420()->StrideU(), 49 | frame.video_frame_buffer()->GetI420()->DataV(), 50 | frame.video_frame_buffer()->GetI420()->StrideV(), 51 | m_bgrImg.data, 52 | m_bgrImg.step[0], 53 | frame.width(), 54 | frame.height(), 55 | libyuv::FOURCC_24BG); 56 | if (err != 0) 57 | { 58 | return; 59 | } 60 | 61 | switch (frame.rotation()) 62 | { 63 | case webrtc::kVideoRotation_0: 64 | m_onFrameReceived(m_bgrImg, frame.timestamp_us()); 65 | return; 66 | case webrtc::kVideoRotation_90: 67 | cv::rotate(m_bgrImg, m_bgrRotatedImg, cv::ROTATE_90_CLOCKWISE); 68 | break; 69 | case webrtc::kVideoRotation_180: 70 | cv::rotate(m_bgrImg, m_bgrRotatedImg, cv::ROTATE_180); 71 | break; 72 | case webrtc::kVideoRotation_270: 73 | cv::rotate(m_bgrImg, m_bgrRotatedImg, cv::ROTATE_90_COUNTERCLOCKWISE); 74 | break; 75 | } 76 | m_onFrameReceived(m_bgrRotatedImg, frame.timestamp_us()); 77 | } 78 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/Sources/VideoSource.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | using namespace opentera; 7 | using namespace std; 8 | using namespace cv; 9 | 10 | /** 11 | * @brief Creates a VideoSource 12 | * 13 | * @param configuration The configuration applied to the video stream by the 14 | * image transport layer 15 | */ 16 | VideoSource::VideoSource(VideoSourceConfiguration configuration) : m_configuration(move(configuration)) {} 17 | 18 | /** 19 | * @brief Sends a frame to the WebRTC transport layer 20 | * 21 | * The frame may or may not be sent depending of the transport layer state 22 | * Frame will be resized to match the transport layer request 23 | * 24 | * @param bgrImg BGR8 encoded frame data 25 | * @param timestampUs Frame timestamp in microseconds 26 | */ 27 | void VideoSource::sendFrame(const Mat& bgrImg, int64_t timestampUs) 28 | { 29 | cv::Rect roi; 30 | int outWidth, outHeight; 31 | 32 | // AdaptFrame return true if the transport layer needs a frame 33 | // Desired resolution is set in out_width and out_height 34 | if (AdaptFrame( 35 | bgrImg.cols, 36 | bgrImg.rows, 37 | timestampUs, 38 | &outWidth, 39 | &outHeight, 40 | &roi.width, 41 | &roi.height, 42 | &roi.x, 43 | &roi.y)) 44 | { 45 | // I420 only support even resolution so we must make output resolution even! 46 | outWidth = (outWidth / 2) * 2; 47 | outHeight = (outHeight / 2) * 2; 48 | 49 | // Convert color space from BGR to YUV 50 | if (outWidth == roi.width && outHeight == roi.height) 51 | { 52 | cv::cvtColor(bgrImg(roi), m_yuvImg, COLOR_BGR2YUV_I420); 53 | } 54 | else 55 | { 56 | cv::resize( 57 | bgrImg(roi), 58 | m_resizedImg, 59 | cv::Size2i(outWidth, outHeight), 60 | 0, 61 | 0, 62 | outWidth < roi.width ? cv::INTER_AREA : cv::INTER_LINEAR); 63 | cv::cvtColor(m_resizedImg, m_yuvImg, COLOR_BGR2YUV_I420); 64 | } 65 | 66 | // Convert from OpenCV matrix to webrtc frame 67 | uint8_t* y = m_yuvImg.data; 68 | uint8_t* u = y + (outWidth * outHeight); 69 | uint8_t* v = u + (outWidth * outHeight) / 4; 70 | webrtc::VideoFrame frame( 71 | webrtc::I420Buffer::Copy(outWidth, outHeight, y, outWidth, u, outWidth / 2, v, outWidth / 2), 72 | webrtc::kVideoRotation_0, 73 | timestampUs); 74 | 75 | // Passes the frame to the transport layer 76 | OnFrame(frame); 77 | } 78 | } 79 | 80 | void VideoSource::AddRef() const {} 81 | 82 | rtc::RefCountReleaseStatus VideoSource::Release() const 83 | { 84 | return rtc::RefCountReleaseStatus::kOtherRefsRemained; 85 | } 86 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/Utils/Client.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace opentera; 4 | using namespace std; 5 | 6 | /** 7 | * @brief Creates a client with the specified values. 8 | * 9 | * @param id The client id 10 | * @param name The client name 11 | * @param data The client data 12 | */ 13 | Client::Client(string id, string name, nlohmann::json data) : m_id(move(id)), m_name(move(name)), m_data(move(data)) {} 14 | 15 | Client::Client(const nlohmann::json& message) 16 | { 17 | if (isValid(message)) 18 | { 19 | m_id = message["id"]; 20 | m_name = message["name"]; 21 | m_data = message["data"]; 22 | } 23 | } 24 | 25 | bool Client::isValid(const nlohmann::json& message) 26 | { 27 | if (!message.is_object()) 28 | { 29 | return false; 30 | } 31 | if (!message.contains("id") || !message.contains("name") || !message.contains("data")) 32 | { 33 | return false; 34 | } 35 | 36 | return message["id"].is_string() && message["name"].is_string(); 37 | } 38 | 39 | /** 40 | * @brief Creates a room client with the default values. 41 | */ 42 | RoomClient::RoomClient() : m_isConnected(false) {} 43 | 44 | /** 45 | * @brief Creates a room client with the specified values. 46 | * 47 | * @param id The client id 48 | * @param name The client name 49 | * @param data The client data 50 | * @param isConnected Indicates if the client is connected (RTCPeerConnection) 51 | */ 52 | RoomClient::RoomClient(string id, string name, nlohmann::json data, bool isConnected) 53 | : m_id(move(id)), 54 | m_name(move(name)), 55 | m_data(move(data)), 56 | m_isConnected(isConnected) 57 | { 58 | } 59 | 60 | /** 61 | * @brief Creates a room client from a client. 62 | * 63 | * @param client The client 64 | * @param isConnected Indicates if the client is connected (RTCPeerConnection) 65 | */ 66 | RoomClient::RoomClient(const Client& client, bool isConnected) 67 | : m_id(client.id()), 68 | m_name(client.name()), 69 | m_data(client.data()), 70 | m_isConnected(isConnected) 71 | { 72 | } 73 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/Utils/Http.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | using namespace opentera; 6 | using namespace std; 7 | 8 | bool Http::get(const string& url, string& response, multimap headers, bool verifyCertificate) 9 | { 10 | string host; 11 | string target; 12 | 13 | if (!Http::splitUrl(url, host, target)) 14 | { 15 | return false; 16 | } 17 | 18 | try 19 | { 20 | httplib::Client cli(host); 21 | #if defined(__APPLE__) 22 | /* 23 | TODO : Remove the certificate path on macosx with new version of 24 | BoringSSL? As of now, the ca-certificates need to be installed on the 25 | system with the following command: brew install ca-certificates 26 | */ 27 | cli.set_ca_cert_path("/usr/local/etc/ca-certificates/cert.pem"); 28 | #elif defined(_WIN32) 29 | /* 30 | TODO : Find a better solution than MSYS2 to install the certificate on 31 | windows. As of now, the ca-certificates need to be installed on the 32 | system with the following command: pacman -S ca-certificates 33 | */ 34 | cli.set_ca_cert_path("C:\\msys64\\usr\\ssl\\cert.pem"); 35 | #endif 36 | cli.enable_server_certificate_verification(verifyCertificate); 37 | auto res = cli.Get(target, httplib::Headers(headers.begin(), headers.end())); 38 | if (res == nullptr || res->status != 200) 39 | { 40 | return false; 41 | } 42 | response = res->body; 43 | } 44 | catch (...) 45 | { 46 | return false; 47 | } 48 | return true; 49 | } 50 | 51 | bool Http::splitUrl(const string& url, string& host, string& target) 52 | { 53 | size_t hostBeginPosistion = url.find("://"); 54 | if (hostBeginPosistion == string::npos) 55 | { 56 | return false; 57 | } 58 | 59 | hostBeginPosistion += 3; 60 | size_t firstSlashPosition = url.find('/', hostBeginPosistion); 61 | 62 | if (firstSlashPosition == string::npos) 63 | { 64 | host = url; 65 | target = "/"; 66 | } 67 | else 68 | { 69 | host = url.substr(0, firstSlashPosition); 70 | target = url.substr(firstSlashPosition); 71 | } 72 | 73 | return true; 74 | } 75 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/Utils/thread.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #if defined(WIN32) || defined(_WIN32) 4 | #include 5 | #elif defined(UNIX) || defined(__unix__) || defined(LINUX) || defined(__linux__) 6 | #include 7 | #endif 8 | 9 | using namespace std; 10 | 11 | bool setThreadPriority(thread& thread, ThreadPriority priority) 12 | { 13 | #if defined(WIN32) || defined(_WIN32) 14 | return SetPriorityClass(thread.native_handle(), static_cast(priority)) != 0; 15 | #elif defined(UNIX) || defined(__unix__) || defined(LINUX) || defined(__linux__) || defined(__APPLE__) 16 | int topPriority = sched_get_priority_max(SCHED_RR) - 1; 17 | int lowPriority = sched_get_priority_min(SCHED_RR) + 1; 18 | 19 | sched_param sch_params; 20 | switch (priority) 21 | { 22 | case ThreadPriority::Normal: 23 | sch_params.sched_priority = (topPriority - lowPriority - 1) / 2; 24 | break; 25 | case ThreadPriority::RealTime: 26 | sch_params.sched_priority = topPriority; 27 | break; 28 | } 29 | 30 | return pthread_setschedparam(thread.native_handle(), SCHED_RR, &sch_params) == 0; 31 | #endif 32 | } 33 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/version.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | string opentera::getVersion() 6 | { 7 | #ifdef OPENTERA_WEBRTC_NATIVE_CLIENT_VERSION 8 | return OPENTERA_WEBRTC_NATIVE_CLIENT_VERSION; 9 | #else 10 | return "dev"; 11 | #endif 12 | } 13 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14.0) 2 | 3 | project(OpenteraWebrtcNativeClientTests) 4 | 5 | set(LIBRARY_OUTPUT_PATH bin/${CMAKE_BUILD_TYPE}) 6 | 7 | include_directories(../../3rdParty/googletest/googletest/include) 8 | include_directories(../../3rdParty/googletest/googlemock/include) 9 | include_directories(../../3rdParty/cpp-subprocess) 10 | include_directories(../include) 11 | include_directories(include) 12 | 13 | if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND "${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS "9.0.0") 14 | set(OPENTERA_WEBRTC_NATIVE_CLIENT_TESTS_FS "stdc++fs") 15 | else() 16 | set(OPENTERA_WEBRTC_NATIVE_CLIENT_TESTS_FS "") 17 | endif() 18 | 19 | file(GLOB_RECURSE 20 | TEST_SOURCE_FILES 21 | "src/*" 22 | "include/*" 23 | ) 24 | 25 | add_executable(OpenteraWebrtcNativeClientTests 26 | ${TEST_SOURCE_FILES} 27 | ) 28 | 29 | target_link_libraries(OpenteraWebrtcNativeClientTests 30 | OpenteraWebrtcNativeClient 31 | gtest 32 | gmock 33 | ${OPENTERA_WEBRTC_NATIVE_CLIENT_TESTS_FS} 34 | ) 35 | 36 | if (WIN32) 37 | target_compile_definitions(OpenteraWebrtcNativeClientTests PRIVATE WIN32_LEAN_AND_MEAN) 38 | endif () 39 | 40 | set_property(TARGET OpenteraWebrtcNativeClientTests PROPERTY CXX_STANDARD 17) 41 | 42 | assign_source_group(${source_files}) 43 | 44 | add_custom_command(TARGET OpenteraWebrtcNativeClientTests POST_BUILD 45 | COMMAND ${CMAKE_COMMAND} -E copy_directory 46 | ${PROJECT_SOURCE_DIR}/resources $/resources 47 | ) 48 | 49 | install(TARGETS OpenteraWebrtcNativeClientTests DESTINATION bin) 50 | install(DIRECTORY resources DESTINATION bin) 51 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/test/include/OpenteraWebrtcNativeClientTests/CallbackAwaiter.h: -------------------------------------------------------------------------------- 1 | #ifndef OPENTERA_WEBRTC_NATIVE_CLIENT_TESTS_CALLBACK_AWAITER_H 2 | #define OPENTERA_WEBRTC_NATIVE_CLIENT_TESTS_CALLBACK_AWAITER_H 3 | 4 | #include 5 | #include 6 | 7 | namespace opentera 8 | { 9 | class CallbackAwaiter 10 | { 11 | std::atomic_int m_count; 12 | const int m_maxCount; 13 | std::chrono::seconds m_timeout; 14 | std::chrono::steady_clock::time_point m_begin; 15 | 16 | public: 17 | CallbackAwaiter(int maxCount, std::chrono::seconds timeout); 18 | 19 | void wait(const char* file, int line); 20 | bool done(); 21 | }; 22 | } 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/test/resources/cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDCzCCAfOgAwIBAgIUd+Q1eIV8HK6S33IdyhG1rBi0C48wDQYJKoZIhvcNAQEL 3 | BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MCAXDTIxMDIxMTIxMzA0N1oYDzIxMjEw 4 | MTE4MjEzMDQ3WjAUMRIwEAYDVQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEB 5 | AQUAA4IBDwAwggEKAoIBAQCglHB9BdxM2BA/bH4W/EEWXmPe9+SvdGhC/O7bSqCf 6 | vZwbZkPptbX1h9xaEj8yEUlQZEhymabMh7W1u5pPoGpb53DEaI8lHK8gewDvluNU 7 | kJgVAU39KuTzplUPqN7mUfBuLOjDsXoYc528DwnDwGlTLHEYueXhC1idek3lObNG 8 | ggAm4pevbRSkEfjELhoCgl7QNNiegW/Uck6HyYgw9QVhSU+0GX+qOwcF8qkusnsL 9 | aLFCMGbA8uvJjGV4Uy3N4e7dBe3VIh/sIJUPcnyroPTu/2tk2a449u99UVsc4hXH 10 | H8D3MrZ9VjNooJKN2Oh22PX5/ud2MKXrvFqXYGSWGlATAgMBAAGjUzBRMB0GA1Ud 11 | DgQWBBS4hYCyJETQQzBmt2C4EeFnIZJ0QDAfBgNVHSMEGDAWgBS4hYCyJETQQzBm 12 | t2C4EeFnIZJ0QDAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBi 13 | zehTPqUupRumPpvumQZaQo8AwiGEvGqD35Ydvt5xyVQcniWmk9sVJKA4qo94AHOW 14 | UcKflVDX6ywXT5cFXhx4VPow014fXSl4XkLVWunm+RD97dR8rcrcXwK+e6jVZ2bW 15 | ozAprFj337VCWFxv/k6MMs4OyW4QCDz49nTYpnBWzoUmGWShYDD1nRaeIAueCOq2 16 | jiUw0rfkz4IHslpDwLhalRWZ400UDg/v8E1S2RPikCmSUgXsALuJ4wwGU4/+B313 17 | cu4ko38E4MxF+4y3BWWS++YIdeMdoWRNfjaXe5Bqtui4hNSt1YZTJjzl5OL8pKM3 18 | k22ZFHp5UWgm/SRW0Bc7 19 | -----END CERTIFICATE----- 20 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/test/resources/iceServers.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "urls": "stun:stun.l.google.com:19302" 4 | } 5 | ] 6 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/test/resources/key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCglHB9BdxM2BA/ 3 | bH4W/EEWXmPe9+SvdGhC/O7bSqCfvZwbZkPptbX1h9xaEj8yEUlQZEhymabMh7W1 4 | u5pPoGpb53DEaI8lHK8gewDvluNUkJgVAU39KuTzplUPqN7mUfBuLOjDsXoYc528 5 | DwnDwGlTLHEYueXhC1idek3lObNGggAm4pevbRSkEfjELhoCgl7QNNiegW/Uck6H 6 | yYgw9QVhSU+0GX+qOwcF8qkusnsLaLFCMGbA8uvJjGV4Uy3N4e7dBe3VIh/sIJUP 7 | cnyroPTu/2tk2a449u99UVsc4hXHH8D3MrZ9VjNooJKN2Oh22PX5/ud2MKXrvFqX 8 | YGSWGlATAgMBAAECggEAC93MTkDfncIduUIgMzyi5q9E/BYfjSOyDLk6QXRLWGKf 9 | pZqyDBREhQdsLi/JAb8rRsiSXf2iyNyCfhKF/bpiAbahq7H6Wgi7nE/aqtngpMAm 10 | rO6yv7Gqx6KUCJs3FZgah1nEPang1uu8TUhjNVcDsYTIOsaKCU5YVxLRrM3NxLj6 11 | qIZ1iimOmPh4WJuH3JKxCnfjG7nbcR5kgcTVCqp/XxhqyiuA3qnx6s6H6YtUk6eY 12 | WFK4zV1HVQJjWX8HwHKdataIPCEjLIrJEW52GTBjn2QoHtWQ8SDhVt0ogvPW4BS+ 13 | AMOQ+/w/76CpAEjyU565nwrp9LrzW4yz69iwiKnk8QKBgQDLfjjeLdxsN9oK19do 14 | znlgkC8/ZJpDoA/aouXchQj9OgRTxP8iytARr7GUycD1NTsefQiQsb6peOORjIOc 15 | Kavh1GnNmOoA/Ettyx4R76JQzT/K1LLF39/Jd0lt5D1dRQ2wMAJBxB1Ncn/fEe+R 16 | 8VvAECyvSl0V7mC14WJoFN6oiQKBgQDKA5Nci7WDjTMMrvmUz+Oxzm4SZrreBrjz 17 | fTaeHPXqJoplJZX/77Varqo7jzfs94YB/dFZ1ZUqxvl5D6662MmJcRBBSl2wKN7Y 18 | 6s9kx5kbgDh9kgTFoqC3xYQFh+oifwZhC5zU87nGTg4PrKamQcXhTA8qtfQ5pKfy 19 | s/OAAFaUuwKBgDVUG+UmEakOrga/cAVYbvi+cJNlcwQb82ux2xmCh8uNI8ssSky8 20 | 5/BqodhDU10vmRGxZMg+vJ+/PaxMLcWEKjZhq2SlGVYuyDm6zGOY8GnKkFhAi6VN 21 | uWEb8NNqyCYkTaUJv92qXp+ITTiRg740iX34/yzlCSYRNakUquxp47w5AoGBAJqK 22 | kblCx+GTq3IQia5mO3JS0bISFPK1gdgD+jyLOzWdtlIapt3cq4hsBp75uXb3BPWR 23 | Dw8CbdMD1OXgMXOPVN5oOF86XOHe4lxfhbk7WM3JEW4+vpfTCdCMsarphxxMwLyM 24 | /bWLnpsuK2OiWPrnZlIstY2fFO7kH/dz4twRZirxAoGAHVTjCLyJkgGjDSLvCWWt 25 | ka1VZgClUHdbWQnfYOVagDWQsdQIfpJubYEHCT3suUrw6ow5cyxEKU3dGa1qLpz1 26 | uQfR5muE81i/GRQX3rjcDpCMTvF/b37mjAa5zkpMLvyvvzEpbX0uYjh5U/p0vMWV 27 | U8FqP+2axjxaFVC5p2wYJ3c= 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/test/src/CallbackAwaiter.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | using namespace opentera; 9 | using namespace std; 10 | 11 | CallbackAwaiter::CallbackAwaiter(int maxCount, chrono::seconds timeout) 12 | : m_count(0), 13 | m_maxCount(maxCount), 14 | m_timeout(timeout), 15 | m_begin(chrono::steady_clock::now()) 16 | { 17 | } 18 | 19 | void CallbackAwaiter::wait(const char* file, int line) 20 | { 21 | while (m_count.load() < m_maxCount) 22 | { 23 | this_thread::sleep_for(50ms); 24 | 25 | chrono::steady_clock::time_point end = chrono::steady_clock::now(); 26 | if (chrono::duration_cast(end - m_begin) > m_timeout) 27 | { 28 | ADD_FAILURE_AT(file, line); 29 | return; 30 | } 31 | } 32 | } 33 | 34 | bool CallbackAwaiter::done() 35 | { 36 | return (++m_count) == m_maxCount; 37 | } 38 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/test/src/Configurations/SignalingServerConfigurationTests.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | using namespace opentera; 7 | using namespace std; 8 | 9 | TEST(SignalingServerConfigurationTests, create_urlClientNameRoom_shouldSetTheAttributes) 10 | { 11 | auto testee = SignalingServerConfiguration::create("url", "name", "room"); 12 | 13 | EXPECT_EQ(testee.url(), "url"); 14 | EXPECT_EQ(testee.clientName(), "name"); 15 | EXPECT_EQ(testee.clientData(), nlohmann::json{}); 16 | EXPECT_EQ(testee.room(), "room"); 17 | EXPECT_EQ(testee.password(), ""); 18 | } 19 | 20 | TEST(SignalingServerConfigurationTests, createWithData_urlClientNameClientDataRoom__shouldSetTheAttributes) 21 | { 22 | auto testee = SignalingServerConfiguration::createWithData("url", "name", 10, "room"); 23 | 24 | EXPECT_EQ(testee.url(), "url"); 25 | EXPECT_EQ(testee.clientName(), "name"); 26 | EXPECT_EQ(testee.clientData(), 10); 27 | EXPECT_EQ(testee.room(), "room"); 28 | EXPECT_EQ(testee.password(), ""); 29 | } 30 | 31 | TEST(SignalingServerConfigurationTests, create_urlClientNameRoomPassword_shouldSetTheAttributes) 32 | { 33 | auto testee = SignalingServerConfiguration::create("url", "name", "room", "password"); 34 | 35 | EXPECT_EQ(testee.url(), "url"); 36 | EXPECT_EQ(testee.clientName(), "name"); 37 | EXPECT_EQ(testee.clientData(), nlohmann::json{}); 38 | EXPECT_EQ(testee.room(), "room"); 39 | EXPECT_EQ(testee.password(), "password"); 40 | } 41 | 42 | TEST(SignalingServerConfigurationTests, createWithData_urlClientNameClientDataRoomPassword_shouldSetTheAttributes) 43 | { 44 | auto testee = SignalingServerConfiguration::createWithData("url", "name", 10, "room", "password"); 45 | 46 | EXPECT_EQ(testee.url(), "url"); 47 | EXPECT_EQ(testee.clientName(), "name"); 48 | EXPECT_EQ(testee.clientData(), 10); 49 | EXPECT_EQ(testee.room(), "room"); 50 | EXPECT_EQ(testee.password(), "password"); 51 | } 52 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/test/src/Configurations/VideoSourceConfigurationTests.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | using namespace opentera; 6 | using namespace std; 7 | 8 | TEST(VideoSourceConfigurationTests, create_shouldSetTheAttributes) 9 | { 10 | VideoSourceConfiguration testee = VideoSourceConfiguration::create(true, false); 11 | 12 | EXPECT_EQ(testee.needsDenoising(), true); 13 | EXPECT_EQ(testee.isScreencast(), false); 14 | } 15 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/test/src/Configurations/VideoStreamConfigurationTests.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace opentera; 5 | using namespace std; 6 | 7 | TEST(VideoStreamConfigurationTests, stringToVideoStreamCodec) 8 | { 9 | EXPECT_EQ(stringToVideoStreamCodec("VP8"), VideoStreamCodec::VP8); 10 | EXPECT_EQ(stringToVideoStreamCodec("VP9"), VideoStreamCodec::VP9); 11 | EXPECT_EQ(stringToVideoStreamCodec("H264"), VideoStreamCodec::H264); 12 | 13 | EXPECT_EQ(stringToVideoStreamCodec("vp8"), VideoStreamCodec::VP8); 14 | EXPECT_EQ(stringToVideoStreamCodec("vp9"), VideoStreamCodec::VP9); 15 | EXPECT_EQ(stringToVideoStreamCodec("h264"), VideoStreamCodec::H264); 16 | 17 | EXPECT_EQ(stringToVideoStreamCodec("Vp8"), VideoStreamCodec::VP8); 18 | EXPECT_EQ(stringToVideoStreamCodec("Vp9"), VideoStreamCodec::VP9); 19 | EXPECT_EQ(stringToVideoStreamCodec("vP8"), VideoStreamCodec::VP8); 20 | EXPECT_EQ(stringToVideoStreamCodec("vP9"), VideoStreamCodec::VP9); 21 | 22 | EXPECT_EQ(stringToVideoStreamCodec("asd"), absl::nullopt); 23 | } 24 | 25 | TEST(VideoStreamConfigurationTests, create_shouldSetTheAttributes) 26 | { 27 | VideoStreamConfiguration testee = VideoStreamConfiguration::create(); 28 | 29 | EXPECT_EQ(testee.forcedCodecs(), unordered_set({})); 30 | EXPECT_EQ(testee.forceGStreamerHardwareAcceleration(), false); 31 | EXPECT_EQ(testee.useGStreamerSoftwareEncoderDecoder(), false); 32 | } 33 | 34 | TEST(VideoStreamConfigurationTests, create_forcedCodecs_shouldSetTheAttributes) 35 | { 36 | VideoStreamConfiguration testee = VideoStreamConfiguration::create({VideoStreamCodec::VP8}); 37 | 38 | EXPECT_EQ(testee.forcedCodecs(), unordered_set({VideoStreamCodec::VP8})); 39 | EXPECT_EQ(testee.forceGStreamerHardwareAcceleration(), false); 40 | EXPECT_EQ(testee.useGStreamerSoftwareEncoderDecoder(), false); 41 | } 42 | 43 | TEST(VideoStreamConfigurationTests, create_all_shouldSetTheAttributes) 44 | { 45 | VideoStreamConfiguration testee1 = VideoStreamConfiguration::create({VideoStreamCodec::VP9}, false, true); 46 | 47 | EXPECT_EQ(testee1.forcedCodecs(), unordered_set({VideoStreamCodec::VP9})); 48 | EXPECT_EQ(testee1.forceGStreamerHardwareAcceleration(), false); 49 | EXPECT_EQ(testee1.useGStreamerSoftwareEncoderDecoder(), true); 50 | 51 | 52 | VideoStreamConfiguration testee2 = 53 | VideoStreamConfiguration::create({VideoStreamCodec::VP8, VideoStreamCodec::H264}, true, false); 54 | 55 | EXPECT_EQ(testee2.forcedCodecs(), unordered_set({VideoStreamCodec::VP8, VideoStreamCodec::H264})); 56 | EXPECT_EQ(testee2.forceGStreamerHardwareAcceleration(), true); 57 | EXPECT_EQ(testee2.useGStreamerSoftwareEncoderDecoder(), false); 58 | } 59 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/test/src/Configurations/WebrtcConfigurationTests.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace opentera; 5 | using namespace std; 6 | 7 | TEST(WebrtcConfigurationTests, create_shouldSetTheAttributes) 8 | { 9 | WebrtcConfiguration testee = WebrtcConfiguration::create(); 10 | EXPECT_EQ(testee.iceServers().size(), 0); 11 | } 12 | 13 | TEST(WebrtcConfigurationTests, create_iceServers_shouldSetTheAttributes) 14 | { 15 | WebrtcConfiguration testee = WebrtcConfiguration::create({IceServer("url1")}); 16 | ASSERT_EQ(testee.iceServers().size(), 1); 17 | ASSERT_EQ(testee.iceServers()[0].urls().size(), 1); 18 | EXPECT_EQ(testee.iceServers()[0].urls()[0], "url1"); 19 | } 20 | 21 | TEST(WebrtcConfigurationTests, operator_webrtcPeerConnectionInterfaceRtcConfiguration_shouldSetTheAttributes) 22 | { 23 | auto testee = static_cast( 24 | WebrtcConfiguration::create({IceServer("url1")})); 25 | ASSERT_EQ(testee.servers.size(), 1); 26 | ASSERT_EQ(testee.servers[0].urls.size(), 1); 27 | EXPECT_EQ(testee.servers[0].urls[0], "url1"); 28 | } 29 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/test/src/Sinks/EncodedVideoSinkTests.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | using namespace opentera; 6 | using namespace std; 7 | 8 | TEST(EncodedVideoSinkTests, VideoCodecType_shouldMatchWebrtcVideoCodecType) 9 | { 10 | EXPECT_EQ(VideoCodecType::Generic, static_cast(webrtc::kVideoCodecGeneric)); 11 | EXPECT_EQ(VideoCodecType::VP8, static_cast(webrtc::kVideoCodecVP8)); 12 | EXPECT_EQ(VideoCodecType::VP9, static_cast(webrtc::kVideoCodecVP9)); 13 | EXPECT_EQ(VideoCodecType::AV1, static_cast(webrtc::kVideoCodecAV1)); 14 | EXPECT_EQ(VideoCodecType::H264, static_cast(webrtc::kVideoCodecH264)); 15 | } 16 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/test/src/Utils/HttpTests.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | using namespace opentera; 7 | using namespace std; 8 | 9 | using ::testing::HasSubstr; 10 | 11 | TEST(HttpTests, get_http_shouldReturnTrueAndSetResponse) 12 | { 13 | string response; 14 | if (Http::get("http://www.perdu.com", response, {})) 15 | { 16 | EXPECT_THAT(response, HasSubstr("Vous Etes Perdu ?")); 17 | } 18 | else if (Http::get("http://www.perdus.com", response, {})) 19 | { 20 | EXPECT_THAT(response, HasSubstr("Vous Etes Perdus ?")); 21 | } 22 | else 23 | { 24 | FAIL() << "Neither 'http://www.perdus.com' nor 'http://www.perdu.com' could be reached."; 25 | } 26 | } 27 | 28 | TEST(HttpTests, get_https_shouldReturnTrueAndSetResponse) 29 | { 30 | string response; 31 | if (Http::get("https://www.perdu.com", response, {})) 32 | { 33 | EXPECT_THAT(response, HasSubstr("Vous Etes Perdu ?")); 34 | } 35 | else if (Http::get("https://www.perdus.com", response, {})) 36 | { 37 | EXPECT_THAT(response, HasSubstr("Vous Etes Perdus ?")); 38 | } 39 | else 40 | { 41 | FAIL() << "Neither 'https://www.perdu.com' nor 'https://www.perdus.com' could be reached."; 42 | } 43 | } 44 | 45 | TEST(HttpTests, get_invalidUrl_shouldReturnFalse) 46 | { 47 | string response; 48 | EXPECT_FALSE(Http::get("http://localhost:8080/iceservers", response, {})); 49 | EXPECT_EQ(response, ""); 50 | 51 | EXPECT_FALSE(Http::get("https://localhost:8080/iceservers", response, {})); 52 | EXPECT_EQ(response, ""); 53 | } 54 | 55 | TEST(HttpTests, splitUrl_invalidUrl_shouldReturnFalse) 56 | { 57 | string host; 58 | string target; 59 | 60 | EXPECT_FALSE(Http::splitUrl("", host, target)); 61 | EXPECT_FALSE(Http::splitUrl("asd", host, target)); 62 | } 63 | 64 | TEST(HttpTests, getHostPortTargetFromUrl_validUrl_shouldReturnTrueAndSetParameters) 65 | { 66 | string host; 67 | string target; 68 | 69 | EXPECT_TRUE(Http::splitUrl("http://localhost", host, target)); 70 | EXPECT_EQ(host, "http://localhost"); 71 | EXPECT_EQ(target, "/"); 72 | 73 | EXPECT_TRUE(Http::splitUrl("http://localhost/a/route/", host, target)); 74 | EXPECT_EQ(host, "http://localhost"); 75 | EXPECT_EQ(target, "/a/route/"); 76 | 77 | EXPECT_TRUE(Http::splitUrl("http://localhost:8080", host, target)); 78 | EXPECT_EQ(host, "http://localhost:8080"); 79 | EXPECT_EQ(target, "/"); 80 | 81 | EXPECT_TRUE(Http::splitUrl("http://localhost:6060/a/route/", host, target)); 82 | EXPECT_EQ(host, "http://localhost:6060"); 83 | EXPECT_EQ(target, "/a/route/"); 84 | } 85 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeClient/test/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char* argv[]) 4 | { 5 | ::testing::InitGoogleTest(&argc, argv); 6 | return RUN_ALL_TESTS(); 7 | } 8 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeGStreamer/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14.0) 2 | 3 | project(OpenteraWebrtcNativeGStreamer) 4 | 5 | file(GLOB_RECURSE 6 | source_files 7 | src/* 8 | include/*) 9 | 10 | add_library(${PROJECT_NAME} SHARED ${source_files}) 11 | set_property(TARGET OpenteraWebrtcNativeGStreamer PROPERTY CXX_STANDARD 17) 12 | 13 | 14 | find_package(PkgConfig REQUIRED) 15 | pkg_check_modules(GSTREAMER REQUIRED gstreamer-1.0) 16 | pkg_check_modules(GSTREAMER_VIDEO REQUIRED gstreamer-video-1.0) 17 | pkg_check_modules(GSTREAMER_APP REQUIRED gstreamer-app-1.0) 18 | 19 | target_include_directories(OpenteraWebrtcNativeGStreamer SYSTEM PRIVATE 20 | ${webrtc_native_INCLUDE} 21 | ${GSTREAMER_INCLUDE_DIRS} 22 | ${GSTREAMER_VIDEO_INCLUDE_DIRS} 23 | ${GSTREAMER_APP_INCLUDE_DIRS}) 24 | target_include_directories(OpenteraWebrtcNativeGStreamer PRIVATE include) 25 | 26 | target_link_directories(OpenteraWebrtcNativeGStreamer PRIVATE 27 | ${GSTREAMER_LIBRARY_DIRS} 28 | ${GSTREAMER_VIDEO_LIBRARY_DIRS} 29 | ${GSTREAMER_APP_LIBRARY_DIRS}) 30 | target_link_libraries(OpenteraWebrtcNativeGStreamer PRIVATE 31 | ${webrtc_native_LIBRARY} 32 | ${GSTREAMER_LIBRARIES} 33 | ${GSTREAMER_VIDEO_LIBRARIES} 34 | ${GSTREAMER_APP_LIBRARIES}) 35 | install(TARGETS OpenteraWebrtcNativeGStreamer DESTINATION bin) 36 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeGStreamer/README.md: -------------------------------------------------------------------------------- 1 | # OpenteraWebrtcNativeGStreamer 2 | 3 | This is a GStreamer decoder/encoder for the OpenTera WebRTC Native Client library. 4 | 5 | # Licence 6 | 7 | This component is licensed under different licenses depending on the files. 8 | 9 | Some files were inspired by an implementation by Apple in the WebCore project, and are licensed under the LGPLv3, which is compatible with the original LGPLv2 license. 10 | The files which depend on these are also licensed under the LGPLv3. 11 | 12 | A few files are licensed under the Apache 2.0 license, just like the rest of the OpenTera WebRTC Native Client library. 13 | These have no dependency whatsoever on the Apple files. 14 | 15 | Every source file is identified with a header comment that contains the license. 16 | 17 | The component as a whole is therefore licensed under the LGPLv3. 18 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeGStreamer/include/OpenteraWebrtcNativeGStreamer/Decoders/Vp8GStreamerVideoDecoders.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 IntRoLab 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 3 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Library General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #ifndef OPENTERA_WEBRTC_NATIVE_GSTREAMER_FACTORIES_GSTREAMER_VP8_VIDEO_DECODER_FACTORY_H 19 | #define OPENTERA_WEBRTC_NATIVE_GSTREAMER_FACTORIES_GSTREAMER_VP8_VIDEO_DECODER_FACTORY_H 20 | 21 | #include 22 | 23 | namespace opentera 24 | { 25 | class Vp8GStreamerVideoDecoder : public GStreamerVideoDecoder 26 | { 27 | public: 28 | explicit Vp8GStreamerVideoDecoder(std::string decoderPipeline, bool resetPipelineOnSizeChanges = false); 29 | ~Vp8GStreamerVideoDecoder() override = default; 30 | 31 | static const char* mediaTypeCaps(); 32 | static const char* codecName(); 33 | }; 34 | 35 | class SoftwareVp8GStreamerVideoDecoder : public Vp8GStreamerVideoDecoder 36 | { 37 | public: 38 | SoftwareVp8GStreamerVideoDecoder(); 39 | ~SoftwareVp8GStreamerVideoDecoder() override = default; 40 | 41 | [[nodiscard]] webrtc::VideoDecoder::DecoderInfo GetDecoderInfo() const override; 42 | 43 | static bool isSupported(); 44 | static bool isHardwareAccelerated(); 45 | }; 46 | 47 | class VaapiVp8GStreamerVideoDecoder : public Vp8GStreamerVideoDecoder 48 | { 49 | public: 50 | VaapiVp8GStreamerVideoDecoder(); 51 | ~VaapiVp8GStreamerVideoDecoder() override = default; 52 | 53 | [[nodiscard]] webrtc::VideoDecoder::DecoderInfo GetDecoderInfo() const override; 54 | 55 | static bool isSupported(); 56 | static bool isHardwareAccelerated(); 57 | }; 58 | 59 | class TegraVp8GStreamerVideoDecoder : public Vp8GStreamerVideoDecoder 60 | { 61 | public: 62 | TegraVp8GStreamerVideoDecoder(); 63 | ~TegraVp8GStreamerVideoDecoder() override = default; 64 | 65 | [[nodiscard]] webrtc::VideoDecoder::DecoderInfo GetDecoderInfo() const override; 66 | 67 | static bool isSupported(); 68 | static bool isHardwareAccelerated(); 69 | }; 70 | } 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeGStreamer/include/OpenteraWebrtcNativeGStreamer/Decoders/Vp9GStreamerVideoDecoders.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 IntRoLab 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 3 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Library General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #ifndef OPENTERA_WEBRTC_NATIVE_GSTREAMER_FACTORIES_GSTREAMER_VP9_VIDEO_DECODER_FACTORY_H 19 | #define OPENTERA_WEBRTC_NATIVE_GSTREAMER_FACTORIES_GSTREAMER_VP9_VIDEO_DECODER_FACTORY_H 20 | 21 | #include 22 | 23 | namespace opentera 24 | { 25 | class Vp9GStreamerVideoDecoder : public GStreamerVideoDecoder 26 | { 27 | public: 28 | explicit Vp9GStreamerVideoDecoder(std::string decoderPipeline, bool resetPipelineOnSizeChanges = false); 29 | ~Vp9GStreamerVideoDecoder() override = default; 30 | 31 | static const char* mediaTypeCaps(); 32 | static const char* codecName(); 33 | }; 34 | 35 | class SoftwareVp9GStreamerVideoDecoder : public Vp9GStreamerVideoDecoder 36 | { 37 | public: 38 | SoftwareVp9GStreamerVideoDecoder(); 39 | ~SoftwareVp9GStreamerVideoDecoder() override = default; 40 | 41 | [[nodiscard]] webrtc::VideoDecoder::DecoderInfo GetDecoderInfo() const override; 42 | 43 | static bool isSupported(); 44 | static bool isHardwareAccelerated(); 45 | }; 46 | 47 | class VaapiVp9GStreamerVideoDecoder : public Vp9GStreamerVideoDecoder 48 | { 49 | public: 50 | VaapiVp9GStreamerVideoDecoder(); 51 | ~VaapiVp9GStreamerVideoDecoder() override = default; 52 | 53 | [[nodiscard]] webrtc::VideoDecoder::DecoderInfo GetDecoderInfo() const override; 54 | 55 | static bool isSupported(); 56 | static bool isHardwareAccelerated(); 57 | }; 58 | 59 | class TegraVp9GStreamerVideoDecoder : public Vp9GStreamerVideoDecoder 60 | { 61 | public: 62 | TegraVp9GStreamerVideoDecoder(); 63 | ~TegraVp9GStreamerVideoDecoder() override = default; 64 | 65 | [[nodiscard]] webrtc::VideoDecoder::DecoderInfo GetDecoderInfo() const override; 66 | 67 | static bool isSupported(); 68 | static bool isHardwareAccelerated(); 69 | }; 70 | } 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeGStreamer/include/OpenteraWebrtcNativeGStreamer/Pipeline/GStreamerDecoderPipeline.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 IntRoLab 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 3 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Library General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #ifndef OPENTERA_WEBRTC_NATIVE_GSTREAMER_PIPELINE_GSTREAMER_DECODER_PIPELINE_H 19 | #define OPENTERA_WEBRTC_NATIVE_GSTREAMER_PIPELINE_GSTREAMER_DECODER_PIPELINE_H 20 | 21 | #include 22 | 23 | #include 24 | 25 | namespace opentera 26 | { 27 | class GStreamerDecoderPipeline 28 | { 29 | gst::unique_ptr m_pipeline; 30 | gst::unique_ptr m_src; 31 | gst::unique_ptr m_sink; 32 | gst::unique_ptr m_error; 33 | bool m_ready; 34 | 35 | public: 36 | GStreamerDecoderPipeline(); 37 | ~GStreamerDecoderPipeline(); 38 | 39 | GstFlowReturn pushSample(gst::unique_ptr& sample); 40 | void getSinkState(GstState& state, GstState& pending); 41 | gst::unique_ptr tryPullSample(); 42 | 43 | [[nodiscard]] bool ready() const; 44 | void setReady(bool ready); 45 | 46 | int32_t initialize(std::string_view capsStr, std::string_view decoderPipeline); 47 | }; 48 | 49 | inline bool GStreamerDecoderPipeline::ready() const { return m_ready; } 50 | 51 | inline void GStreamerDecoderPipeline::setReady(bool ready) { m_ready = ready; } 52 | } 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeGStreamer/include/OpenteraWebrtcNativeGStreamer/Pipeline/GStreamerEncoderPipeline.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 IntRoLab 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 3 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Library General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #ifndef OPENTERA_WEBRTC_NATIVE_GSTREAMER_PIPELINE_GSTREAMER_ENCODER_PIPELINE_H 19 | #define OPENTERA_WEBRTC_NATIVE_GSTREAMER_PIPELINE_GSTREAMER_ENCODER_PIPELINE_H 20 | 21 | #include 22 | #include 23 | 24 | #include 25 | 26 | namespace opentera 27 | { 28 | enum class BitRateUnit 29 | { 30 | BitPerSec, 31 | KBitPerSec 32 | }; 33 | 34 | class GStreamerEncoderPipeline 35 | { 36 | std::string m_encoderBitRatePropertyName; 37 | BitRateUnit m_encoderBitRatePropertyUnit; 38 | std::string m_encoderKeyframeIntervalPropertyName; 39 | 40 | gst::unique_ptr m_pipeline; 41 | gst::unique_ptr m_src; 42 | gst::unique_ptr m_srcPad; 43 | gst::unique_ptr m_encoder; 44 | gst::unique_ptr m_sink; 45 | gst::unique_ptr m_error; 46 | 47 | public: 48 | GStreamerEncoderPipeline(); 49 | ~GStreamerEncoderPipeline(); 50 | 51 | void forceKeyFrame(); 52 | void setBitRate(uint32_t bitRate); 53 | void setKeyframeInterval(int interval); 54 | 55 | GstFlowReturn pushSample(gst::unique_ptr& sample); 56 | gst::unique_ptr tryPullSample(); 57 | 58 | int32_t initialize( 59 | std::string encoderBitRatePropertyName, 60 | BitRateUnit bitRatePropertyUnit, 61 | std::string keyframeIntervalPropertyName, 62 | std::string_view capsStr, 63 | std::string_view encoderPipeline); 64 | 65 | private: 66 | void setEncoderProperty(const std::string& name, guint value); 67 | }; 68 | } 69 | 70 | #endif 71 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeGStreamer/include/OpenteraWebrtcNativeGStreamer/Utils/ClassMacro.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 IntRoLab 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef OPENTERA_WEBRTC_NATIVE_GSTREAMER_UTILS_CLASS_MACRO_H 18 | #define OPENTERA_WEBRTC_NATIVE_GSTREAMER_UTILS_CLASS_MACRO_H 19 | 20 | #define DECLARE_NOT_COPYABLE(className) \ 21 | className(const className&) = delete; \ 22 | className& operator=(const className&) = delete 23 | 24 | #define DECLARE_NOT_MOVABLE(className) \ 25 | className(className&&) = delete; \ 26 | className& operator=(className&&) = delete 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeGStreamer/include/OpenteraWebrtcNativeGStreamer/Utils/GStreamerBufferPool.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 IntRoLab 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef OPENTERA_WEBRTC_NATIVE_GSTREAMER_UTILS_GSTREAMER_BUFFER_POOL_H 18 | #define OPENTERA_WEBRTC_NATIVE_GSTREAMER_UTILS_GSTREAMER_BUFFER_POOL_H 19 | 20 | #include 21 | #include 22 | 23 | namespace opentera 24 | { 25 | class GStreamerBufferPool 26 | { 27 | gst::unique_ptr m_bufferPool; 28 | 29 | public: 30 | GStreamerBufferPool(); 31 | 32 | bool initialize(size_t bufferSize); 33 | gst::unique_ptr acquireBuffer(); 34 | }; 35 | 36 | inline gst::unique_ptr GStreamerBufferPool::acquireBuffer() 37 | { 38 | gst::unique_ptr buffer; 39 | switch (gst_buffer_pool_acquire_buffer(m_bufferPool.get(), out_ptr(buffer), nullptr)) 40 | { 41 | case GST_FLOW_OK: 42 | return buffer; 43 | default: 44 | return nullptr; 45 | } 46 | } 47 | } 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeGStreamer/include/OpenteraWebrtcNativeGStreamer/Utils/GStreamerSupport.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 IntRoLab 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef OPENTERA_WEBRTC_NATIVE_GSTREAMER_UTILS_GSTREAMER_SUPPORT_H 18 | #define OPENTERA_WEBRTC_NATIVE_GSTREAMER_UTILS_GSTREAMER_SUPPORT_H 19 | 20 | #include 21 | 22 | namespace gst 23 | { 24 | bool elementFactoryExists(const char* name); 25 | bool testEncoderDecoderPipeline(const std::string& encoderDecoderPipeline); 26 | } 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeGStreamer/include/OpenteraWebrtcNativeGStreamer/Utils/GstMappedBuffer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012, 2015, 2016, 2018 Igalia S.L 3 | * Copyright (C) 2015, 2016, 2018 Metrological Group B.V. 4 | * Copyright (C) 2022 IntRoLab 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Library General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | /* 21 | * Original file(s): 22 | * https://opensource.apple.com/source/WebCore/WebCore-7611.3.10.0.1/platform/graphics/gstreamer/GStreamerCommon.h.auto.html 23 | */ 24 | 25 | #ifndef OPENTERA_WEBRTC_NATIVE_GSTREAMER_UTILS_GST_MAPPED_BUFFER_H 26 | #define OPENTERA_WEBRTC_NATIVE_GSTREAMER_UTILS_GST_MAPPED_BUFFER_H 27 | 28 | #include 29 | 30 | #include 31 | #include 32 | 33 | namespace opentera 34 | { 35 | 36 | class GstMappedBuffer 37 | { 38 | GstBuffer* m_buffer; 39 | GstMapInfo m_bufferInfo; 40 | bool m_isValid = false; 41 | 42 | public: 43 | GstMappedBuffer(GstBuffer* buffer, GstMapFlags flags); 44 | ~GstMappedBuffer(); 45 | 46 | DECLARE_NOT_COPYABLE(GstMappedBuffer); 47 | DECLARE_NOT_MOVABLE(GstMappedBuffer); 48 | 49 | [[nodiscard]] uint8_t* data() const; 50 | [[nodiscard]] size_t size() const; 51 | 52 | explicit operator bool() const { return m_isValid; } 53 | }; 54 | 55 | inline GstMappedBuffer::GstMappedBuffer(GstBuffer* buffer, GstMapFlags flags) : m_buffer(buffer) 56 | { 57 | m_isValid = gst_buffer_map(buffer, &m_bufferInfo, flags); 58 | } 59 | 60 | inline GstMappedBuffer::~GstMappedBuffer() 61 | { 62 | if (m_isValid) 63 | { 64 | gst_buffer_unmap(m_buffer, &m_bufferInfo); 65 | } 66 | m_isValid = false; 67 | } 68 | 69 | inline uint8_t* GstMappedBuffer::data() const { return m_isValid ? m_bufferInfo.data : nullptr; } 70 | 71 | inline size_t GstMappedBuffer::size() const { return m_isValid ? m_bufferInfo.size : 0; } 72 | } 73 | 74 | #endif 75 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeGStreamer/include/OpenteraWebrtcNativeGStreamer/Utils/out_ptr.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 IntRoLab 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef OPENTERA_WEBRTC_NATIVE_GSTREAMER_UTILS_OUT_PTR_H 18 | #define OPENTERA_WEBRTC_NATIVE_GSTREAMER_UTILS_OUT_PTR_H 19 | 20 | #include 21 | #include 22 | 23 | namespace opentera 24 | { 25 | // Inspired from std::out_ptr_t in the C++23 standard 26 | // (cppreference: https://en.cppreference.com/w/cpp/memory/out_ptr_t) 27 | // (MSVC implementation: 28 | // https://github.com/microsoft/STL/blob/2f03bdf361f7f153b4216c60a0d9491c0be13a73/stl/inc/memory) 29 | template 30 | class out_ptr_t 31 | { 32 | public: 33 | explicit out_ptr_t(Smart& s) noexcept : m_smart(s) {} 34 | 35 | out_ptr_t(const out_ptr_t&) = delete; 36 | out_ptr_t& operator=(const out_ptr_t&) = delete; 37 | 38 | ~out_ptr_t() noexcept { m_smart.reset(m_ptr); } 39 | 40 | operator Ptr*() noexcept { return std::addressof(m_ptr); } 41 | 42 | private: 43 | Smart& m_smart; 44 | Ptr m_ptr = nullptr; 45 | }; 46 | 47 | // Inspired from std::out_ptr in the C++23 standard 48 | // (cppreference: https://en.cppreference.com/w/cpp/memory/out_ptr_t/out_ptr) 49 | template 50 | inline auto out_ptr(Smart& s) 51 | { 52 | if constexpr (!std::is_void_v) 53 | { 54 | return out_ptr_t(s); 55 | } 56 | else 57 | { 58 | return out_ptr_t(s); 59 | } 60 | } 61 | } 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeGStreamer/src/Utils/GStreamerBufferPool.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace opentera; 4 | 5 | GStreamerBufferPool::GStreamerBufferPool() = default; 6 | 7 | bool GStreamerBufferPool::initialize(size_t bufferSize) 8 | { 9 | m_bufferPool = gst::unique_from_ptr(gst_buffer_pool_new()); 10 | GstStructure* bufferPoolConfig = gst_buffer_pool_get_config(m_bufferPool.get()); 11 | gst_buffer_pool_config_set_params(bufferPoolConfig, nullptr, bufferSize, 1, 0); 12 | return gst_buffer_pool_set_config(m_bufferPool.get(), bufferPoolConfig) && 13 | gst_buffer_pool_set_active(m_bufferPool.get(), true); 14 | } 15 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeGStreamer/src/Utils/GStreamerHelpers.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // RAII wrapper for GStreamer initialization/deinitialization 4 | class GstInit 5 | { 6 | public: 7 | GstInit() 8 | { 9 | if (!gst_is_initialized()) 10 | { 11 | gst_init(nullptr, nullptr); 12 | } 13 | } 14 | }; 15 | 16 | GstInit gstInitInstance; 17 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/OpenteraWebrtcNativeGStreamer/src/Utils/GStreamerSupport.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace opentera; 14 | using namespace opentera::internal; 15 | using namespace std; 16 | 17 | bool gst::elementFactoryExists(const char* name) 18 | { 19 | auto factory = gst::unique_from_ptr(gst_element_factory_find(name)); 20 | return factory != nullptr; 21 | } 22 | 23 | static bool testEncoderDecoderPipeline(const string& encoderDecoderPipeline) 24 | { 25 | constexpr GstClockTime Timeout = GST_SECOND; 26 | 27 | string pipelineStr = "videotestsrc num-buffers=1 ! " 28 | "capsfilter caps=video/x-raw,format=(string)I420,width=(int)256,height=(int)256 ! " + 29 | encoderDecoderPipeline + " ! appsink name=sink"; 30 | 31 | gst::unique_ptr error; 32 | auto pipeline = gst::unique_from_ptr(GST_PIPELINE(gst_parse_launch(pipelineStr.c_str(), out_ptr(error)))); 33 | if (error) 34 | { 35 | return false; 36 | } 37 | 38 | auto sink = gst::unique_from_ptr(gst_bin_get_by_name(GST_BIN(pipeline.get()), "sink")); 39 | connectBusMessageCallback(pipeline); 40 | 41 | if (gst_element_set_state(GST_ELEMENT(pipeline.get()), GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) 42 | { 43 | return false; 44 | } 45 | 46 | GstState state; 47 | if (gst_element_get_state(GST_ELEMENT(pipeline.get()), &state, nullptr, Timeout) != GST_STATE_CHANGE_SUCCESS || 48 | state != GST_STATE_PLAYING) 49 | { 50 | return false; 51 | } 52 | 53 | auto sample = gst::unique_from_ptr(gst_app_sink_try_pull_sample(GST_APP_SINK(sink.get()), Timeout)); 54 | return sample != nullptr; 55 | } 56 | 57 | bool gst::testEncoderDecoderPipeline(const string& encoderDecoderPipeline) 58 | { 59 | static unordered_map cache; 60 | static shared_mutex mutex; 61 | 62 | { 63 | shared_lock lock(mutex); 64 | auto it = cache.find(encoderDecoderPipeline); 65 | if (it != cache.end()) 66 | { 67 | return it->second; 68 | } 69 | } 70 | 71 | { 72 | unique_lock lock(mutex); 73 | bool ok = ::testEncoderDecoderPipeline(encoderDecoderPipeline); 74 | cache[encoderDecoderPipeline] = ok; 75 | return ok; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /opentera-webrtc-native-client/README.md: -------------------------------------------------------------------------------- 1 | Native Library 2 | 3 | TODO Documentation 4 | -------------------------------------------------------------------------------- /opentera-webrtc-web-client/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "env": { 3 | "browser": true, 4 | "commonjs": true, 5 | "es6": true 6 | }, 7 | "extends": "eslint:recommended", 8 | "parserOptions": { 9 | "ecmaVersion": 2018, 10 | "sourceType": "module" 11 | }, 12 | "rules": { 13 | "indent": [ 14 | "error", 15 | 2 16 | ], 17 | "linebreak-style": [ 18 | "error", 19 | "unix" 20 | ], 21 | "quotes": [ 22 | "error", 23 | "single" 24 | ], 25 | "semi": [ 26 | "error", 27 | "always" 28 | ] 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /opentera-webrtc-web-client/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | lib 4 | 5 | package-lock.json 6 | -------------------------------------------------------------------------------- /opentera-webrtc-web-client/README.md: -------------------------------------------------------------------------------- 1 | # opentera-webrtc-web-client 2 | 3 | Create from [https://github.com/georapbox/webpack-library-starter-kit](https://github.com/georapbox/webpack-library-starter-kit) 4 | -------------------------------------------------------------------------------- /opentera-webrtc-web-client/browser-tests/.gitignore: -------------------------------------------------------------------------------- 1 | openteraWebrtcWebClient.js* 2 | -------------------------------------------------------------------------------- /opentera-webrtc-web-client/browser-tests/DataChannelClient/disconnectedDataChannelClient.spec.js: -------------------------------------------------------------------------------- 1 | const SignalingServerConfiguration = { 2 | url: 'ws://localhost:8080/signaling', 3 | name: '', 4 | room: 'chat', 5 | password: '' 6 | }; 7 | const DataChannelConfiguration = {}; 8 | const RtcConfiguration = {}; 9 | 10 | let dataChannelClient; 11 | 12 | describe('Disconnected DataChannelClient', () => { 13 | beforeEach(() => dataChannelClient = new window.openteraWebrtcWebClient.DataChannelClient(SignalingServerConfiguration, 14 | DataChannelConfiguration, RtcConfiguration)); 15 | 16 | it('isConnected should return false', () => { 17 | expect(dataChannelClient.isConnected).to.eql(false); 18 | }); 19 | it('isRtcConnected should return false', () => { 20 | expect(dataChannelClient.isRtcConnected).to.eql(false); 21 | }); 22 | it('id should return null', () => { 23 | expect(dataChannelClient.id).to.eql(null); 24 | }); 25 | it('connectedRoomClientIds should return []', () => { 26 | expect(dataChannelClient.connectedRoomClientIds).to.eql([]); 27 | }); 28 | it('roomClients should return []', () => { 29 | expect(dataChannelClient.roomClients).to.eql([]); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /opentera-webrtc-web-client/browser-tests/DataChannelClient/wrongPasswordDataChannelClient.spec.js: -------------------------------------------------------------------------------- 1 | describe('Wrong password DataChannelClient', () => { 2 | const SignalingServerConfiguration = { 3 | url: 'ws://localhost:8080/signaling', 4 | name: '', 5 | room: 'chat', 6 | password: '' 7 | }; 8 | const DataChannelConfiguration = {}; 9 | const RtcConfiguration = {}; 10 | 11 | it('connect should return an error', done => { 12 | let dataChannelClient = new window.openteraWebrtcWebClient.DataChannelClient(SignalingServerConfiguration, 13 | DataChannelConfiguration, RtcConfiguration); 14 | 15 | dataChannelClient.onSignalingConnectionOpen = () => { 16 | dataChannelClient.close(); 17 | assert.fail(); 18 | done(); 19 | }; 20 | dataChannelClient.onSignalingConnectionError = () => { 21 | expect(dataChannelClient.isConnected).to.eql(false); 22 | expect(dataChannelClient.isRtcConnected).to.eql(false); 23 | expect(dataChannelClient.id).to.eql(null); 24 | expect(dataChannelClient.connectedRoomClientIds).to.eql([]); 25 | expect(dataChannelClient.roomClients).to.eql([]); 26 | done(); 27 | }; 28 | 29 | dataChannelClient.connect(); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /opentera-webrtc-web-client/browser-tests/iceServers.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "urls": "stun:stun.l.google.com:19302" 4 | } 5 | ] 6 | -------------------------------------------------------------------------------- /opentera-webrtc-web-client/browser-tests/iceServers.spec.js: -------------------------------------------------------------------------------- 1 | describe('iceServers', () => { 2 | it('should get an empty array if the password is wrong', async () => { 3 | let iceServers = await window.openteraWebrtcWebClient.iceServers.fetchFromServer('http://localhost:8080/iceservers', ''); 4 | expect(iceServers).to.eql([]); 5 | }); 6 | it('should get an the array if the password is right', async () => { 7 | let iceServers = await window.openteraWebrtcWebClient.iceServers.fetchFromServer('http://localhost:8080/iceservers', 'abc'); 8 | expect(iceServers).to.eql([{ urls: "stun:stun.l.google.com:19302" }]); 9 | }); 10 | }); 11 | -------------------------------------------------------------------------------- /opentera-webrtc-web-client/browser-tests/run_browser_tests.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SCRIPT=`realpath $0` 4 | SCRIPT_PATH=`dirname $SCRIPT` 5 | 6 | cd $SCRIPT_PATH/.. 7 | npm install 8 | npm run build:umd 9 | 10 | cp $SCRIPT_PATH/../dist/openteraWebrtcWebClient.js* $SCRIPT_PATH 11 | 12 | cd $SCRIPT_PATH/../../signaling-server 13 | python3 opentera-signaling-server --port 8080 --password abc --ice_servers $SCRIPT_PATH/iceServers.json --static_folder $SCRIPT_PATH & 14 | SERVER_PID=$! 15 | trap "kill ${SERVER_PID}; exit 1" INT 16 | 17 | URL="http://localhost:8080/tests.html" 18 | 19 | 20 | if which xdg-open > /dev/null 21 | then 22 | xdg-open $URL 23 | elif which gnome-open > /dev/null 24 | then 25 | gnome-open $URL 26 | elif open > /dev/null 27 | then 28 | open $URL 29 | else 30 | echo "The OS is not supported" 31 | fi 32 | 33 | wait $SERVER_PID 34 | -------------------------------------------------------------------------------- /opentera-webrtc-web-client/browser-tests/tests.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 10 | 11 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /opentera-webrtc-web-client/index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./src').default; 2 | -------------------------------------------------------------------------------- /opentera-webrtc-web-client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "opentera-webrtc-web-client", 3 | "version": "1.0.0", 4 | "description": "opentera-webrtc-web-client", 5 | "main": "lib/Library.js", 6 | "files": [ 7 | "src/", 8 | "dist/", 9 | "lib/" 10 | ], 11 | "scripts": { 12 | "test": "browser-tests/run_browser_tests.bash", 13 | "lint": "eslint src/**/*.js", 14 | "build:umdmin": "webpack --mode=production --env output-library-target=umd", 15 | "build:umd": "webpack --mode=development --env output-library-target=umd", 16 | "build:commonjs": "webpack --mode=development --env output-library-target=commonjs2", 17 | "build": "npm-run-all build:*", 18 | "dev:umd": "webpack --progress --colors --watch --mode=development --env output-library-target=umd", 19 | "dev:commonjs": "webpack --progress --colors --watch --mode=development --env output-library-target=commonjs2", 20 | "dev": "npm-run-all --parallel dev:*", 21 | "clean": "rimraf dist lib coverage", 22 | "prepare": "npm-run-all clean build" 23 | }, 24 | "repository": { 25 | "type": "git", 26 | "url": "git+https://github.com/introlab/opentera-webrtc" 27 | }, 28 | "keywords": [], 29 | "author": "IntRoLab", 30 | "license": "Apache-2.0", 31 | "bugs": { 32 | "url": "https://github.com/introlab/opentera-webrtc/issues" 33 | }, 34 | "homepage": "https://github.com/introlab/opentera-webrtc#readme", 35 | "devDependencies": { 36 | "@babel/core": "^7.17.10", 37 | "@babel/plugin-proposal-object-rest-spread": "^7.17.3", 38 | "@babel/preset-env": "^7.17.10", 39 | "@babel/register": "^7.17.7", 40 | "babel-loader": "^8.2.5", 41 | "chai": "^4.3.6", 42 | "cross-env": "^6.0.3", 43 | "eslint": "^8.35.0", 44 | "eslint-config-google": "^0.14.0", 45 | "eslint-webpack-plugin": "^4.0.0", 46 | "mocha": "^10.0.0", 47 | "npm-run-all": "^4.1.5", 48 | "nyc": "^15.1.0", 49 | "rimraf": "^3.0.2", 50 | "sinon": "^7.5.0", 51 | "sinon-chai": "^3.5.0", 52 | "webpack": "^5.76.0", 53 | "webpack-cli": "^5.0.1", 54 | "yargs": "^17.7.1" 55 | }, 56 | "browserslist": "> 0.5%, last 2 versions, Firefox ESR, not dead", 57 | "dependencies": { 58 | "socket.io-client": "^4.6.1", 59 | "webrtc-adapter": "^8.2.1" 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /opentera-webrtc-web-client/src/devices.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @brief Enumerates all media devices. 3 | * @returns {Promise} 4 | */ 5 | async function enumerate() { 6 | if (!navigator.mediaDevices || !navigator.mediaDevices.enumerateDevices) { 7 | throw new Error('enumerateDevices() is not supported.'); 8 | } 9 | if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) { 10 | throw new Error('getUserMedia() is not supported.'); 11 | } 12 | 13 | await navigator.mediaDevices.getUserMedia({ audio: true, video: true }); 14 | return await navigator.mediaDevices.enumerateDevices(); 15 | } 16 | 17 | /** 18 | * @brief Gets a stream that satisfies the constraints. 19 | * @param {Object} constraints See https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia 20 | * @returns {Promise} 21 | */ 22 | async function getStream(constraints) { 23 | if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) { 24 | throw new Error('getUserMedia() is not supported.'); 25 | } 26 | 27 | return await navigator.mediaDevices.getUserMedia(constraints); 28 | } 29 | 30 | /** 31 | * @brief Gets the default audio and video stream. 32 | * @returns {Promise} 33 | */ 34 | async function getDefaultStream() { 35 | if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) { 36 | throw new Error('getUserMedia() is not supported.'); 37 | } 38 | 39 | return await navigator.mediaDevices.getUserMedia({ audio: true, video: true }); 40 | } 41 | 42 | /** 43 | * @brief Gets the default audio stream. 44 | * @returns {Promise} 45 | */ 46 | async function getDefaultAudioStream() { 47 | if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) { 48 | throw new Error('getUserMedia() is not supported.'); 49 | } 50 | 51 | return await navigator.mediaDevices.getUserMedia({ audio: true, video: false }); 52 | } 53 | 54 | /** 55 | * @brief Gets the default video stream. 56 | * @returns {Promise} 57 | */ 58 | async function getDefaultVideoStream() { 59 | if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) { 60 | throw new Error('getUserMedia() is not supported.'); 61 | } 62 | 63 | return await navigator.mediaDevices.getUserMedia({ audio: false, video: true }); 64 | } 65 | 66 | let devices = { 67 | enumerate, 68 | getStream, 69 | getDefaultStream, 70 | getDefaultAudioStream, 71 | getDefaultVideoStream 72 | }; 73 | 74 | export default devices; 75 | -------------------------------------------------------------------------------- /opentera-webrtc-web-client/src/iceServers.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @brief Gets the ice servers from the signaling server. 3 | * @param {String} url The signaling server ice servers address. 4 | * @param {String} password The signaling server password. 5 | * @returns {Promise} THe signaling server ice servers 6 | */ 7 | async function fetchFromServer(url, password) { 8 | let response = await fetch(url, { 9 | method: 'GET', 10 | headers: new Headers({ 'Authorization': password }) 11 | }); 12 | 13 | return await response.json(); 14 | } 15 | 16 | let iceServers = { 17 | fetchFromServer 18 | }; 19 | 20 | export default iceServers; 21 | -------------------------------------------------------------------------------- /opentera-webrtc-web-client/src/index.js: -------------------------------------------------------------------------------- 1 | import adapter from 'webrtc-adapter'; // eslint-disable-line 2 | 3 | import devices from './devices'; 4 | import iceServers from './iceServers'; 5 | import DataChannelClient from './DataChannelClient'; 6 | import StreamClient from './StreamClient'; 7 | import StreamDataChannelClient from './StreamDataChannelClient'; 8 | 9 | 10 | let openteraWebrtcWebClient = { 11 | devices, 12 | iceServers, 13 | DataChannelClient, 14 | StreamClient, 15 | StreamDataChannelClient 16 | }; 17 | 18 | export default openteraWebrtcWebClient; 19 | -------------------------------------------------------------------------------- /opentera-webrtc-web-client/webpack.config.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack'); 2 | const pkg = require('./package.json'); 3 | const ESLintPlugin = require('eslint-webpack-plugin'); 4 | 5 | const libraryName = 'openteraWebrtcWebClient'; 6 | 7 | const banner = `${pkg.name} 8 | ${pkg.description}\n 9 | @version v${pkg.version} 10 | @author ${pkg.author} 11 | @homepage ${pkg.homepage} 12 | @repository ${pkg.repository.url}`; 13 | 14 | const plugins = [ 15 | new webpack.BannerPlugin(banner), 16 | new ESLintPlugin() 17 | ]; 18 | 19 | module.exports = (env, options) => { 20 | const libraryTarget = env['output-library-target']; 21 | const mode = options['mode']; 22 | 23 | return { 24 | entry: `${__dirname}/index.js`, 25 | devtool: 'source-map', 26 | output: { 27 | path: `${__dirname}/${libraryTarget === 'umd' ? 'dist' : 'lib'}`, 28 | filename: mode === 'development' ? `${libraryName}.js` : `${libraryName}.min.js`, 29 | library: libraryName, 30 | libraryTarget: libraryTarget || 'umd', 31 | globalObject: '(typeof self !== \'undefined\' ? self : this)', // TODO Hack (for Webpack 4+) to enable create UMD build which can be required by Node without throwing error for window being undefined (https://github.com/webpack/webpack/issues/6522) 32 | umdNamedDefine: true 33 | }, 34 | module: { 35 | rules: [ 36 | { 37 | test: /(\.jsx|\.js)$/, 38 | loader: 'babel-loader', 39 | exclude: /(node_modules|bower_components)/ 40 | } 41 | ] 42 | }, 43 | plugins: plugins 44 | }; 45 | }; 46 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | sphinx==6.1.3 2 | pybind11-stubgen==0.12.0 3 | build==0.10.0 4 | -------------------------------------------------------------------------------- /signaling-server/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | venv/ 3 | tools/*.pem 4 | *.cpy 5 | __pycache__ 6 | -------------------------------------------------------------------------------- /signaling-server/README.md: -------------------------------------------------------------------------------- 1 | # Signaling Server 2 | 3 | TODO documentation 4 | -------------------------------------------------------------------------------- /signaling-server/_source/conf.py.in: -------------------------------------------------------------------------------- 1 | # Configuration file for the Sphinx documentation builder. 2 | # 3 | # This file only contains a selection of the most common options. For a full 4 | # list see the documentation: 5 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 6 | 7 | # -- Path setup -------------------------------------------------------------- 8 | 9 | # If extensions (or modules to document with autodoc) are in another directory, 10 | # add these directories to sys.path here. If the directory is relative to the 11 | # documentation root, use os.path.abspath to make it absolute, like shown here. 12 | # 13 | import os 14 | import sys 15 | sys.path.insert(0, os.path.abspath('../')) 16 | sys.path.insert(0, os.path.abspath('./theme')) 17 | sys.path.insert(0, os.path.abspath('../opentera_webrtc/signaling_server')) 18 | 19 | for path in sys.path: 20 | for prefix in "${PYTHON_HTML_IGNORE_PREFIXES}".split(";"): 21 | if prefix.strip() != "" and path.startswith(prefix): 22 | sys.path.remove(path) 23 | 24 | # -- Project information ----------------------------------------------------- 25 | 26 | project = 'OpenTera' 27 | copyright = '2022, IntRoLab' 28 | author = 'IntRoLab' 29 | 30 | # The full version, including alpha/beta/rc tags 31 | release = "${OPENTERA_WEBRTC_NATIVE_CLIENT_VERSION}" 32 | version = "${OPENTERA_WEBRTC_NATIVE_CLIENT_VERSION}" 33 | 34 | 35 | # -- General configuration --------------------------------------------------- 36 | 37 | # Add any Sphinx extension module names here, as strings. They can be 38 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 39 | # ones. 40 | extensions = [ 41 | "sphinx.ext.autodoc", 42 | "sphinx.ext.autosummary", 43 | "sphinx.ext.intersphinx", 44 | "sphinx.ext.todo", 45 | "sphinx.ext.viewcode", 46 | "sphinx.ext.napoleon", 47 | ] 48 | 49 | autodoc_member_order = 'bysource' 50 | autodoc_default_options = { 51 | 'members': True, 52 | 'undoc-members': True, 53 | 'show-inheritance': True, 54 | } 55 | add_module_names = False 56 | autosummry_generate = True 57 | autodoc_typehints_format = 'short' 58 | python_use_unqualified_type_names = True 59 | 60 | 61 | # Add any paths that contain templates here, relative to this directory. 62 | templates_path = ['_templates'] 63 | 64 | # List of patterns, relative to source directory, that match files and 65 | # directories to ignore when looking for source files. 66 | # This pattern also affects html_static_path and html_extra_path. 67 | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store', 'setup.py', 'theme'] 68 | 69 | 70 | # -- Options for HTML output ------------------------------------------------- 71 | 72 | # The theme to use for HTML and HTML Help pages. See the documentation for 73 | # a list of builtin themes. 74 | # 75 | html_theme = 'sphinx_rtd_theme' 76 | 77 | html_theme_options = { 78 | 79 | } 80 | 81 | html_logo = 'https://avatars.githubusercontent.com/u/1263458?s=200&v=4' 82 | 83 | # Add any paths that contain custom static files (such as style sheets) here, 84 | # relative to this directory. They are copied after the builtin static files, 85 | # so a file named "default.css" will overwrite the builtin "default.css". 86 | html_static_path = ['_static'] 87 | 88 | 89 | html_show_sourcelink = False 90 | html_show_copyright = True 91 | 92 | intersphinx_mapping = {'https://docs.python.org/3.10': None} 93 | -------------------------------------------------------------------------------- /signaling-server/_source/index.rst: -------------------------------------------------------------------------------- 1 | .. OpenTera documentation master file, created by 2 | sphinx-quickstart on Thu Mar 3 16:11:36 2022. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to OpenTera's documentation! 7 | ==================================== 8 | 9 | .. autosummary:: 10 | :toctree: _autosummary 11 | :recursive: 12 | 13 | opentera_webrtc 14 | 15 | 16 | Indices and tables 17 | ================== 18 | 19 | * :ref:`genindex` 20 | * :ref:`modindex` 21 | * :ref:`search` 22 | -------------------------------------------------------------------------------- /signaling-server/_source/theme/requirements.txt: -------------------------------------------------------------------------------- 1 | sphinx-rtd-theme==1.1.1 2 | charset-normalizer<3.0,>=2.0 3 | sphinx==5.3.0 4 | urllib3<2.0 5 | -------------------------------------------------------------------------------- /signaling-server/opentera-signaling-server: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3.8 2 | 3 | from opentera_webrtc.signaling_server.signaling_server import main 4 | 5 | 6 | if __name__ == '__main__': 7 | main() 8 | -------------------------------------------------------------------------------- /signaling-server/opentera_webrtc/signaling_server/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/introlab/opentera-webrtc/458277e9c1d17e9e1e1e6fe15394dee7e1329aa3/signaling-server/opentera_webrtc/signaling_server/__init__.py -------------------------------------------------------------------------------- /signaling-server/opentera_webrtc/signaling_server/web_socket_client_manager.py: -------------------------------------------------------------------------------- 1 | import uuid 2 | 3 | import asyncio 4 | 5 | 6 | class WebSocketClientManager: 7 | def __init__(self): 8 | self._ws_by_id = {} 9 | 10 | self._lock = None 11 | 12 | async def add_ws(self, ws): 13 | self._create_lock_if_none() 14 | async with self._lock: 15 | id = self._generate_id() 16 | self._ws_by_id[id] = ws 17 | return id 18 | 19 | async def close(self, id): 20 | self._create_lock_if_none() 21 | async with self._lock: 22 | if id in self._ws_by_id: 23 | await self._ws_by_id[id].close() 24 | del self._ws_by_id[id] 25 | 26 | async def close_all(self): 27 | self._create_lock_if_none() 28 | async with self._lock: 29 | asyncio.gather(*[ws.close() for ws in self._ws_by_id.values()]) 30 | self._ws_by_id.clear() 31 | 32 | async def send_to(self, message, ids): 33 | if isinstance(ids, str): 34 | ids = [ids] 35 | 36 | self._create_lock_if_none() 37 | async with self._lock: 38 | tasks = [] 39 | 40 | for id in ids: 41 | if id in self._ws_by_id and not self._ws_by_id[id].closed: 42 | tasks.append(asyncio.create_task(self._ws_by_id[id].send_str(message))) 43 | 44 | if len(tasks) == 0: 45 | return 46 | await asyncio.wait(tasks) 47 | 48 | async def send_to_all(self, message): 49 | self._create_lock_if_none() 50 | async with self._lock: 51 | tasks = [] 52 | 53 | for ws in self._ws_by_id.values(): 54 | if not ws.closed: 55 | tasks.append(asyncio.create_task(ws.send_str(message))) 56 | 57 | if len(tasks) == 0: 58 | return 59 | await asyncio.wait(tasks) 60 | 61 | async def list_ids(self): 62 | self._create_lock_if_none() 63 | async with self._lock: 64 | return list(self._ws_by_id.keys()) 65 | 66 | def _generate_id(self): 67 | return str(uuid.uuid4()) 68 | 69 | def _create_lock_if_none(self): 70 | if self._lock is None: 71 | self._lock = asyncio.Lock() 72 | -------------------------------------------------------------------------------- /signaling-server/opentera_webrtc/tests/__init__.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | 3 | from typing import Optional 4 | 5 | 6 | class AsyncRunner: 7 | def __init__(self, event_loop: Optional[asyncio.BaseEventLoop] = None) -> None: 8 | self.loop = event_loop or asyncio.new_event_loop() 9 | 10 | def run_async(self, coroutine): 11 | return self.loop.run_until_complete(coroutine) 12 | 13 | def __del__(self): 14 | self.loop.close() 15 | -------------------------------------------------------------------------------- /signaling-server/opentera_webrtc/tests/test_web_socket_client_manager.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from signaling_server.web_socket_client_manager import WebSocketClientManager 4 | from tests import AsyncRunner 5 | 6 | 7 | class WsMock: 8 | def __init__(self): 9 | self._closed = False 10 | self.messages = [] 11 | 12 | async def send_str(self, message): 13 | self.messages.append(message) 14 | 15 | async def close(self): 16 | self._closed = True 17 | 18 | @property 19 | def closed(self): 20 | return self._closed 21 | 22 | 23 | class TestRoomManager(unittest.TestCase): 24 | def _run_async(self, coroutine): 25 | return self.sync_runner.run_async(coroutine) 26 | 27 | def setUp(self): 28 | self._ws_manager = WebSocketClientManager() 29 | self.sync_runner = AsyncRunner() 30 | 31 | def test_add_ws(self): 32 | id1 = self._run_async(self._ws_manager.add_ws(WsMock())) 33 | id2 = self._run_async(self._ws_manager.add_ws(WsMock())) 34 | 35 | self.assertNotEqual(id1, id2) 36 | 37 | ids = self._run_async(self._ws_manager.list_ids()) 38 | self.assertEqual(len(ids), 2) 39 | self.assertIn(id1, ids) 40 | self.assertIn(id2, ids) 41 | 42 | def test_close(self): 43 | ws = WsMock() 44 | id = self._run_async(self._ws_manager.add_ws(ws)) 45 | self.assertIn(id, self._run_async(self._ws_manager.list_ids())) 46 | self.assertFalse(ws.closed) 47 | 48 | self._run_async(self._ws_manager.close(id)) 49 | self.assertNotIn(id, self._run_async(self._ws_manager.list_ids())) 50 | self.assertTrue(ws.closed) 51 | 52 | def test_send_to_send_to_all(self): 53 | ws1 = WsMock() 54 | ws2 = WsMock() 55 | ws3 = WsMock() 56 | ws4 = WsMock() 57 | self._run_async(ws4.close()) 58 | 59 | id1 = self._run_async(self._ws_manager.add_ws(ws1)) 60 | id2 = self._run_async(self._ws_manager.add_ws(ws2)) 61 | id3 = self._run_async(self._ws_manager.add_ws(ws3)) 62 | id4 = self._run_async(self._ws_manager.add_ws(ws4)) 63 | 64 | self._run_async(self._ws_manager.send_to('message1', [id1, id2])) 65 | self._run_async(self._ws_manager.send_to('message2', id3)) 66 | self._run_async(self._ws_manager.send_to('message3', id4)) 67 | self._run_async(self._ws_manager.send_to_all('message4')) 68 | 69 | self.assertEqual(ws1.messages, ['message1', 'message4']) 70 | self.assertEqual(ws2.messages, ['message1', 'message4']) 71 | self.assertEqual(ws3.messages, ['message2', 'message4']) 72 | self.assertEqual(ws4.messages, []) 73 | -------------------------------------------------------------------------------- /signaling-server/requirements.txt: -------------------------------------------------------------------------------- 1 | aiohttp==3.9.4 2 | aiohttp_index==0.1 3 | -------------------------------------------------------------------------------- /signaling-server/setup.py.in: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | import os 3 | 4 | def read_file(name): 5 | with open(name, "r", encoding="utf-8") as fh: 6 | return fh.read() 7 | 8 | 9 | def get_doc_files(): 10 | files = {} 11 | for root, _, filenames in os.walk('_doc'): 12 | for filename in filenames: 13 | rootless = root.replace('_doc', os.path.join('doc', 'opentera', 'webrtc', 'signaling_server')) 14 | if not rootless in files.keys(): 15 | files[rootless] = [] 16 | files[rootless].append(os.path.join(root, filename)) 17 | return list(files.items()) 18 | 19 | 20 | LONG_DESCRIPTION = read_file("README.md") 21 | REQUIREMENTS = read_file("requirements.txt").splitlines() 22 | DATA_FILES = [('', ["requirements.txt"])] 23 | $,DATA_FILES.extend(get_doc_files()),> 24 | 25 | setup( 26 | name="opentera_webrtc_signaling_server", 27 | version="${OPENTERA_WEBRTC_NATIVE_CLIENT_VERSION}", 28 | author="Marc-Antoine Maheux, Cedric Godin, Dominic Letourneau", 29 | author_email="marc-antoine.maheux@usherbrooke.ca, cedric.godin@usherbrooke.ca, dominic.letourneau@usherbrooke.ca", 30 | description="OpenTera WebRTC Signaling Server", 31 | long_description=LONG_DESCRIPTION, 32 | long_description_content_type="text/markdown", 33 | url="https://github.com/introlab/opentera-webrtc", 34 | packages=['opentera_webrtc.signaling_server'], 35 | classifiers=[ 36 | "Programming Language :: Python :: 3", 37 | "Development Status :: 4 - Beta", 38 | "License :: OSI Approved :: Apache Software License", 39 | "Operating System :: POSIX", 40 | ], 41 | license="Apache Software License", 42 | platforms=['linux_x86_64'], 43 | python_requires='>=3.8', 44 | data_files=DATA_FILES, 45 | include_package_data=True, 46 | zip_safe=False, 47 | install_requires=REQUIREMENTS, 48 | scripts=['opentera-signaling-server'], 49 | ) 50 | -------------------------------------------------------------------------------- /signaling-server/tools/generate_certificate.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365 -subj '/CN=localhost' -nodes 3 | # will return the exit code of the previous command 4 | exit 5 | --------------------------------------------------------------------------------