Skip to content

StreamDoctor requirements #1

Open
5 of 6 issues completed
Open

Description

@varsill

General description

StreamDoctor is a a tool that broadcasts a synthetic stream and measures what happened to it along the way, for teams maintaining video infrastructure, so that e.g. A/V drift and dropped frames get caught by CI rather than by a human clicking through a list of manual tests.

StreamDoctor consists of a couple of elements:

  • a "daemon" - server capable of spawning "streamers" and "viewers" and dynamically managing them, controlled via REST API, delivered as a binary, it could be using Boombox and Membrane under the hood
  • "core" - a native implementation (e.g. in Rust, with wgpu) of core functions that need to be run both by daemon and in the browser (e.g. via WASM), potentially computationally heavy, like marker encoding/decoding etc.
  • a bunch of SDKs (e.g. in Typescript), which spawn daemon processes and use them to execute testing scenarios defined by user

Below there is an example of how the usage of StreamDoctor could look like:

test('stream reaches viewers in sync', async ({ page, stream_doc }) => {
  await page.goto('/login'); // Regular Playwright's login logic

  const rtmpUrl = await page.locator('[data-test=rtmp-url]').innerText();
  const hlsUrl  = await page.locator('[data-test=hls-url]').innerText();

  const session = await stream_doc.session();

  const streamer = session.publish(rtmpUrl, {
    source: { kind: 'synthetic', pattern: 'bars', fps: 60 },
    // {kind: 'file', path: 'my_file.mp4' }
    // {kind: 'file', path: TEST_CORPUS.b_frames_h264}
    marker: true,
  });
  await streamer.waitUntilLive();

  await page.click('button#play');

  const viewer = await session.watch(hlsUrl);

  await viewer.mark('baseline', '30s');
  await streamer.degrade({ packetLoss: 0.3 });
  await viewer.mark('degraded', '15s');
  await streamer.restore();
  await viewer.mark('recovery', '10s');
  
  const m = await viewer.stop();
  
  expect(m.window('baseline').avDriftMs.status).toBe('measured'); // status might be: 'measured', 'missing_marker' or 'invalid'
  expect(Math.abs(m.window('baseline').avDriftMs.value)).toBeLessThan(50);
  expect(m.window('baseline').variants).toEqual(['1080p', '720p', '480p']);

  expect(m.window('baseline').stalls).toHaveLength(0);
  expect(m.window('degraded').video.fps.average).toBeGreaterThan(20);
  expect(m.window('recovery').avDriftMs.value).toBeLessThan(50);
});

StreamDoctor requirements

Below there is a list of features of StreamDoctor
✅ - let's do it in MVP
❌ - not for MVP
⚠️ - technical risk, requires validation

  1. Source
    ✅ synthetic video (test pattern, configurable fps/resolution/bitrate)
    ✅ reference marker - visual bars and audio bursts, encoding frame number and session ID ⚠️
    ✅ broadcasting from a file
    ❌ a set of "edge case" streams (strange H.264 profiles, negative timestamps etc.) ⚠️

  2. Orchestration
    ✅ session grouping a publisher and its viewers, isolated across parallel runs
    ✅ waitUntilLive()- synchronization with the actual start of broadcasting
    ✅ cleanup on test failure and on process kill
    ❌ named windows (mark()) assigned by marker
    ❌ multiple publishers within a single session
    ❌ session with multiple "hops"

  3. Metrics
    Structural (just playlist/container parsing)
    ✅ list of variants with their parameters
    ❌ presence of an audio track
    ✅ container type (MPEG-TS / CMAF)
    ❌ discontinuities
    ❌ PTS monotonicity
    ✅ time to first frame
    Content-based (requires decoding)
    ✅ frozen frames, black frames, silence
    ❌ fps, bitrate
    ❌ flickering ⚠️
    ❌ stalls ⚠️
    Reference (requires a marked stream)
    ❌ A/V synchronization ⚠️
    ✅ frame ordering
    ✅ ingest → output latency
    ❌ missing or duplicated frames
    ❌ VMAF / quality metrics ⚠️

  4. Chaos
    ❌ packet loss on the sender side, controlled throughout the test duration (degrade()) ⚠️
    ❌ restore() ⚠️
    ❌ latency, jitter, bandwidth limits ⚠️
    ❌ chaos on the receiver side (throttling, segment delaying) ⚠️

  5. Protocols

Protocol Direction MVP
RTMP/RTMPS sender ✅
MoQ sender ❌
SRT sender ❌
RTSP ⚠️ (we don't support that in Membrane yet) sender ❌
WHIP sender ❌
WebRTC (vendor SDK) ⚠️ sender ❌
HLS viewer ✅
WHEP viewer ❌
raw frames from browser players (e.g. IVS player/ custom WebRTC players) ⚠️ viewer ❌
MoQ viewer ❌
SRT viewer ❌
RTSP viewer ❌
RTMP/RTMPS viewer ❌
  1. Delivery
    ✅ daemon with REST API as delivered as a binary ⚠️
    ✅ SDK in TypeScript (daemon lazy start, daemon version check during handshake)
    ❌ SDK in Python
    ❌ Docker image
    ❌ daemon hosted "as a service" ⚠️

Blockers/decisions to make

  • Should daemon use Membrane/Boombox as a multimedia framework? (alternatively we could use e.g. MediaBunny)

Activity

  1. changed the title [-]MVP of Stream Doctor - tool for automated multimedia quality assurance[/-] [+]StreamDoctor requirements[/+] on Aug 20, 2026
  2. self-assigned this
    on Sep 10, 2026
  3. kidq330 commented on Oct 6, 2026

    @kidq330
    Member

    I'd propose a property-testing layer or some PBT framework that could be used by stream-doctor for driving semi-random testing of properties ubiquitous in streaming settings: data roundtrips and is processed irrespective of how it is partitioned into frames. An experiment in that vein has brought forth many findings for Membrane itself in terms of hardening reliability of our plugins, basing on https://github.com/whatyouhide/stream_data.

    Other relevant libraries in the ecosystem are:

    • PropEr - the original library StreamData is based on, which in turn bases itself on QuickCheck. It is GPL 3.0 licensed though. One notable pattern is stateful testing of FSMs and the like by generating a sequence of pre-defined commands.
    • property_damage - also for stateful testing, but from what I can tell this particular library targets asynchronous systems

    Some slides describing the methodology: https://www.cis.upenn.edu/~bcpierce/papers/Yow2022-Pierce.pdf. The piece to keep in mind is that quality of tests increases substantially while keeping complexity low, as opposed to more theoretical-heavy approaches like formal methods.

    It should be noted that other tools touting high degrees of reliability have also used PBT tools, like Dropbox and JaneStreet. Erlang itself has used QuickCheck for finding concurrency bugs.

    LLM notes: https://github.com/kidq330/stream_fuzz/tree/claude/clever-cori-wu9xbz/research_notes

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions