diff --git a/404.html b/404.html deleted file mode 100644 index 086a5c9..0000000 --- a/404.html +++ /dev/null @@ -1,25 +0,0 @@ ---- -permalink: /404.html -layout: default ---- - - - -
-

404

- -

Page not found :(

-

The requested page could not be found.

-
diff --git a/Gemfile b/Gemfile deleted file mode 100644 index 916fc3b..0000000 --- a/Gemfile +++ /dev/null @@ -1,32 +0,0 @@ -source "https://rubygems.org" -# Hello! This is where you manage which Jekyll version is used to run. -# When you want to use a different version, change it below, save the -# file and run `bundle install`. Run Jekyll with `bundle exec`, like so: -# -# bundle exec jekyll serve -# -# This will help ensure the proper Jekyll version is running. -# Happy Jekylling! -# gem "jekyll" -# If you want to use GitHub Pages, remove the "gem "jekyll"" above and -# uncomment the line below. To upgrade, run `bundle update github-pages`. -gem "webrick" -gem "github-pages", "~> 228", group: :jekyll_plugins -# If you have any plugins, put them here! -group :jekyll_plugins do - gem "jekyll-feed", "~> 0.12" -end - -# Windows and JRuby does not include zoneinfo files, so bundle the tzinfo-data gem -# and associated library. -platforms :mingw, :x64_mingw, :mswin, :jruby do - gem "tzinfo", ">= 1", "< 3" - gem "tzinfo-data" -end - -# Performance-booster for watching directories on Windows -gem "wdm", "~> 0.1.1", :platforms => [:mingw, :x64_mingw, :mswin] - -# Lock `http_parser.rb` gem to `v0.6.x` on JRuby builds since newer versions of the gem -# do not have a Java counterpart. -gem "http_parser.rb", "~> 0.6.0", :platforms => [:jruby] diff --git a/Gemfile.lock b/Gemfile.lock deleted file mode 100644 index 7b961d1..0000000 --- a/Gemfile.lock +++ /dev/null @@ -1,265 +0,0 @@ -GEM - remote: https://rubygems.org/ - specs: - activesupport (7.0.6) - concurrent-ruby (~> 1.0, >= 1.0.2) - i18n (>= 1.6, < 2) - minitest (>= 5.1) - tzinfo (~> 2.0) - addressable (2.8.5) - public_suffix (>= 2.0.2, < 6.0) - coffee-script (2.4.1) - coffee-script-source - execjs - coffee-script-source (1.11.1) - colorator (1.1.0) - commonmarker (0.23.10) - concurrent-ruby (1.2.2) - dnsruby (1.70.0) - simpleidn (~> 0.2.1) - em-websocket (0.5.3) - eventmachine (>= 0.12.9) - http_parser.rb (~> 0) - ethon (0.16.0) - ffi (>= 1.15.0) - eventmachine (1.2.7) - execjs (2.8.1) - faraday (2.7.10) - faraday-net_http (>= 2.0, < 3.1) - ruby2_keywords (>= 0.0.4) - faraday-net_http (3.0.2) - ffi (1.15.5) - forwardable-extended (2.6.0) - gemoji (3.0.1) - github-pages (228) - github-pages-health-check (= 1.17.9) - jekyll (= 3.9.3) - jekyll-avatar (= 0.7.0) - jekyll-coffeescript (= 1.1.1) - jekyll-commonmark-ghpages (= 0.4.0) - jekyll-default-layout (= 0.1.4) - jekyll-feed (= 0.15.1) - jekyll-gist (= 1.5.0) - jekyll-github-metadata (= 2.13.0) - jekyll-include-cache (= 0.2.1) - jekyll-mentions (= 1.6.0) - jekyll-optional-front-matter (= 0.3.2) - jekyll-paginate (= 1.1.0) - jekyll-readme-index (= 0.3.0) - jekyll-redirect-from (= 0.16.0) - jekyll-relative-links (= 0.6.1) - jekyll-remote-theme (= 0.4.3) - jekyll-sass-converter (= 1.5.2) - jekyll-seo-tag (= 2.8.0) - jekyll-sitemap (= 1.4.0) - jekyll-swiss (= 1.0.0) - jekyll-theme-architect (= 0.2.0) - jekyll-theme-cayman (= 0.2.0) - jekyll-theme-dinky (= 0.2.0) - jekyll-theme-hacker (= 0.2.0) - jekyll-theme-leap-day (= 0.2.0) - jekyll-theme-merlot (= 0.2.0) - jekyll-theme-midnight (= 0.2.0) - jekyll-theme-minimal (= 0.2.0) - jekyll-theme-modernist (= 0.2.0) - jekyll-theme-primer (= 0.6.0) - jekyll-theme-slate (= 0.2.0) - jekyll-theme-tactile (= 0.2.0) - jekyll-theme-time-machine (= 0.2.0) - jekyll-titles-from-headings (= 0.5.3) - jemoji (= 0.12.0) - kramdown (= 2.3.2) - kramdown-parser-gfm (= 1.1.0) - liquid (= 4.0.4) - mercenary (~> 0.3) - minima (= 2.5.1) - nokogiri (>= 1.13.6, < 2.0) - rouge (= 3.26.0) - terminal-table (~> 1.4) - github-pages-health-check (1.17.9) - addressable (~> 2.3) - dnsruby (~> 1.60) - octokit (~> 4.0) - public_suffix (>= 3.0, < 5.0) - typhoeus (~> 1.3) - html-pipeline (2.14.3) - activesupport (>= 2) - nokogiri (>= 1.4) - http_parser.rb (0.8.0) - i18n (1.14.1) - concurrent-ruby (~> 1.0) - jekyll (3.9.3) - addressable (~> 2.4) - colorator (~> 1.0) - em-websocket (~> 0.5) - i18n (>= 0.7, < 2) - jekyll-sass-converter (~> 1.0) - jekyll-watch (~> 2.0) - kramdown (>= 1.17, < 3) - liquid (~> 4.0) - mercenary (~> 0.3.3) - pathutil (~> 0.9) - rouge (>= 1.7, < 4) - safe_yaml (~> 1.0) - jekyll-avatar (0.7.0) - jekyll (>= 3.0, < 5.0) - jekyll-coffeescript (1.1.1) - coffee-script (~> 2.2) - coffee-script-source (~> 1.11.1) - jekyll-commonmark (1.4.0) - commonmarker (~> 0.22) - jekyll-commonmark-ghpages (0.4.0) - commonmarker (~> 0.23.7) - jekyll (~> 3.9.0) - jekyll-commonmark (~> 1.4.0) - rouge (>= 2.0, < 5.0) - jekyll-default-layout (0.1.4) - jekyll (~> 3.0) - jekyll-feed (0.15.1) - jekyll (>= 3.7, < 5.0) - jekyll-gist (1.5.0) - octokit (~> 4.2) - jekyll-github-metadata (2.13.0) - jekyll (>= 3.4, < 5.0) - octokit (~> 4.0, != 4.4.0) - jekyll-include-cache (0.2.1) - jekyll (>= 3.7, < 5.0) - jekyll-mentions (1.6.0) - html-pipeline (~> 2.3) - jekyll (>= 3.7, < 5.0) - jekyll-optional-front-matter (0.3.2) - jekyll (>= 3.0, < 5.0) - jekyll-paginate (1.1.0) - jekyll-readme-index (0.3.0) - jekyll (>= 3.0, < 5.0) - jekyll-redirect-from (0.16.0) - jekyll (>= 3.3, < 5.0) - jekyll-relative-links (0.6.1) - jekyll (>= 3.3, < 5.0) - jekyll-remote-theme (0.4.3) - addressable (~> 2.0) - jekyll (>= 3.5, < 5.0) - jekyll-sass-converter (>= 1.0, <= 3.0.0, != 2.0.0) - rubyzip (>= 1.3.0, < 3.0) - jekyll-sass-converter (1.5.2) - sass (~> 3.4) - jekyll-seo-tag (2.8.0) - jekyll (>= 3.8, < 5.0) - jekyll-sitemap (1.4.0) - jekyll (>= 3.7, < 5.0) - jekyll-swiss (1.0.0) - jekyll-theme-architect (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-cayman (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-dinky (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-hacker (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-leap-day (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-merlot (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-midnight (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-minimal (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-modernist (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-primer (0.6.0) - jekyll (> 3.5, < 5.0) - jekyll-github-metadata (~> 2.9) - jekyll-seo-tag (~> 2.0) - jekyll-theme-slate (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-tactile (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-time-machine (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-titles-from-headings (0.5.3) - jekyll (>= 3.3, < 5.0) - jekyll-watch (2.2.1) - listen (~> 3.0) - jemoji (0.12.0) - gemoji (~> 3.0) - html-pipeline (~> 2.2) - jekyll (>= 3.0, < 5.0) - kramdown (2.3.2) - rexml - kramdown-parser-gfm (1.1.0) - kramdown (~> 2.0) - liquid (4.0.4) - listen (3.8.0) - rb-fsevent (~> 0.10, >= 0.10.3) - rb-inotify (~> 0.9, >= 0.9.10) - mercenary (0.3.6) - minima (2.5.1) - jekyll (>= 3.5, < 5.0) - jekyll-feed (~> 0.9) - jekyll-seo-tag (~> 2.1) - minitest (5.19.0) - nokogiri (1.15.3-x86_64-linux) - racc (~> 1.4) - octokit (4.25.1) - faraday (>= 1, < 3) - sawyer (~> 0.9) - pathutil (0.16.2) - forwardable-extended (~> 2.6) - public_suffix (4.0.7) - racc (1.7.1) - rb-fsevent (0.11.2) - rb-inotify (0.10.1) - ffi (~> 1.0) - rexml (3.2.6) - rouge (3.26.0) - ruby2_keywords (0.0.5) - rubyzip (2.3.2) - safe_yaml (1.0.5) - sass (3.7.4) - sass-listen (~> 4.0.0) - sass-listen (4.0.0) - rb-fsevent (~> 0.9, >= 0.9.4) - rb-inotify (~> 0.9, >= 0.9.7) - sawyer (0.9.2) - addressable (>= 2.3.5) - faraday (>= 0.17.3, < 3) - simpleidn (0.2.1) - unf (~> 0.1.4) - terminal-table (1.8.0) - unicode-display_width (~> 1.1, >= 1.1.1) - typhoeus (1.4.0) - ethon (>= 0.9.0) - tzinfo (2.0.6) - concurrent-ruby (~> 1.0) - unf (0.1.4) - unf_ext - unf_ext (0.0.8.2) - unicode-display_width (1.8.0) - webrick (1.8.1) - -PLATFORMS - x86_64-linux - -DEPENDENCIES - github-pages (~> 228) - http_parser.rb (~> 0.6.0) - jekyll-feed (~> 0.12) - tzinfo (>= 1, < 3) - tzinfo-data - wdm (~> 0.1.1) - webrick - -BUNDLED WITH - 2.4.18 diff --git a/README.md b/README.md index bb033b6..967cff5 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,3 @@ # Elixir WebRTC Elixir WebRTC home page. - -To develop run - -``` -bundle install -bundle exec jekyll serve --livereload -``` \ No newline at end of file diff --git a/_config.yml b/_config.yml deleted file mode 100644 index 8c0aa75..0000000 --- a/_config.yml +++ /dev/null @@ -1,60 +0,0 @@ -# Welcome to Jekyll! -# -# This config file is meant for settings that affect your whole blog, values -# which you are expected to set up once and rarely edit after that. If you find -# yourself editing this file very often, consider using Jekyll's data files -# feature for the data you need to update frequently. -# -# For technical reasons, this file is *NOT* reloaded automatically when you use -# 'bundle exec jekyll serve'. If you change this file, please restart the server process. -# -# If you need help with YAML syntax, here are some quick references for you: -# https://learn-the-web.algonquindesign.ca/topics/markdown-yaml-cheat-sheet/#yaml -# https://learnxinyminutes.com/docs/yaml/ -# -# Site settings -# These are used to personalize your new site. If you look in the HTML files, -# you will see them accessed via {{ site.title }}, {{ site.email }}, and so on. -# You can create any custom variable you would like, and they will be accessible -# in the templates via {{ site.myvariable }}. - -title: Elixir WebRTC -email: michal.sledz@swmansion.com -description: >- # this means to ignore newlines until "baseurl:" - Rewrite Pion in Elixir -baseurl: "" # the subpath of your site, e.g. /blog -url: "" # the base hostname & protocol for your site, e.g. http://example.com -github_username: elixir-webrtc - -# Build settings -remote_theme: "riggraz/no-style-please" - -theme_config: - appearance: "light" - show_description: true - -plugins: - - jekyll-feed - -mermaid: - src: 'https://cdnjs.cloudflare.com/ajax/libs/mermaid/10.5.0/mermaid.min.js' - -# Exclude from processing. -# The following items will not be processed, by default. -# Any item listed under the `exclude:` key here will be automatically added to -# the internal "default list". -# -# Excluded items can be processed by explicitly listing the directories or -# their entries' file path in the `include:` list. -# -# exclude: -# - .sass-cache/ -# - .jekyll-cache/ -# - gemfiles/ -# - Gemfile -# - Gemfile.lock -# - node_modules/ -# - vendor/bundle/ -# - vendor/cache/ -# - vendor/gems/ -# - vendor/ruby/ diff --git a/_data/menu.yml b/_data/menu.yml deleted file mode 100644 index 6c97681..0000000 --- a/_data/menu.yml +++ /dev/null @@ -1,56 +0,0 @@ -# For documentation on this file, see: -# https://github.com/riggraz/no-style-please#customize-the-menu - -entries: - - title: Are we there yet? Yes! Elixir WebRTC 0.1.0 is out! - entries: - - title: "[x] PeerConnection" - - title: "[ ] SCTP" - - title: "[x] SRTP" - - title: "[x] RTP" - - title: "[x] RTCP" - - title: "[x] SDP" - - title: "[x] DTLS" - - title: "[x] ICE" - - title: "[x] TURN" - - title: "[x] STUN" - - - title: Reco - Phoenix app for real-time image recognition using Elixir WebRTC and Elixir Nx - url: https://github.com/elixir-webrtc/reco - - - title: Rel - Pure Elixir, publicly available TURN server - url: rel - - - title: FAQ - entries: - - title: ICE - url: faq/ice - - - title: Elixir WebRTC Resources - entries: - - title: Rewrite Pion in Elixir - RTC.ON slides (10.2023) - url: resources/rewrite_pion_in_elixir_rtcon_2023.pdf - - title: Rewrite Pion in Elixir - RTC.ON talk (10.2023) - url: https://www.youtube.com/watch?v=64yXjGZnU1k - - title: Rewrite Pion in Elixir - ElixirConf slides (09.2023) - url: resources/rewrite_pion_in_elixir_elixirconfus_2023.pdf - - title: Rewrite Pion in Elixir - ElixirConf Talk (09.2023) - url: https://www.youtube.com/watch?v=4XaB4XWg-Qg - - - title: WebRTC Resources - entries: - - title: Plan B vs Unified Plan - url: https://docs.google.com/document/d/1-ZfikoUtoJa9k-GZG1daN0BU3IjIanQ_JSscHxQesvU/edit - - title: The evolution of WebRTC 1.0 - url: https://blog.mozilla.org/webrtc/the-evolution-of-webrtc/ - - title: Exploring RTCRtpTransceiver - url: https://blog.mozilla.org/webrtc/rtcrtptransceiver-explored/ - - title: W3C IRC (channel webrtc) - url: https://irc.w3.org/ - - title: W3C WebRTC Meeting slides - url: https://www.w3.org/2011/04/webrtc/wiki/Main_Page - - - title: Contact - entries: - - title: "michal.sledz at swmansion.com" - - title: "lukasz.wala at swmansion.com" diff --git a/assets/css/main.scss b/assets/css/main.scss deleted file mode 100644 index 665ab93..0000000 --- a/assets/css/main.scss +++ /dev/null @@ -1,4 +0,0 @@ ---- ---- - -@import "no-style-please"; \ No newline at end of file diff --git a/faq/ice.md b/faq/ice.md deleted file mode 100644 index 3244be3..0000000 --- a/faq/ice.md +++ /dev/null @@ -1,96 +0,0 @@ ---- -layout: page -title: FAQ ICE ---- - -1. [Should we filter out bridges (like those created by docker) when gathering host candidates?](#1) -2. [When conn check req and resp address might not be symmetric? sec 7.2.5.2.1](#2) -3. [How does iptables work? (In particular NAT table, and MASQUERADE and DNAT targets)](#3) -4. [Is it actually possible to have srflx candidate? reflexive candidates are replaced by their bases and pruned if redundant - see section 6.1.2.4](#4) -5. [Is it possible to connect ice outside docker with ice inside docker?](#5) -6. [Is it possible for initial pair state to be different than :waiting when we have only one checklist?](#6) -7. [Is it possible not to prune some srflx candidate - sec 6.1.2.4?](#7) -8. [Is it possible to receive binding response to binding request with USE-CANDIDATE that will result in creating a new valid pair? sec 7.2.5.3.4](#8) -9. [A Trickle ICE agent MUST NOT pair a local candidate until it has been trickled to the remote party. How can we know that the candidate has been trickled to the remote party? Does any implementation exposes in its API ability to mark the candidate as trickled?](#9) -10. [What data use for keepalives and how often?](#10) -11. [Can ICE be restarted before completing?](#11) -12. [Can we send data on valid pair before regular nomination in RFC 5245?](#12) -13. [Why does chrome allocate only one ICE candidate?](#13) -14. [What is default local address?](#14) - - -### 1. Should we filter out bridges (like those created by docker) when gathering host candidates? - -### 2. When conn check req and resp address might not be symmetric? sec 7.2.5.2.1 - -### 3. How does iptables work? (In particular NAT table, and MASQUERADE and DNAT targets) - -### 4. Is it actually possible to have srflx candidate? reflexive candidates are replaced by their bases and pruned if redundant - see section 6.1.2.4 - -### 5. Is it possible to connect ice outside docker with ice inside docker? - -### 6. Is it possible for initial pair state to be different than :waiting when we have only one checklist? - -Yes, consider scenario where remote peer sends us two the same srflx candidates that differ in ports only. Remote can obtain two srflx candidates when it has multiple local interfaces or has docker bridges on its system. RFC doesnt seem to say we should filter out "redundant" candidates. - -### 7. Is it possible not to prune some srflx candidate - sec 6.1.2.4? - -### 8. Is it possible to receive binding response to binding request with USE-CANDIDATE that will result in creating a new valid pair? sec 7.2.5.3.4 - -### 9. A Trickle ICE agent MUST NOT pair a local candidate until it has been trickled to the remote party. How can we know that the candidate has been trickled to the remote party? Does any implementation exposes in its API ability to mark the candidate as trickled? - -### 10. What data use for keepalives and how often? - -Chrome seems to send binding requests every 2-2.5s which is a discouraged behavior -according to appendinx B.8 of RFC 8445. -Chrome also sends those keepalives even when the data is flowing which is also -an opposite behavior comparing to what RFC says. -Pion seems to send Binding Indications 2 seconds after there is no traffic. -In general, we should send Binding Indications and only when there is no media traffic. -RFC says that we should send keepalives after 15 seconds of inactivity. -"Though Binding Indications are used for -keepalives, an agent MUST be prepared to receive a connectivity check -as well. If a connectivity check is received, a response is -generated as discussed in [RFC5389], but there is no impact on ICE -processing otherwise." - -### 11. Can ICE be restarted before completing? - -### 12. Can we send data on valid pair before regular nomination in RFC 5245? - -### 13. Why does chrome allocate only one ICE candidate? - -Chrome operates on ADAPTER_ENUMERATION flag. When ADAPTER_ENUMERATION is enabled, chrome -will search for local NIC and create candidates. When ADAPTER_ENUMERATION is disabled or -the process of searching local NIC fails, chrome uses INADDR_ANY i.e. 0.0.0.0 address as its -only candidate. When the ADAPTER_ENUMERATION can be blocked? The comment from basic_port_allocator -says: - -``` -If the adapter enumeration is disabled, we'll just bind to any address instead of specific NIC. This is to ensure the same routing for http traffic by OS is also used here to avoid any local or public IP leakage during stun process. -``` - -so this might have something to do with the http traffic. - -This might have also something to do with private networks or at least when no STUN or TURN -server is provided. From stun_port.cc - -``` -When adapter enumeration is disabled and binding to the any address, the default local address will be issued as a candidate instead if `emit_local_for_anyaddress` is true. This is to allow connectivity for applications which absolutely requires a HOST candidate. -``` - -How the 0.0.0.0 is transported to the peer? -Which address is used when sending data from a socket listening on 0.0.0.0? - -Possibly using default local address. Refer to what is default local address". - -See basic_port_allocator.cc and network.cc files for reference. -[[click]](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/p2p/client/basic_port_allocator.cc;l=741?q=basic_port_a&ss=chromium) - -### 14. What is default local address? - -From network.h - -``` -The default local address is the local address used in multi-homed endpoint when the any address (0.0.0.0 or ::) is used as the local address. It's important to check the return value as a IP family may not be enabled. -``` \ No newline at end of file diff --git a/fonts/Aeonik-Bold.ttf b/fonts/Aeonik-Bold.ttf new file mode 100644 index 0000000..ff4253e Binary files /dev/null and b/fonts/Aeonik-Bold.ttf differ diff --git a/fonts/Aeonik-Medium.ttf b/fonts/Aeonik-Medium.ttf new file mode 100644 index 0000000..2bd6a5f Binary files /dev/null and b/fonts/Aeonik-Medium.ttf differ diff --git a/fonts/Aeonik-Regular.ttf b/fonts/Aeonik-Regular.ttf new file mode 100644 index 0000000..8b4a766 Binary files /dev/null and b/fonts/Aeonik-Regular.ttf differ diff --git a/fonts/Roc-Grotesk-Medium.otf b/fonts/Roc-Grotesk-Medium.otf new file mode 100644 index 0000000..88b2be0 Binary files /dev/null and b/fonts/Roc-Grotesk-Medium.otf differ diff --git a/img/arrowright.svg b/img/arrowright.svg new file mode 100644 index 0000000..407d554 --- /dev/null +++ b/img/arrowright.svg @@ -0,0 +1,4 @@ + + + + diff --git a/img/broadcaster.svg b/img/broadcaster.svg new file mode 100644 index 0000000..f5ac889 --- /dev/null +++ b/img/broadcaster.svg @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/img/demos.svg b/img/demos.svg new file mode 100644 index 0000000..99d1461 --- /dev/null +++ b/img/demos.svg @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/img/elixir-webrtc.svg b/img/elixir-webrtc.svg new file mode 100644 index 0000000..87cc795 --- /dev/null +++ b/img/elixir-webrtc.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/img/examples.svg b/img/examples.svg new file mode 100644 index 0000000..f0c57e0 --- /dev/null +++ b/img/examples.svg @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/img/favicon.ico b/img/favicon.ico new file mode 100644 index 0000000..6ec8905 Binary files /dev/null and b/img/favicon.ico differ diff --git a/img/github-logo.svg b/img/github-logo.svg new file mode 100644 index 0000000..ef3372a --- /dev/null +++ b/img/github-logo.svg @@ -0,0 +1,3 @@ + + + diff --git a/img/hero-logo-large.svg b/img/hero-logo-large.svg new file mode 100644 index 0000000..f77e983 --- /dev/null +++ b/img/hero-logo-large.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/img/hero-logo-small.svg b/img/hero-logo-small.svg new file mode 100644 index 0000000..5a5b2fb --- /dev/null +++ b/img/hero-logo-small.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/img/logo.svg b/img/logo.svg new file mode 100644 index 0000000..ee476ef --- /dev/null +++ b/img/logo.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/img/membrane.svg b/img/membrane.svg new file mode 100644 index 0000000..7ab832d --- /dev/null +++ b/img/membrane.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/img/menu.svg b/img/menu.svg new file mode 100644 index 0000000..8d23ac8 --- /dev/null +++ b/img/menu.svg @@ -0,0 +1,3 @@ + + + diff --git a/img/nexus.svg b/img/nexus.svg new file mode 100644 index 0000000..f4d6f4f --- /dev/null +++ b/img/nexus.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/img/observability.svg b/img/observability.svg new file mode 100644 index 0000000..546eb35 --- /dev/null +++ b/img/observability.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/img/recognizer.svg b/img/recognizer.svg new file mode 100644 index 0000000..58ef276 --- /dev/null +++ b/img/recognizer.svg @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/img/simulcast.svg b/img/simulcast.svg new file mode 100644 index 0000000..1bc3989 --- /dev/null +++ b/img/simulcast.svg @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/img/swm.svg b/img/swm.svg new file mode 100644 index 0000000..a296681 --- /dev/null +++ b/img/swm.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/img/tutorials.svg b/img/tutorials.svg new file mode 100644 index 0000000..c928dd7 --- /dev/null +++ b/img/tutorials.svg @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/img/whipwhep.svg b/img/whipwhep.svg new file mode 100644 index 0000000..464f6be --- /dev/null +++ b/img/whipwhep.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/img/xav.svg b/img/xav.svg new file mode 100644 index 0000000..9d82886 --- /dev/null +++ b/img/xav.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/index.html b/index.html new file mode 100644 index 0000000..6b2d861 --- /dev/null +++ b/index.html @@ -0,0 +1,287 @@ + + + + + + + + Elixir WebRTC + + + + +
+ +
+
+
+
+
+
+ +

A batteries-included WebRTC implementation for the Elixir ecosystem.

+
+ +
+
+
+ +
+
+ +
+
+
+
+
+
+
Demos
+
+
+
+ +
Recognizer
+
A simple app performing real-time image recognition.
+
+
    +
  • Phoenix Framework
  • +
  • Elixir WebRTC
  • +
  • Elixir Nx
  • +
+
+ +
+
+
+
+ +
Broadcaster
+
WHIP/WHEP Twitch-like real-time streaming service with a built-in streaming + panel. +
+
+
    +
  • Phoenix Framework
  • +
  • Elixir WebRTC
  • +
+
+ +
+
+
+
+ +
Nexus
+
A single-room video conferencing app.
+
+
    +
  • Phoenix Framework
  • +
  • Elixir WebRTC
  • +
+
+ +
+
+
+
+
+
+
+
+
+
Recognizer live coding
+
+

Learn in less than 6 minutes how to:

+
    +
  • send audio and video from a web browser to a Phoenix based web app using Elixir + WebRTC +
  • +
  • unpack and decode it using Xav
  • +
  • feed it into Elixir Nx to perform image + recognition
  • +
+

Everything in pure Elixir!

+
+
+
+ +
+
+
+
+
+
+
Features
+
+ Elixir WebRTC aims to provide you with all the pieces needed to create fully functional real-time + audio/video applications. + Use it with Phoenix, Membrane, or Elixir Nx without a hassle. +
+
+
+
+ +
+
Observability
+
Dedicated, easy to integrate with Phoenix, dashboard that provides server-side + webrtc-internals.
+
+
+
+
+
+ +
+
Simulcast
+
Support for multiple inbound resolutions that allows you to chose video + quality of your preference.
+
+
+
+
+
+ +
+
Xav
+
Library for audio/video decoding that makes it easy to feed data into Elixir + Nx. +
+
+
+
+
+
+ +
+
Tutorials
+
A series of tutorials introducing you to both WebRTC and Elixir WebRTC.
+
+
+
+
+
+ +
+
Membrane Ready
+
Sink and Source elements for the Membrane Framework.
+
+
+
+
+
+ +
+
Demo Applications
+
Multiple demo applications deployed 24/7 for testing and experimental + purposes.
+
+
+
+
+
+ +
+
Examples
+
Simple examples presenting API usage, ready to be run locally.
+
+
+
+
+
+ +
+
WHIP/WHEP Ready
+
Stream directly from OBS to an Elixir WebRTC based app.
+
+
+
+
+
+
+
+
+
Talks
+
Want to know more? See our conference talks!
+
+ + + +
+
+
+
+ + + + + + \ No newline at end of file diff --git a/index.markdown b/index.markdown deleted file mode 100644 index 0671507..0000000 --- a/index.markdown +++ /dev/null @@ -1,6 +0,0 @@ ---- -# Feel free to add content and custom Front Matter to this file. -# To modify the layout, see https://jekyllrb.com/docs/themes/#overriding-theme-defaults - -layout: home ---- diff --git a/rel.md b/rel.md deleted file mode 100644 index 6856a11..0000000 --- a/rel.md +++ /dev/null @@ -1,67 +0,0 @@ ---- -layout: page -title: Rel - Pure Elixir, publicly available TURN server ---- - -[Rel](https://github.com/elixir-webrtc/rel.git) is publicly available for tests and experiments. -Just execute a simple POST request to obtain your credentials -and copy-paste them into [RTCPeerConnection](https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/RTCPeerConnection) constructor. - -```sh -$ curl -X POST "https://turn.bigcow.ovh/?service=turn&username=johnsmith" -{ - "password":"l6hs9SzUgudFeb5XjrfCfOWKeOQ=", - "ttl":1728, - "uris":["turn:167.235.241.140:3478?transport=udp"], - "username":"1691574817:johnsmith" -} -``` - -```js -pc = new RTCPeerConnection({ - iceServers: [ - { - credential: "l6hs9SzUgudFeb5XjrfCfOWKeOQ=", - urls: "turn:167.235.241.140:3478?transport=udp", - username: "1691574817:johnsmith" - } - ] -}); -``` - -## Benchmarks - -We have **N** connections, where every connection consists of one client and one peer. -A client creates an allocation, a peer starts sending data through this allocation to the client -and the client echo back this data to the peer. - -Questions we wanted to answer: -1. How many such connections are we able to handle? -1. How big bitrates are we able to handle? -1. What is the impact of datagram payload size on the TURN server performance? - -### Testbed - -* Rel version: 0.2.0 -* coTURN version: 4.5.2 -* eturnal version: 1.11.1 -* TURN server machine: AMD EPYC 7502P 32-Core Processor -* Clients and Peers machine: AMD EPYC 7502P 32-Core Processor -* RAM: 126 GB -* Connection link: 10 Gbbps - -### Results - -| Conns | Bitrate in one direction (kbps) | Payload (bytes) | Overall Bitrate (Mbps) | Rel (Elixir) | coTURN (C) | eturnal (Erlang) | -| :-: | :-: | :-: | :-: | :-: | :-: | :-: | -| 2000 | 50 | 150 | 400 | 25% | 10% | ? | -| 2000 | 50 | 1200 | 400 | 2-4% | 1.3% | ? | -| 1000 | 1500 | 1200 | 5200 | 45% | 15% | crashes | - - -Notes: -* **?** means that eturnal was not able to create more than 1000 connections -* **crashes** means that eturnal was not able to read incoming data fast enough, -which resulted in a packet loss. -This doesn't mean that the CPU usage was high. - diff --git a/resources/rewrite_pion_in_elixir_elixirconfus_2023.pdf b/resources/rewrite_pion_in_elixir_elixirconfus_2023.pdf deleted file mode 100644 index e80b68a..0000000 Binary files a/resources/rewrite_pion_in_elixir_elixirconfus_2023.pdf and /dev/null differ diff --git a/resources/rewrite_pion_in_elixir_rtcon_2023.pdf b/resources/rewrite_pion_in_elixir_rtcon_2023.pdf deleted file mode 100644 index f5c281d..0000000 Binary files a/resources/rewrite_pion_in_elixir_rtcon_2023.pdf and /dev/null differ diff --git a/script.js b/script.js new file mode 100644 index 0000000..c69f2f5 --- /dev/null +++ b/script.js @@ -0,0 +1,11 @@ +function toggleMenu() { + const menuContent = document.getElementById("navbar-menu-content"); + if (window.getComputedStyle(menuContent).display !== "none") { + menuContent.style.display = "none"; + } else { + menuContent.style.display = "flex"; + } +} + +document.getElementById("navbar-menu").onclick = toggleMenu; +document.getElementById("navbar-menu-list").onclick = toggleMenu; \ No newline at end of file diff --git a/styles.css b/styles.css new file mode 100644 index 0000000..571921c --- /dev/null +++ b/styles.css @@ -0,0 +1,682 @@ +@font-face { + font-family: "Roc Grotesk-Medium"; + font-style: normal; + font-weight: 500; + src: url("./fonts/Roc-Grotesk-Medium.otf") format("opentype"); +} + +@font-face { + font-family: "Aeonik-Medium"; + font-style: normal; + font-weight: 500; + src: url("./fonts/Aeonik-Medium.ttf") format("truetype"); +} + +@font-face { + font-family: "Aeonik-Regular"; + font-style: normal; + font-weight: 400; + src: url("./fonts/Aeonik-Regular.ttf") format("truetype"); +} + +@font-face { + font-family: "Aeonik-Bold"; + font-style: normal; + font-weight: 700; + src: url("./fonts/Aeonik-Bold.ttf") format("truetype"); +} + +:root { + --colorsviolet100: #4239ac; + --colorsviolet20: #f6f5fe; + --colorsviolet40: #d2cffd; + --lighttext-colorsnavy-100: #001a72; + + --font-family-aeonik-bold: "Aeonik-Bold", Helvetica; + --font-family-aeonik-medium: "Aeonik-Medium", Helvetica; + --font-family-aeonik-regular: "Aeonik-Regular", Helvetica; + --font-family-roc_grotesk-medium: "Roc Grotesk-Medium", Helvetica; + + --font-size-xs: 12px; + --font-size-s: 14px; + --font-size-m: 16px; + --font-size-l: 18px; + --font-size-xl: 20px; + --font-size-xxl: 24px; + --font-size-xxxl: 32px; +} + +/* from https://stackoverflow.com/a/38994837/9620900 */ +/* Hiding scrollbar for Chrome, Safari and Opera */ +::-webkit-scrollbar { + display: none; +} + +/* Use border-box globally */ +html { + box-sizing: border-box; +} + +header { + overflow-x: hidden; +} + +main { + overflow-x: hidden; +} + +*, +*:before, +*:after { + box-sizing: inherit; +} + +/* Default stylesheet sets body margin to 8px */ +body { + margin: 0; +} + +li span { + /* Reduce space between bullet point, which is by default set to + margin-right: 14px, and
  • 's contet */ + position: relative; + left: -6px; +} + +a { + text-decoration: none; +} + +.lc a { + text-decoration: underline; +} + +a:visited { + color: inherit; +} + +.section-header { + font-family: var(--font-family-aeonik-medium); + font-size: var(--font-size-xxl); + font-style: normal; + font-weight: 500; + color: var(--colorsviolet100); +} + +.container { + display: flex; + margin-left: auto; + margin-right: auto; + max-width: 1120px; + width: 100%; + justify-content: center; + padding: 45px 20px; +} + +.btn { + cursor: pointer; +} + +/* navbar */ +.navbar-outer { + display: flex; + justify-content: center; + width: 100%; + background-color: var(--colorsviolet20); +} + +.navbar { + justify-content: space-between; + flex-wrap: wrap; + padding: 30px 20px; + max-width: 1440px; +} + +.navbar-left { + display: flex; + align-items: center; + color: var(--colorsviolet100); + font-family: var(--font-family-roc_grotesk-medium); + font-size: var(--font-size-xl); + text-wrap: nowrap; +} + +.navbar-left-txt { + display: none; +} + +.navbar-mid { + display: none; + color: var(--colorsviolet100); + font-family: var(--font-family-aeonik-medium); + font-size: var(--font-size-l); +} + +.navbar-right { + display: none; + color: var(--colorsviolet100); + font-family: var(--font-family-aeonik-medium); + font-size: var(--font-size-xl); +} + +.navbar-menu { + display: flex; + align-items: center; +} + +.navbar-menu-content { + width: 100%; + display: none; +} + +.navbar-menu-content ul { + position: absolute; + display: flex; + z-index: 1; + left: 0; + background-color: var(--colorsviolet20); + flex-direction: column; + align-items: center; + width: 100%; + list-style-type: none; + padding: 0; +} + +.navbar-menu-content ul li { + padding: 15px; + font-family: var(--font-family-aeonik-medium); + font-size: var(--font-size-xl); + color: var(--colorsviolet100); + +} + +/* hero */ +.hero-outer { + display: flex; + justify-content: center; + width: 100%; + background-color: var(--colorsviolet20); + align-items: center; +} + +.hero { + padding-bottom: 75px; +} + +.hero-logo { + max-width: 300px; + max-height: 48px; +} + +.hero-left { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + gap: 50px; +} + +.hero-right { + display: none; +} + +.hero-button { + border-radius: 10px; + border: 1px solid; + border-color: var(--colorsviolet100); + background-color: var(--colorsviolet100); + width: max-content; + color: #ffffff; + font-family: var(--font-family-aeonik-medium); + font-size: var(--font-size-l); +} + +.hero-button-link { + padding: 10px 20px; + display: flex; + gap: 16px; + text-decoration: none; + align-items: center; + width: 100%; + height: 100%; +} + +.hero-copy { + display: flex; + flex-direction: column; + align-items: center; + gap: 50px +} + +.hero-copy-font { + font-family: var(--font-family-aeonik-regular); + font-size: var(--font-size-xxl); + color: var(--colorsviolet100); + font-weight: 400; + /* TODO revisit letter-spacing */ + letter-spacing: 0.64px; + text-align: center; +} + +.hero-logo-small { + margin-bottom: -30%; + margin-left: 35%; +} + +/* demos */ +.demo ul { + /* Place bullet points close to
  • 's content */ + list-style-position: inside; + padding: 0; +} + +.demos-outer { + width: 100%; + background-color: #D2CFFD80; + /* background: linear-gradient(183.02deg, rgba(255, 255, 255, 0) -24.48%, rgba(104, 91, 242, 0.3) 103.09%), rgba(210, 207, 253, 0.5); */ + /* background: linear-gradient(183.02deg, rgba(255, 255, 255, 0) -24.48%, rgba(104, 91, 242, 0.3) 103.09%), #D2CFFD50; */ +} + +.demos { + flex-direction: column; + gap: 30px; +} + +.demos-tiles { + display: flex; + gap: 25px; + overflow-x: scroll; + /* Hide scrollbar for Firefox, IE and Edge. + For Chrome, Safari and Opera, this is done globally on webkit */ + scrollbar-width: none; + /* Firefox */ + -ms-overflow-style: none; + /* IE and Edge */ +} + +.shadow-box { + /* Create some space for shadow, + it will be added in .demo class. */ + padding-bottom: 10px; + padding-right: 10px; +} + +.demo { + width: 230px; + height: 400px; + padding: 25px 20px; + display: flex; + flex-direction: column; + align-items: center; + text-align: center; + background: #FFFFFF; + border-radius: 20px; + color: var(--colorsviolet100); + justify-content: space-between; + box-shadow: 6px 6px 4px rgba(210, 207, 253, 0.5); +} + +.demo-img { + width: 60px; + height: 60px; +} + +.demo-title { + font-family: var(--font-family-aeonik-bold); + font-size: var(--font-size-xl); + line-height: 120%; +} + +.demo-desc { + font-family: var(--font-family-aeonik-regular); + font-size: var(--font-size-m); + line-height: 160%; +} + +.demo-stack { + font-family: var(--font-family-aeonik-regular); + font-size: var(--font-size-s); + line-height: 140%; +} + +.demo-button { + display: flex; + width: 150px; + height: 45px; + color: #FFFFFF; + font-family: var(--font-family-aeonik-medium); + font-size: var(--font-size-l); + font-style: normal; + background-color: var(--colorsviolet100); + border-radius: 10px; + align-items: center; + justify-content: center; +} + +/* live-coding */ +.lc ul { + padding-left: 30px; +} + +.lc-outer { + width: 100%; + background-color: #FFFFFF; +} + +.lc { + flex-direction: column; + gap: 10px; +} + +.lc-content { + display: flex; + flex-direction: column; + gap: 30px; +} + +.lc-desc { + font-family: var(--font-family-aeonik-regular); + font-size: var(--font-size-m); + font-style: normal; + font-weight: 400; + line-height: 160%; + color: var(--colorsviolet100); + display: flex; + flex-direction: column; + gap: 30px; + flex: 1; +} + +.lc-video { + flex-grow: 1; + flex-shrink: 1; + flex-basis: 1; + height: 219px; + max-width: 640px; +} + +.lc-video-iframe { + width: 100%; + height: 100%; + border-radius: 20px; +} + +/* features */ +.features-outer { + width: 100%; + background-color: var(--colorsviolet20); +} + +.features { + flex-direction: column; + gap: 30px; +} + +.features-desc { + font-family: var(--font-family-aeonik-regular); + font-size: var(--font-size-m); + font-style: normal; + font-weight: 400; + color: var(--colorsviolet100); + line-height: 160%; +} + +.features-tiles { + display: flex; + flex-wrap: wrap; + gap: 25px; +} + +.feature { + display: flex; + gap: 20px; + align-items: start; + /* FIXME this doesn't work for small tiles */ + max-width: 500px; + padding: 20px 20px; + background-color: #FFFFFF; + box-shadow: 3px 5px 4px rgba(210, 207, 253, 0.5); + border-radius: 10px; +} + +.feature-img { + width: 50px; + height: 50px; +} + +.feature-content { + display: flex; + flex-direction: column; + gap: 10px; +} + +.feature-title { + color: var(--colorsviolet100); + font-family: var(--font-family-aeonik-bold); + font-size: var(--font-size-l); + font-style: normal; + font-weight: 700; + line-height: 130%; + /* text-align: center; */ +} + +.feature-desc { + font-family: var(--font-family-aeonik-regular); + font-size: var(--font-size-m); + font-style: normal; + font-weight: 400; + line-height: 160%; + /* text-align: center; */ + color: var(--colorsviolet100); +} + +/* talks */ +.talks-outer { + background-color: #FFFFFF; +} + +.talks { + flex-direction: column; + gap: 30px; +} + +.talks-tiles { + display: flex; + gap: 25px; + overflow-x: scroll; + /* Hide scrollbar for Firefox, IE and Edge. + For Chrome, Safari and Opera, this is done globally on webkit */ + scrollbar-width: none; + /* Firefox */ + -ms-overflow-style: none; + /* IE and Edge */ +} + +.talk-iframe { + border-radius: 5px; +} + +.footer-outer { + width: 100%; + background: linear-gradient(360deg, #675AF1 -135%, #FFFFFF 68.33%); +} + +.footer { + gap: 20px; + align-items: center; + display: flex; + margin-left: auto; + margin-right: auto; + max-width: 1120px; + width: 100%; + justify-content: center; + padding: 20px 20px; + font-family: var(--font-family-aeonik-regular); + font-size: var(--font-size-xs); + font-style: normal; + font-weight: 400; + letter-spacing: 0; + color: var(--lighttext-colorsnavy-100); +} + +.footer-img { + width: 45px; +} + +@media (min-width: 1024px) { + .arrow-right { + stroke: var(--colorsviolet100); + } + + .section-header { + font-size: var(--font-size-xxxl); + } + + .container { + padding: 78px 70px 78px 70px; + } + + .navbar { + padding: 26px 70px; + } + + .navbar-left-txt { + display: block; + } + + .navbar-mid { + display: flex; + align-items: center; + gap: 80px; + } + + .navbar-right { + display: flex; + align-items: center; + gap: 40px; + } + + .navbar-menu { + display: none; + } + + .hero { + justify-content: space-between; + } + + .hero-left { + gap: 100px; + align-items: start; + } + + .hero-logo { + max-width: 409px; + } + + .hero-button { + background-color: var(--colorsviolet20); + color: var(--colorsviolet100); + font-size: var(--font-size-xl); + } + + .hero-button-link { + padding: 16px 24px; + } + + .hero-copy { + align-items: start; + gap: 0px; + } + + .hero-copy-font { + text-align: left; + font-size: var(--font-size-xxxl); + } + + .hero-right { + display: flex; + flex-direction: column; + } + + .demo { + width: 295px; + height: 490px; + padding: 55px 30px 55px 30px; + } + + .demo-img { + width: 81px; + height: 65px; + } + + .demo-title { + font-size: var(--font-size-xxl); + } + + .demo-button { + width: 210px; + height: 56px; + font-size: var(--font-size-xl); + } + + .demo-button-link { + display: flex; + width: 100%; + height: 100%; + align-items: center; + justify-content: center; + } + + .lc-content { + flex-direction: row; + } + + .lc-video { + /* TODO revisit */ + flex-basis: 0; + height: 267px; + } + + .feature { + flex-direction: column; + gap: 30px; + width: 215px; + height: 310px; + padding: 30px 15px; + align-items: center; + } + + .feature-link { + width: 100%; + height: 100%; + } + + .feature-img { + width: 81px; + height: 56px; + } + + .feature-content { + gap: 20px; + } + + .feature-title { + text-align: center; + } + + .feature-desc { + text-align: center; + } + + .footer { + gap: 30px; + padding: 40px 70px; + font-size: var(--font-size-m); + text-align: center; + justify-content: center; + } + + .footer-img { + width: 60px; + } +} \ No newline at end of file