Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ bin/
# Web
web/node_modules/
web/dist/
web/dist-lib/

# TLS
*.pem
Expand Down
7 changes: 4 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ All changes must pass `make check`, which runs:

- `gofmt -s` — Go code formatting with simplification
- `go vet` — Go static analysis
- `staticcheck` — Extended static analysis ([install](https://staticcheck.dev/))
- `go test -race` — All tests with the race detector enabled
- `npx tsc --noEmit` — TypeScript type checking (strict mode)

Expand All @@ -47,13 +48,13 @@ All changes must pass `make check`, which runs:
make test

# Run tests for a specific package
go test -v -race ./internal/demux/
go test -v -race ./demux/

# Run fuzz tests (default 10s, adjust as needed)
go test -fuzz=FuzzParseAnnexB -fuzztime=30s ./internal/demux/
go test -fuzz=FuzzParseAnnexB -fuzztime=30s ./demux/

# Run benchmarks
go test -bench=. -benchmem ./internal/distribution/
go test -bench=. -benchmem ./distribution/
```

## Project Structure
Expand Down
1 change: 0 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ check: fmt vet
go mod tidy
staticcheck ./...
go test -race -cover ./...
govulncheck ./...
cd web && npx tsc --noEmit

web-install:
Expand Down
82 changes: 68 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,61 @@ ffmpeg -re -i input.ts -c copy -f mpegts srt://localhost:6000?streamid=mystream

Then open `https://localhost:4444/?stream=mystream`.

## Examples

Prism's packages are designed to be used as a library. The `examples/` directory contains standalone programs showing how to embed Prism in your own application, and `web/examples/` shows how to use the player in a browser.

### Minimal server (Go)

A stripped-down version of `cmd/prism` — SRT ingest, demux, and WebTransport delivery in ~60 lines:

```bash
go run ./examples/minimal-server
ffmpeg -re -i input.ts -c copy -f mpegts srt://localhost:6000?streamid=demo
open https://localhost:4443
```

### Custom ingest (Go)

Feed any MPEG-TS `io.Reader` directly into the pipeline — no SRT required:

```bash
go run ./examples/custom-ingest input.ts
open https://localhost:4443/?stream=file
```

### Standalone web player (TypeScript)

Embed `PrismPlayer` in your own page using the built library bundle:

```bash
cd web && npm run demo:lib # builds dist-lib/prism.js + starts Vite dev server
# (start the Prism server in another terminal: make run)
open http://localhost:5173/examples/standalone.html?stream=demo
```

The HTML is ~80 lines and shows the full API: create a player, connect to a stream key, handle lifecycle callbacks. See [`web/examples/standalone.html`](web/examples/standalone.html).

### Building the web player library

To use `PrismPlayer` in your own project:

```bash
cd web && npm run build:lib # outputs web/dist-lib/prism.js
```

```js
import { PrismPlayer } from "./dist-lib/prism.js";

const player = new PrismPlayer(document.getElementById("container"), {
onStreamConnected(key) { console.log("connected:", key); },
onStreamDisconnected(key) { console.log("disconnected:", key); },
});
player.connect("demo");
```

The library also exports `MoQTransport`, `MoQMultiviewTransport`, `MetricsStore`, and related types for advanced use cases.

## Architecture

```
Expand All @@ -64,18 +119,18 @@ Single Go binary, vanilla TypeScript frontend:
| Package | Purpose |
|---|---|
| `cmd/prism/` | Entry point, wires everything together |
| `internal/ingest/` | Stream ingest registry |
| `internal/ingest/srt/` | SRT server (push) and caller (pull) |
| `internal/demux/` | MPEG-TS demuxer, H.264/H.265/AAC parsers |
| `internal/media/` | Frame types (`VideoFrame`, `AudioFrame`) |
| `internal/distribution/` | WebTransport server, MoQ sessions, relay fan-out |
| `internal/moq/` | MoQ Transport wire protocol codec |
| `internal/pipeline/` | Demux-to-distribution orchestration |
| `internal/stream/` | Stream lifecycle management |
| `internal/mpegts/` | Low-level MPEG-TS packet/PES/PSI parsing |
| `internal/scte35/` | SCTE-35 splice info encoding/decoding |
| `internal/certs/` | Self-signed ECDSA certificate generation |
| `internal/webtransport/` | WebTransport server on quic-go/HTTP3 |
| `ingest/` | Stream ingest registry |
| `ingest/srt/` | SRT server (push) and caller (pull) |
| `demux/` | MPEG-TS demuxer, H.264/H.265/AAC parsers |
| `media/` | Frame types (`VideoFrame`, `AudioFrame`) |
| `distribution/` | WebTransport server, MoQ sessions, relay fan-out |
| `moq/` | MoQ Transport wire protocol codec |
| `pipeline/` | Demux-to-distribution orchestration |
| `stream/` | Stream lifecycle management |
| `mpegts/` | Low-level MPEG-TS packet/PES/PSI parsing |
| `scte35/` | SCTE-35 splice info encoding/decoding |
| `certs/` | Self-signed ECDSA certificate generation |
| `webtransport/` | WebTransport server on quic-go/HTTP3 |
| `web/` | Vanilla TypeScript viewer (Vite, WebTransport, WebCodecs) |

## Configuration
Expand Down Expand Up @@ -131,11 +186,10 @@ make demo
make demo-full
```

`make check` requires [staticcheck](https://staticcheck.dev/) and [govulncheck](https://pkg.go.dev/golang.org/x/vuln/cmd/govulncheck):
`make check` requires [staticcheck](https://staticcheck.dev/):

```bash
go install honnef.co/go/tools/cmd/staticcheck@latest
go install golang.org/x/vuln/cmd/govulncheck@latest
```

## Security Considerations
Expand Down
File renamed without changes.
File renamed without changes.
12 changes: 6 additions & 6 deletions cmd/prism/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ import (

"golang.org/x/sync/errgroup"

"github.com/zsiec/prism/internal/certs"
"github.com/zsiec/prism/internal/distribution"
"github.com/zsiec/prism/internal/ingest"
srtingest "github.com/zsiec/prism/internal/ingest/srt"
"github.com/zsiec/prism/internal/pipeline"
"github.com/zsiec/prism/internal/stream"
"github.com/zsiec/prism/certs"
"github.com/zsiec/prism/distribution"
"github.com/zsiec/prism/ingest"
srtingest "github.com/zsiec/prism/ingest/srt"
"github.com/zsiec/prism/pipeline"
"github.com/zsiec/prism/stream"
)

var version = "dev"
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
"testing"

"github.com/zsiec/ccx"
"github.com/zsiec/prism/internal/mpegts"
"github.com/zsiec/prism/mpegts"
)

func TestCaptionHarness(t *testing.T) {
Expand Down
2 changes: 1 addition & 1 deletion internal/demux/diag_test.go → demux/diag_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
"testing"

"github.com/zsiec/ccx"
"github.com/zsiec/prism/internal/mpegts"
"github.com/zsiec/prism/mpegts"
)

func TestDiag_DecodedCaptions(t *testing.T) {
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
6 changes: 3 additions & 3 deletions internal/demux/mpegts.go → demux/mpegts.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import (
"time"

"github.com/zsiec/ccx"
"github.com/zsiec/prism/internal/media"
"github.com/zsiec/prism/internal/mpegts"
"github.com/zsiec/prism/internal/scte35"
"github.com/zsiec/prism/media"
"github.com/zsiec/prism/mpegts"
"github.com/zsiec/prism/scte35"
)

const (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"fmt"

"github.com/quic-go/quic-go/quicvarint"
"github.com/zsiec/prism/internal/webtransport"
"github.com/zsiec/prism/webtransport"
)

// moqCatalog is the top-level catalog structure per draft-ietf-moq-catalogformat-01.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ import (
"time"

"github.com/zsiec/ccx"
"github.com/zsiec/prism/internal/media"
"github.com/zsiec/prism/internal/moq"
"github.com/zsiec/prism/internal/webtransport"
"github.com/zsiec/prism/media"
"github.com/zsiec/prism/moq"
"github.com/zsiec/prism/webtransport"
)

// moqTrackSub holds state for a single track subscription within a MoQ session.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ import (
"github.com/quic-go/quic-go"
"github.com/quic-go/quic-go/quicvarint"
"github.com/zsiec/ccx"
"github.com/zsiec/prism/internal/media"
"github.com/zsiec/prism/internal/moq"
"github.com/zsiec/prism/internal/webtransport"
"github.com/zsiec/prism/media"
"github.com/zsiec/prism/moq"
"github.com/zsiec/prism/webtransport"
)

// buildClientSetupPayload builds a CLIENT_SETUP payload for testing.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import (
"io"

"github.com/quic-go/quic-go/quicvarint"
"github.com/zsiec/prism/internal/media"
"github.com/zsiec/prism/internal/moq"
"github.com/zsiec/prism/media"
"github.com/zsiec/prism/moq"
)

// Compile-time interface check.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
"testing"

"github.com/quic-go/quic-go/quicvarint"
"github.com/zsiec/prism/internal/media"
"github.com/zsiec/prism/media"
)

func TestMoQWriterSubgroupHeader(t *testing.T) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
// Package distribution implements the WebTransport-based viewer delivery
// layer, including the fan-out relay, MoQ session management, and the
// HTTP/QUIC server that ties them together. The low-level MoQ wire protocol
// codec lives in [github.com/zsiec/prism/internal/moq].
// codec lives in [github.com/zsiec/prism/moq].
package distribution

import (
"io"

"github.com/zsiec/prism/internal/media"
"github.com/zsiec/prism/media"
)

// Track ID constants used to identify media types in the MoQ catalog
Expand Down
4 changes: 2 additions & 2 deletions internal/distribution/relay.go → distribution/relay.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import (
"sync"

"github.com/zsiec/ccx"
"github.com/zsiec/prism/internal/media"
"github.com/zsiec/prism/internal/moq"
"github.com/zsiec/prism/media"
"github.com/zsiec/prism/moq"
)

// Viewer is the interface that a viewer session (single or mux) must implement
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"testing"

"github.com/zsiec/ccx"
"github.com/zsiec/prism/internal/media"
"github.com/zsiec/prism/media"
)

// mockViewer implements the Viewer interface for testing.
Expand Down
6 changes: 3 additions & 3 deletions internal/distribution/server.go → distribution/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ import (

"github.com/quic-go/quic-go"
"github.com/quic-go/quic-go/http3"
"github.com/zsiec/prism/internal/certs"
"github.com/zsiec/prism/internal/moq"
"github.com/zsiec/prism/internal/webtransport"
"github.com/zsiec/prism/certs"
"github.com/zsiec/prism/moq"
"github.com/zsiec/prism/webtransport"
)

// StatsProvider is implemented by Pipeline to supply stream statistics
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"strings"
"testing"

"github.com/zsiec/prism/internal/certs"
"github.com/zsiec/prism/certs"
)

func newTestServer(t *testing.T) *Server {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package distribution
import (
"sync/atomic"

"github.com/zsiec/prism/internal/media"
"github.com/zsiec/prism/media"
)

// trySendVideo implements the damaged-group-aware video send logic shared
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"sync/atomic"
"testing"

"github.com/zsiec/prism/internal/media"
"github.com/zsiec/prism/media"
)

func TestTrySendVideoKeyframeResetsGroup(t *testing.T) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"sync/atomic"
"time"

"github.com/zsiec/prism/internal/demux"
"github.com/zsiec/prism/demux"
)

// Compile-time interface check.
Expand Down
49 changes: 49 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Examples

Standalone programs demonstrating how to use Prism's packages as a library.

## Go

### Minimal Server

[`minimal-server/main.go`](minimal-server/main.go) — A complete SRT-to-WebTransport server in ~60 lines. Same architecture as `cmd/prism` but stripped to the essentials.

```bash
go run ./examples/minimal-server
ffmpeg -re -i input.ts -c copy -f mpegts srt://localhost:6000?streamid=demo
open https://localhost:4443
```

### Custom Ingest

[`custom-ingest/main.go`](custom-ingest/main.go) — Feed any MPEG-TS `io.Reader` directly into the pipeline, bypassing SRT entirely.

```bash
go run ./examples/custom-ingest input.ts
open https://localhost:4443/?stream=file
```

## Web

### Standalone Player

[`../web/examples/standalone.html`](../web/examples/standalone.html) — Embed `PrismPlayer` in a plain HTML page using the built library bundle.

```bash
cd web && npm run demo:lib # builds dist-lib/prism.js + starts dev server
# (start the Prism server in another terminal: make run)
open http://localhost:5173/examples/standalone.html?stream=demo
```

## Key Packages

These are the main packages you'll use when embedding Prism:

| Package | Description |
|---|---|
| `certs` | Generate self-signed ECDSA certificates for WebTransport |
| `distribution` | WebTransport server, MoQ sessions, relay fan-out |
| `ingest` | Stream ingest registry (pairs stream keys with pipelines) |
| `ingest/srt` | SRT push server and pull caller |
| `pipeline` | Connects a demuxer to a distribution relay |
| `stream` | Stream lifecycle management |
Loading