Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
f6b27b1
Serve the init segment instead of pieces of it. (#1062)
kixelated Mar 6, 2026
81ce43f
Add unit tests for fMP4 importer init segment generation (#1066)
kixelated Mar 6, 2026
202e48d
Merge remote-tracking branch 'origin/main' into make-log-fallble
kixelated Mar 11, 2026
692d05b
Make Log::init() fallible (#1076)
kixelated Mar 11, 2026
8fa0f07
Merge remote-tracking branch 'origin/main' into dev
kixelated Mar 11, 2026
b2eef54
Merge remote-tracking branch 'origin/main' into dev
kixelated Mar 13, 2026
9131382
Fix unused Result warning in moq-ffi log init (#1098)
kixelated Mar 13, 2026
80d5630
Add hops-based broadcast routing (#1082)
kixelated Mar 13, 2026
4b75286
Merge remote-tracking branch 'origin/main' into dev
kixelated Mar 17, 2026
40e7ea6
Merge remote-tracking branch 'origin/main' into dev
kixelated Mar 19, 2026
079d425
Merge remote-tracking branch 'origin/main' into dev
kixelated Mar 19, 2026
247a393
Reapply "Rename next_group to recv_group for clarity (#1135)"
kixelated Mar 19, 2026
fef1bc8
Add convert/export modules and subscribe CLI command (#1102)
kixelated Mar 19, 2026
2626a25
Move sync to props and add dynamic SyncTrack API (#1138)
kixelated Mar 19, 2026
64cbba8
Merge remote-tracking branch 'origin/main' into dev
kixelated Mar 21, 2026
997e161
Replace monolithic catalog with generic section-based registry
kixelated Mar 22, 2026
6fecb39
Update moq-ffi Container::Cmaf to match upstream field change
kixelated Mar 23, 2026
96e387b
Merge remote-tracking branch 'origin/main' into dev
kixelated Mar 26, 2026
63fe6e6
just fix
kixelated Mar 26, 2026
b700f70
Fix dev branch: CMAF decode, relay ctrl+c, CLI args, catalog serde (#…
kixelated Mar 26, 2026
829f108
Rename catalog task APIs to subscribe/unsubscribe (#1140)
kixelated Mar 26, 2026
4e12cbb
Update TypeScript from 5.9 to 6.0 (#1151)
kixelated Mar 26, 2026
9ed8847
feat: expose moq-relay as library (#1121)
Frando Mar 26, 2026
8fc26c6
Use typed ordered::Consumer for video/audio in moq-ffi (#1163)
Qizot Mar 26, 2026
cbe183a
Remove --quiet flag from cargo and nix commands (#1166)
kixelated Mar 26, 2026
e674949
Fix mismerged Cmaf variant fields in moq-ffi media.rs
kixelated Mar 27, 2026
229d07c
Reorganize moq-native API: feature-gated modules and builder pattern …
kixelated Mar 28, 2026
a515d2b
Refactor Origin API: cleaner naming, remove Option from announcements…
kixelated Mar 31, 2026
41dc66a
moq-lite-04: Replace hop count with explicit OriginId list (#1152)
kixelated Apr 1, 2026
2d01f69
Merge remote-tracking branch 'origin/dev' into generic-catalog
kixelated Apr 2, 2026
2586e37
Merge dev, resolve conflicts, and address review feedback
kixelated Apr 2, 2026
874ff76
Subscription model refactor + async subscribe_track (#1134)
kixelated Apr 3, 2026
745f7df
Merge main into dev: resolve conflicts and update APIs
kixelated Apr 3, 2026
b507a77
Merge remote-tracking branch 'origin/dev' into generic-catalog
kixelated Apr 3, 2026
9b237f5
Fix merge conflicts with dev: update APIs and zod/mini types
kixelated Apr 3, 2026
88ee499
Remove moq-mux feature gates, make all deps non-optional
kixelated Apr 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 0 additions & 10 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,6 @@ result
node_modules
/.direnv

# Don't leak dev stuff
*.mp4
*.fmp4
*.crt
*.key
*.hex
*.jwk
*.jwt
*.m3u8
*.m4s

# We're using bun
package-lock.json
Expand Down
2 changes: 2 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,13 +116,15 @@ match version {
- Run `just fix` to automatically fix formating and easy things.
- Rust tests are integrated within source files
- Async tests that sleep should call `tokio::time::pause()` at the start to simulate time instantly
- Use `tokio::time::sleep()` (not `advance()`) to move time forward in paused-time tests — `sleep` both advances the clock and yields to the runtime so spawned tasks can run

## Branching Strategy

- **`main`**: Stable branch for patch releases. Only non-breaking fixes and additions.
- **`dev`**: Development branch for breaking API changes. PRs with major API changes should target `dev`.
- When ready for a new minor/major release, merge `dev` into `main`.
- `cargo-semver-checks` enforces this on PRs to `main`.
- When removing a public method on `dev`, mark it `#[deprecated]` first so downstream code gets warnings before the next breaking release.

## Workflow

Expand Down
19 changes: 13 additions & 6 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 15 additions & 7 deletions cdn/input.tf
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,25 @@ variable "webhook" {
# instance types: https://api.linode.com/v4/linode/types
locals {
relays = {
usc = {
region = "us-central" # Dallas, TX
type = "g6-standard-2" # 4GB RAM, 2 vCPU, $24/mo, 4TB out
usw = {
region = "us-west" # Fremont, CA
type = "g6-standard-2" # 4GB RAM, 2 vCPU, $24/mo, 4TB out
connect = ["use"]
}
use = {
region = "us-east" # Newark, NJ
type = "g6-standard-2"
connect = ["usw", "euc"]
}
euc = {
region = "eu-central" # Frankfurt, Germany
type = "g6-standard-2"
region = "eu-central" # Frankfurt, Germany
type = "g6-standard-2"
connect = ["use"]
}
sea = {
region = "ap-south" # Singapore
type = "g6-standard-2"
region = "ap-south" # Singapore
type = "g6-standard-2"
connect = ["use"]
}
}
}
1 change: 1 addition & 0 deletions cdn/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ module "relay" {
module "pub" {
source = "./pub"
domain = var.domain
relay = "use.${var.domain}"
ssh_keys = var.ssh_keys
stackscript_id = linode_stackscript.bootstrap.id
gcp_account_key = google_service_account_key.relay.private_key
Expand Down
2 changes: 1 addition & 1 deletion cdn/pub/demo-bbb.service.tftpl
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ ExecStart=/bin/bash -c '\
-movflags cmaf+separate_moof+delay_moov+skip_trailer+frag_every_frame \
- | \
/var/lib/moq/pkg/bin/moq-cli publish \
--url "https://${domain}/demo?jwt=$(cat /var/lib/moq/demo-pub.jwt)" \
--url "https://${relay}/demo?jwt=$(cat /var/lib/moq/demo-pub.jwt)" \
--name bbb \
fmp4'

Expand Down
4 changes: 2 additions & 2 deletions cdn/pub/main.tf
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
# Generate systemd service files from templates
resource "local_file" "demo_bbb_service" {
content = templatefile("${path.module}/demo-bbb.service.tftpl", {
domain = var.domain
relay = var.relay
})
filename = "${path.module}/gen/demo-bbb.service"
}

# Publisher instance
resource "linode_instance" "publisher" {
label = "publisher-moq"
region = "us-central" # Dallas, TX
region = "us-east" # Newark, NJ (colocated with use relay)
type = "g6-nanode-1"

# Use Debian 12 as base, will be converted to NixOS via bootstrap
Expand Down
5 changes: 5 additions & 0 deletions cdn/pub/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ variable "domain" {
type = string
}

variable "relay" {
description = "Relay hostname to publish to (e.g. use.example.com)"
type = string
}

variable "ssh_keys" {
description = "SSH public keys for root access"
type = list(string)
Expand Down
3 changes: 2 additions & 1 deletion cdn/relay/dns.tf
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ resource "google_dns_record_set" "relay_global" {
# GCP uses region codes like "us-east1", "us-west1", "europe-west3", "asia-southeast1"
locals {
relay_gcp_regions = {
usc = "us-central1" # Dallas, TX -> closest GCP region
usw = "us-west1" # Fremont, CA -> closest GCP region
use = "us-east1" # Newark, NJ -> closest GCP region
euc = "europe-west3" # Frankfurt -> closest GCP region
sea = "asia-southeast1" # Singapore -> closest GCP region
}
Expand Down
7 changes: 4 additions & 3 deletions cdn/relay/justfile
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,14 @@ host node:

# List the available nodes.
nodes:
@echo "usc: Dallas, TX"
@echo "usw: Fremont, CA"
@echo "use: Newark, NJ"
@echo "euc: Frankfurt, Germany"
@echo "sea: Singapore"

# Deploy moq-relay and moq-cert to all nodes
[parallel]
deploy-all: (deploy "usc") (deploy "euc") (deploy "sea")
deploy-all: (deploy "usw") (deploy "use") (deploy "euc") (deploy "sea")

# Deploy moq-relay and moq-cert to a specific node
deploy node:
Expand Down Expand Up @@ -78,7 +79,7 @@ status node:
echo "=== $HOST ==="
ssh root@$HOST "systemctl status moq-relay --no-pager"

status-all: (status "usc") (status "euc") (status "sea")
status-all: (status "usw") (status "use") (status "euc") (status "sea")

ssh node:
#!/usr/bin/env bash
Expand Down
9 changes: 6 additions & 3 deletions cdn/relay/main.tf
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
# Generate systemd service files from templates
# Generate per-node systemd service files from templates
resource "local_file" "moq_relay_service" {
for_each = var.relays

content = templatefile("${path.module}/moq-relay.service.tftpl", {
domain = var.domain
domain = var.domain
connect = each.value.connect
})
filename = "${path.module}/gen/moq-relay.service"
filename = "${path.module}/gen/${each.key}/moq-relay.service"
}

resource "local_file" "moq_cert_service" {
Expand Down
4 changes: 3 additions & 1 deletion cdn/relay/moq-relay.service.tftpl
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ ExecStart=/var/lib/moq/pkg/bin/moq-relay \
--web-https-listen [::]:443 \
--web-https-cert /etc/letsencrypt/live/${domain}/fullchain.pem \
--web-https-key /etc/letsencrypt/live/${domain}/privkey.pem \
--cluster-root usc.${domain} \
%{ for peer in connect ~}
--cluster-connect ${peer}.${domain} \
%{ endfor ~}
--cluster-node %H \
--cluster-token /var/lib/moq/cluster.jwt

Expand Down
5 changes: 3 additions & 2 deletions cdn/relay/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ variable "ssh_keys" {
variable "relays" {
description = "Map of relay node configurations"
type = map(object({
region = string
type = string
region = string
type = string
connect = list(string)
}))
}

Expand Down
9 changes: 9 additions & 0 deletions dev/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
*.mp4
*.fmp4
*.crt
*.key
*.hex
*.jwk
*.jwt
*.m3u8
*.m4s
6 changes: 3 additions & 3 deletions dev/boy/src/audio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use anyhow::{Context, Result};
///
/// Uses ffmpeg-next for Opus encoding (same dependency as video H.264).
pub struct AudioEncoder {
opus: moq_mux::import::Opus,
opus: moq_mux::producer::Opus,
ffmpeg_encoder: ffmpeg_next::encoder::audio::Encoder,
resampler: Option<ffmpeg_next::software::resampling::Context>,
sample_buffer: Vec<i16>,
Expand All @@ -26,10 +26,10 @@ impl AudioEncoder {
catalog: moq_mux::CatalogProducer,
input_sample_rate: u32,
) -> Result<Self> {
let opus = moq_mux::import::Opus::new(
let opus = moq_mux::producer::Opus::new(
broadcast,
catalog,
moq_mux::import::OpusConfig {
moq_mux::producer::OpusConfig {
sample_rate: OPUS_SAMPLE_RATE,
channel_count: CHANNELS,
},
Expand Down
4 changes: 2 additions & 2 deletions dev/boy/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ class GameCard {
const sync = new Watch.Sync({ jitter: 50 as Moq.Time.Milli });
this.#signals.cleanup(() => sync.close());

const videoSource = new Watch.Video.Source(sync, { broadcast });
const videoSource = new Watch.Video.Source({ sync, broadcast });
this.#signals.cleanup(() => videoSource.close());

// Set pixel budget based on expanded state.
Expand All @@ -220,7 +220,7 @@ class GameCard {
this.#signals.cleanup(() => videoRenderer.close());

// Set up audio — play on hover at 50% volume.
const audioSource = new Watch.Audio.Source(sync, { broadcast });
const audioSource = new Watch.Audio.Source({ sync, broadcast });
this.#signals.cleanup(() => audioSource.close());

const audioDecoder = new Watch.Audio.Decoder(audioSource);
Expand Down
Loading
Loading