+ There will be dope diagrams and animations here one day. Until then, it's better to prove that the
+ protocol works via a demo. Dope diagrams and animations only prove that I can use a vector graphics
+ editor.
+
+
+ Or you can watch some of my older presentations:{" "}
+ Video @ Scale and{" "}
+ Demuxed.
+
+
+ )
+}
diff --git a/web/github.tsx b/web/github.tsx
index 605de3b..8181234 100644
--- a/web/github.tsx
+++ b/web/github.tsx
@@ -1,26 +1,6 @@
-import * as caniuse from "caniuse-lite"
-import { For } from "solid-js"
+import { A } from "@solidjs/router"
export function Github() {
- const features = ["webtransport", "webcodecs", "audio-api", "sharedarraybuffer"].map((id) => {
- return { id, ...caniuse.feature(caniuse.features[id]) }
- })
- const agents = ["chrome", "edge", "firefox", "safari", "ios_saf", "android"].map((id) => {
- const agent = caniuse.agents[id]!
-
- // Get the date of the latest release:
- const latest =
- Object.values(agent.release_date).reduce((a, b) => {
- if (!a) return b
- if (!b) return a
- return a > b ? a : b
- }) ?? 0
-
- return { id, latest, ...caniuse.agents[id] }
- })
-
- const latest = agents.reduce((a, b) => (a.latest > b.latest ? a : b)).latest
-
return (
So you want some source code huh? That's cool.
@@ -106,57 +86,7 @@ export function Github() {
This project is using a lot of new web APIs. Chrome support is guaranteed but other browsers are still
- catching up.
-
-
- Here is a non-compreshensive list of required features from the{" "}
- caniuse database, based on the latest version of each browser as of:{" "}
- {new Date(1000 * latest).toDateString()}
-
- )
- }}
-
- >
- )
- }}
-
+ catching up. See issues for more details.
Licensing
diff --git a/web/img/warning.svg b/web/img/warning.svg
new file mode 100644
index 0000000..9a3cc96
--- /dev/null
+++ b/web/img/warning.svg
@@ -0,0 +1 @@
+
diff --git a/web/index.tsx b/web/index.tsx
index 5314f19..2a65a30 100644
--- a/web/index.tsx
+++ b/web/index.tsx
@@ -7,6 +7,8 @@ import { Listings } from "./listing"
import { Publish } from "./publish"
import { Home } from "./home"
import { Github } from "./github"
+import { Issues } from "./issues"
+import { Explain } from "./explain"
// Import the icons using this trick so Parcel can rewrite the URLs.
const icons = {
@@ -61,6 +63,8 @@ function Main() {
+
+ 404 Not found
} />
diff --git a/web/issues.tsx b/web/issues.tsx
new file mode 100644
index 0000000..20374e6
--- /dev/null
+++ b/web/issues.tsx
@@ -0,0 +1,248 @@
+import { A } from "@solidjs/router"
+import * as caniuse from "caniuse-lite"
+import { For } from "solid-js"
+
+const icons = {
+ // TODO draw in my dumb art style
+ warning: new URL("./img/warning.svg", import.meta.url),
+}
+
+export function Issues() {
+ const features = ["webtransport", "webcodecs", "audio-api", "sharedarraybuffer"].map((id) => {
+ return { id, ...caniuse.feature(caniuse.features[id]) }
+ })
+
+ const agents = ["chrome", "edge", "firefox", "safari", "ios_saf", "android"].map((id) => {
+ const agent = caniuse.agents[id]!
+
+ // Get the date of the latest release:
+ const latest =
+ Object.values(agent.release_date).reduce((a, b) => {
+ if (!a) return b
+ if (!b) return a
+ return a > b ? a : b
+ }) ?? 0
+
+ return { id, latest, ...caniuse.agents[id] }
+ })
+
+ const latest = agents.reduce((a, b) => (a.latest > b.latest ? a : b)).latest
+
+ return (
+
+
Yeah so there's a lot of work to do.
+
+ This is an early PoC and hobby project, so expect nothing to work. Check out the Github issues (
+ moq-rs and{" "}
+ moq-js) if you want to contribute or complain;
+ both are equally valid.
+
+
+ Browser Support
+
+ We're using some pretty new web standards, so browser support is limited. Here is a non-compreshensive
+ list of the required features from the caniuse database as of:{" "}
+ {new Date(1000 * latest).toDateString()}
+
+ The only hard requirement is{" "}
+ WebTransport. See the
+ following sections for possible alternatives for web playback and web contribution.
+
+
+ Web Playback
+
+ WebCodecs decoding is a
+ breeze but rendering is a nightmare, as the application is responsible for everything. This includes
+ when to render video frames but also when to emit audio samples, which gets very complicated quickly as
+ it involves synchronization.
+
+
+ Additionally, there's no built-in controls. Even something as trivial as changing the volume requires
+ building a WebAudio filter as opposed to relying on the <video> tag. I'm not a front-end developer
+ (no flame pls) and would love any contributions on this front.
+
+
+ A much simpler rendering technology is{" "}
+ MSE. I had a
+ previous demo that used this API, but the latency is significantly higher than WebCodecs as it will
+ buffer during starvation. I plan on supporting it again in the future and it works great with Media over
+ QUIC as both use fMP4.
+
+
+ Web Contribution
+
+ WebCodecs is great for
+ encoding in my relatively limited experience. We may need some more functionality to support
+ conferencing, such as like echo cancellation or advanced encodings.
+
+
+ The main limitation is capturing sources from the browser, as the browser doesn't have the same
+ flexibility as a native program like OBS. I would also love to see
+ a UI that allows positioning elements or doing cool effects. If you can render to a <canvas>, then
+ you can encode it with WebCodecs and transmit it with WebTransport.
+
+
+ Media over QUIC relies on both congestion control and prioritization to provide the best user experience
+ on poor networks. The WebTransport specification does provide{" "}
+
+ prioritization
+ {" "}
+ and{" "}
+
+ congestion control hints
+
+ , but these have not been implemented yet. We have limited control over the browser's congestion control
+ which is especially important for live media.
+
+ The congestion control algorithm is extremely important for live media over the internet, as{" "}
+ bufferbloat will cause queuing on the network.
+ TCP-oriented congestion control are often compared by sustained throughput, but for live media we're
+ more interested in latency, since the encoded bitrate is the limiting factor. When latency is critical,
+ it's better to drop old media instead of queuing new media, and that's only possible when you can detect
+ queuing via congestion control.
+
+
+ Loss-based congestion control like{" "}
+ New Reno (Windows default) and{" "}
+ CUBIC (Linux default) suffer from bufferbloat.
+ Your experience will vary based on the network, with some ISPs and parts of the world being
+ significantly worse than others. This is also the fundamental issue with RTMP, since it relies on the
+ operating system's TCP congestion control. QUIC libraries can ship their own congestion control allowing
+ much faster experimentation and iteration.
+
+
+ Delay-based congestion control like{" "}
+
+ BBR
+ {" "}
+ and COPA are better, but are still fundamentally designed for
+ TCP. They're not designed for application-limited environments like live media where we don't fully
+ saturate the network. Flooding the network with PADDING packets to occasionally saturate the network
+ makes a big difference, but is experimental and not yet implemented.
+
+
+ Delayed-based and latency-sensitive congestion control like{" "}
+ GCC and{" "}
+ SCReAM are the best* for real-time media and
+ see wide usage in WebRTC. However, the per-packet feedback required for these algorithms are not
+ available in QUIC. We will need a QUIC extension in order to match WebRTC performance and latency.
+
+
+ Dynamic Bitrate
+
+ An alternative to dropping media is to dynamically adjust the bitrate. The picture quality will worsen,
+ but more frames will be delivered, which often results in a better user experience.
+
+
+ In 1:1 video conferencing, the media encoding is adjusted in response to viewer feedback. A protocol
+ like WebRTC will lower the media bitrate in response to minor congestion and request a new I-frame in
+ response to major-congestion. No such feedback exists yet in Media over QUIC, and is complicated by the
+ presence of relays.
+
+
+ In 1:N video conferencing, the encoding is fixed, as one viewer's experience should not degrade
+ everybody else's experience. The common approach is to encode multiple renditions of the broadcast at
+ different bitrates, allowing the viewer to switch between them depending on their network. This is
+ called ABR in distribution
+ circles and simulcast in contribution circles.
+ This is not implemented yet either.
+
+
+ CDNs
+
+ Media over QUIC is designed with relays and CDNs in mind.{" "}
+ MoqTransport is media agnostic
+ and exposes only the most critical information to relay. The design should enable world-side scale while
+ still supporting real-time latency budgets.
+
+
+ ...but we haven't built it yet. You're currently connecting to a single server somewhere in the US, so
+ don't expect the best quality. I'm working on it now so expect this section to be updated soon.
+
+
+ Specification
+
+ Media over QUIC is an IETF working group.
+ The IETF is an open organization that develops Internet standards,
+ including some of your favorite protocols like HTTP, TLS, and DNS.
+
+
+ The standardization effort is slow and deliberate so don't expect an RFC for years.{" "}
+ quic.video uses a fork of the specification, allowing us to experiment
+ with new features without the litigation involved in a standard.{" "}
+
+ Here's a list
+ {" "}
+ of the changes thus far, which we hope will be merged into the standard.
+
+
+ )
+}
+
+export function Notice() {
+ return (
+
+
+
+ This is an early-stage proof-of-concept. Check out the current limitations.
+ Contributions are welcome!
+
+
+ )
+}
diff --git a/web/publish.tsx b/web/publish.tsx
index 5790f0b..0c7190b 100644
--- a/web/publish.tsx
+++ b/web/publish.tsx
@@ -7,6 +7,7 @@ import { useSearchParams } from "@solidjs/router"
import { Listing } from "./listing"
import { createFetch } from "./common"
import { connect } from "./connect"
+import { Notice } from "./issues"
interface GeneralConfig {
server: string
@@ -204,21 +205,12 @@ export function Publish() {
return (
<>
+
{error()!.name}: {error()!.message}
-
-
-
- You've made a PUBLIC broadcast. Don't abuse it pls.
-
-
- Make a PUBLIC broadcast. Don't abuse it pls.
-
-
-
Preview
diff --git a/web/tsconfig.json b/web/tsconfig.json
index f138174..dd33c55 100644
--- a/web/tsconfig.json
+++ b/web/tsconfig.json
@@ -16,6 +16,6 @@
"jsxImportSource": "solid-js",
"typeRoots": ["../lib/types", "../node_modules/@types"],
"lib": ["esnext"],
- "types": ["web", "parcel-env", "dom-webcodecs", "dom-mediacapture-transform"]
+ "types": ["web", "parcel-env", "dom-webcodecs", "dom-mediacapture-transform", "solid-jsx/types"]
}
}
diff --git a/web/watch.tsx b/web/watch.tsx
index f208d3a..ecf58d6 100644
--- a/web/watch.tsx
+++ b/web/watch.tsx
@@ -7,6 +7,7 @@ import { useParams, useSearchParams } from "@solidjs/router"
import { createFetch, createPack, createSource } from "./common"
import { Listing } from "./listing"
import { connect } from "./connect"
+import { Notice } from "./issues"
export function Watch() {
const params = useParams<{ name: string }>()
@@ -42,16 +43,14 @@ export function Watch() {
// TODO shrink it if needed via CSS
return (
<>
+
+
{error()!.name}: {error()!.message}
-
- This is a PUBLIC broadcast. Report any abuse pls.
-