Documentation
¶
Overview ¶
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/moq.
Index ¶
- Constants
- func AudioTrackID(trackIndex int) byte
- type AudioInfo
- type AudioTrackStats
- type CaptionStats
- type ControlBroadcaster
- type DebugProvider
- type DemuxStats
- func (ds *DemuxStats) PTSDebug() PTSDebugStats
- func (ds *DemuxStats) RecordAudioFrame(trackIdx int, bytes int64, pts int64, sampleRate, channels int)
- func (ds *DemuxStats) RecordCaption(channel int)
- func (ds *DemuxStats) RecordResolution(width, height int)
- func (ds *DemuxStats) RecordSCTE35(event demux.SCTE35Event)
- func (ds *DemuxStats) RecordTimecode(tc string)
- func (ds *DemuxStats) RecordVideoCodec(codec string)
- func (ds *DemuxStats) RecordVideoFrame(bytes int64, isKeyframe bool, pts int64)
- func (ds *DemuxStats) Snapshot() (VideoStats, []AudioTrackStats, CaptionStats, SCTE35Stats)
- func (ds *DemuxStats) VideoBitrateKbps() float64
- func (ds *DemuxStats) VideoFPS() float64
- type IngestDebugStats
- type IngestLookup
- type MoQSession
- type MoQSessionConfig
- type PTSDebugStats
- type PTSWrapEvent
- type PipelineDebugSnapshot
- type PipelineDebugStats
- type Relay
- func (r *Relay) AddViewer(session Viewer)
- func (r *Relay) AudioInfo() AudioInfo
- func (r *Relay) AudioTrackCount() int
- func (r *Relay) BroadcastAudio(frame *media.AudioFrame)
- func (r *Relay) BroadcastCaptions(frame *ccx.CaptionFrame)
- func (r *Relay) BroadcastVideo(frame *media.VideoFrame)
- func (r *Relay) BroadcastVideoNoCache(frame *media.VideoFrame)
- func (r *Relay) RemoveViewer(id string)
- func (r *Relay) ReplayAudioToChannel(trackIndex int, ch chan<- *media.AudioFrame) int
- func (r *Relay) ReplayFullGOPToChannel(ch chan<- *media.VideoFrame) int
- func (r *Relay) SetAudioInfo(info AudioInfo)
- func (r *Relay) SetAudioTrackCount(count int)
- func (r *Relay) SetVideoInfo(info VideoInfo)
- func (r *Relay) VideoInfo() VideoInfo
- func (r *Relay) ViewerCount() int
- func (r *Relay) ViewerStatsAll() []ViewerStats
- func (r *Relay) WaitVideoInfo(ctx context.Context) bool
- type SCTE35Stats
- type SRTListFunc
- type SRTPullFunc
- type SRTPullInfo
- type SRTStopFunc
- type Server
- func (s *Server) APIHandler() http.Handler
- func (s *Server) GetPipeline(streamKey string) StatsProvider
- func (s *Server) GetRelay(streamKey string) *Relay
- func (s *Server) RegisterStream(streamKey string) *Relay
- func (s *Server) SetPipeline(streamKey string, p StatsProvider)
- func (s *Server) Start(ctx context.Context) error
- func (s *Server) UnregisterStream(streamKey string)
- type ServerConfig
- type StatsProvider
- type StatsProviderFunc
- type StreamFrameWriter
- type StreamInfo
- type StreamLister
- type StreamSnapshot
- type VideoInfo
- type VideoStats
- type Viewer
- type ViewerStats
Constants ¶
const ( TrackIDVideo byte = 0 TrackIDCaptions byte = 2 TrackIDAudioBase byte = 10 )
Track ID constants used to identify media types in the MoQ catalog and session logic. Audio tracks beyond the first use sequential IDs starting at TrackIDAudioBase.
Variables ¶
This section is empty.
Functions ¶
func AudioTrackID ¶
AudioTrackID converts a zero-based audio track index to its wire track ID.
Types ¶
type AudioInfo ¶
AudioInfo holds the audio codec parameters for a single track, derived from the first ADTS frame seen by the demuxer.
type AudioTrackStats ¶
type AudioTrackStats struct {
TrackIndex int `json:"trackIndex"`
Codec string `json:"codec"`
SampleRate int `json:"sampleRate"`
Channels int `json:"channels"`
Frames int64 `json:"frames"`
BitrateKbps float64 `json:"bitrateKbps"`
PTSErrors int64 `json:"ptsErrors"`
TotalBytes int64 `json:"totalBytes"`
}
AudioTrackStats holds per-track audio metrics for a stream.
type CaptionStats ¶
type CaptionStats struct {
ActiveChannels []int `json:"activeChannels"`
TotalFrames int64 `json:"totalFrames"`
}
CaptionStats tracks closed-caption activity across all channels.
type ControlBroadcaster ¶ added in v0.1.1
type ControlBroadcaster struct {
// contains filtered or unexported fields
}
ControlBroadcaster fans out messages from a single source channel to multiple subscriber channels. Each subscriber gets its own buffered channel; slow subscribers have messages dropped (non-blocking send) rather than blocking other subscribers or the source.
func NewControlBroadcaster ¶ added in v0.1.1
func NewControlBroadcaster() *ControlBroadcaster
NewControlBroadcaster creates a ControlBroadcaster ready for use.
func (*ControlBroadcaster) Run ¶ added in v0.1.1
func (b *ControlBroadcaster) Run(ctx context.Context, source <-chan []byte)
Run reads from the source channel and fans out each message to all subscribers. It blocks until ctx is cancelled or the source channel is closed. Non-blocking sends: if a subscriber's channel is full, the message is dropped for that subscriber (matching the Viewer drop pattern).
func (*ControlBroadcaster) Subscribe ¶ added in v0.1.1
func (b *ControlBroadcaster) Subscribe(id string) <-chan []byte
Subscribe creates a per-subscriber buffered channel and returns it. The caller must call Unsubscribe when done. If a channel already exists for the given id, it is closed and replaced.
func (*ControlBroadcaster) Unsubscribe ¶ added in v0.1.1
func (b *ControlBroadcaster) Unsubscribe(id string)
Unsubscribe removes and closes the subscriber's channel. It is safe to call multiple times for the same id.
type DebugProvider ¶
type DebugProvider interface {
StatsProvider
PipelineDebug() PipelineDebugStats
DemuxStats() *DemuxStats
}
DebugProvider extends StatsProvider with lower-level pipeline and demuxer diagnostics, exposed via the /api/streams/{key}/debug endpoint.
type DemuxStats ¶
type DemuxStats struct {
// contains filtered or unexported fields
}
DemuxStats accumulates stream telemetry from the demuxer in a concurrency-safe manner using atomic counters. It implements the demux.StatsRecorder interface and produces point-in-time Snapshots for the stats API.
Fields are organized by the mutex/mechanism that guards them:
- Atomic counters: lock-free concurrent reads/writes
- ptsWrapMu: PTS wrap event log
- timecodeMu: SMPTE timecode string
- mu: audio track accumulators, caption channels
- scte35Mu: SCTE-35 event log
- bitrateWindowMu: video bitrate sliding window
- fpsWindowMu: video FPS sliding window
- videoCodecMu: video codec label
func NewDemuxStats ¶
func NewDemuxStats() *DemuxStats
NewDemuxStats creates a DemuxStats ready for use as a StatsRecorder.
func (*DemuxStats) PTSDebug ¶
func (ds *DemuxStats) PTSDebug() PTSDebugStats
PTSDebug returns a snapshot of PTS debugging information.
func (*DemuxStats) RecordAudioFrame ¶
func (ds *DemuxStats) RecordAudioFrame(trackIdx int, bytes int64, pts int64, sampleRate, channels int)
RecordAudioFrame records an audio frame for the given track, creating the per-track accumulator on first use.
func (*DemuxStats) RecordCaption ¶
func (ds *DemuxStats) RecordCaption(channel int)
RecordCaption records a caption frame on the given channel.
func (*DemuxStats) RecordResolution ¶
func (ds *DemuxStats) RecordResolution(width, height int)
RecordResolution stores the detected video resolution from an SPS.
func (*DemuxStats) RecordSCTE35 ¶
func (ds *DemuxStats) RecordSCTE35(event demux.SCTE35Event)
RecordSCTE35 records a SCTE-35 event, maintaining a bounded recent-events window.
func (*DemuxStats) RecordTimecode ¶
func (ds *DemuxStats) RecordTimecode(tc string)
RecordTimecode stores the latest SMPTE 12M timecode string.
func (*DemuxStats) RecordVideoCodec ¶
func (ds *DemuxStats) RecordVideoCodec(codec string)
RecordVideoCodec stores the detected video codec label (e.g. "H.264", "H.265").
func (*DemuxStats) RecordVideoFrame ¶
func (ds *DemuxStats) RecordVideoFrame(bytes int64, isKeyframe bool, pts int64)
RecordVideoFrame records a video frame's size, type, and PTS, updating frame counters, GOP length, bitrate/FPS sliding windows, and PTS continuity.
func (*DemuxStats) Snapshot ¶
func (ds *DemuxStats) Snapshot() (VideoStats, []AudioTrackStats, CaptionStats, SCTE35Stats)
Snapshot produces a consistent point-in-time view of all stream statistics.
func (*DemuxStats) VideoBitrateKbps ¶
func (ds *DemuxStats) VideoBitrateKbps() float64
VideoBitrateKbps computes the current video bitrate from a 2-second sliding window of frame sizes.
func (*DemuxStats) VideoFPS ¶
func (ds *DemuxStats) VideoFPS() float64
VideoFPS computes the current frame rate from a 2-second sliding window.
type IngestDebugStats ¶
type IngestDebugStats struct {
BytesReceived int64 `json:"bytesReceived"`
ReadCount int64 `json:"readCount"`
ConnectedAt int64 `json:"connectedAt"`
UptimeMs int64 `json:"uptimeMs"`
RemoteAddr string `json:"remoteAddr"`
}
IngestDebugStats captures SRT ingest connection metrics for the debug API.
type IngestLookup ¶
type IngestLookup func(key string) *IngestDebugStats
IngestLookup resolves a stream key to its ingest debug stats, or nil if the stream is not currently being ingested.
type MoQSession ¶
type MoQSession struct {
// contains filtered or unexported fields
}
MoQSession manages a single MoQ viewer connection. It implements the Viewer interface so the Relay can fan out frames to it. Internally, it dispatches frames to per-track subscriptions, each with its own write loop and moqWriter.
func NewMoQSession ¶
func NewMoQSession(cfg MoQSessionConfig) *MoQSession
NewMoQSession creates a new MoQ session for the given stream key.
func (*MoQSession) ID ¶
func (m *MoQSession) ID() string
ID returns the unique identifier for this MoQ session.
func (*MoQSession) Run ¶
func (m *MoQSession) Run(ctx context.Context) error
Run starts the MoQ session control loop. It blocks until the session ends.
func (*MoQSession) SendAudio ¶
func (m *MoQSession) SendAudio(frame *media.AudioFrame)
SendAudio dispatches an audio frame to the matching audio subscription.
func (*MoQSession) SendCaptions ¶
func (m *MoQSession) SendCaptions(frame *ccx.CaptionFrame)
SendCaptions dispatches a caption frame to the caption subscription.
func (*MoQSession) SendVideo ¶
func (m *MoQSession) SendVideo(frame *media.VideoFrame)
SendVideo dispatches a video frame to the video subscription if active.
func (*MoQSession) Stats ¶
func (m *MoQSession) Stats() ViewerStats
Stats returns delivery metrics for this MoQ session.
type MoQSessionConfig ¶
type MoQSessionConfig struct {
ID string
Session *webtransport.Session
Control webtransport.Stream
StreamKey string
Relay *Relay
StatsProvider StatsProviderFunc
ControlBroadcaster *ControlBroadcaster
// OnDatagram is called when a WebTransport datagram arrives from a viewer.
// The callback receives the viewer's stream key and the raw datagram bytes.
// Called from the session's datagram read goroutine — must not block.
OnDatagram func(streamKey string, data []byte)
}
MoQSessionConfig holds the parameters for creating a new MoQ session.
type PTSDebugStats ¶
type PTSDebugStats struct {
FirstVideoPTS int64 `json:"firstVideoPTS"`
FirstAudioPTS int64 `json:"firstAudioPTS"`
LastVideoPTS int64 `json:"lastVideoPTS"`
LastAudioPTS int64 `json:"lastAudioPTS"`
VideoPTSWraps int64 `json:"videoPTSWraps"`
AudioPTSWraps int64 `json:"audioPTSWraps"`
RecentWraps []PTSWrapEvent `json:"recentWraps,omitempty"`
}
PTSDebugStats provides low-level PTS debugging information, including first/last timestamps and wrap events, exposed via the debug API endpoint.
type PTSWrapEvent ¶
type PTSWrapEvent struct {
Timestamp int64 `json:"ts"`
Track string `json:"track"`
OldPTS int64 `json:"oldPTS"`
NewPTS int64 `json:"newPTS"`
DeltaMs int64 `json:"deltaMs"`
}
PTSWrapEvent records a detected PTS wrap-around, which occurs when the 33-bit MPEG-TS PTS counter overflows (every ~26.5 hours).
type PipelineDebugSnapshot ¶
type PipelineDebugSnapshot struct {
Ingest *IngestDebugStats `json:"ingest,omitempty"`
Demuxer PTSDebugStats `json:"demuxer"`
Pipeline PipelineDebugStats `json:"pipeline"`
Viewers []ViewerStats `json:"viewers"`
}
PipelineDebugSnapshot is the JSON response for /api/streams/{key}/debug, aggregating ingest, demuxer, pipeline, and viewer diagnostics.
type PipelineDebugStats ¶
type PipelineDebugStats struct {
VideoForwarded int64 `json:"videoForwarded"`
AudioForwarded int64 `json:"audioForwarded"`
CaptionFwd int64 `json:"captionForwarded"`
LastVideoFwdPTS int64 `json:"lastVideoFwdPTS"`
LastAudioFwdPTS int64 `json:"lastAudioFwdPTS"`
VideoChanDepth int `json:"videoChanDepth"`
AudioChanDepth int `json:"audioChanDepth"`
}
PipelineDebugStats captures frame forwarding counters and channel depths for the demux-to-relay pipeline, useful for diagnosing backpressure.
type Relay ¶
type Relay struct {
// contains filtered or unexported fields
}
Relay is the fan-out hub for a single stream. It distributes video, audio, and caption frames from the pipeline to all connected MoQ viewers. It also caches the current GOP so that late-joining viewers can start playback immediately from the most recent keyframe, and recent audio frames so that new audio subscribers can pre-fill their buffers.
func (*Relay) AddViewer ¶
AddViewer replays the cached GOP to the viewer, then registers it for live frame delivery. Replay happens before registration so that BroadcastVideo cannot interleave live frames before the replay completes.
func (*Relay) AudioInfo ¶
AudioInfo returns the detected audio codec parameters, or sensible defaults if no audio frame has been seen yet.
func (*Relay) AudioTrackCount ¶
AudioTrackCount returns the number of audio tracks, defaulting to 1.
func (*Relay) BroadcastAudio ¶
func (r *Relay) BroadcastAudio(frame *media.AudioFrame)
BroadcastAudio sends an audio frame to all connected viewers and updates the per-track audio cache for late-joining subscriber replay.
func (*Relay) BroadcastCaptions ¶
func (r *Relay) BroadcastCaptions(frame *ccx.CaptionFrame)
BroadcastCaptions sends a caption frame to all connected viewers.
func (*Relay) BroadcastVideo ¶
func (r *Relay) BroadcastVideo(frame *media.VideoFrame)
BroadcastVideo sends a video frame to all connected viewers and updates the GOP cache. Codec detection is handled by the pipeline via SetVideoInfo.
func (*Relay) BroadcastVideoNoCache ¶ added in v0.1.3
func (r *Relay) BroadcastVideoNoCache(frame *media.VideoFrame)
BroadcastVideoNoCache sends a video frame to all connected viewers without storing it in the GOP cache. Use this for streams where every frame is independently decodable (e.g., raw YUV) and GOP caching provides no value.
Because no frame data is retained after this call returns, the caller may safely reuse the frame's WireData buffer on the next call. This eliminates per-frame allocation for high-throughput streams like raw video monitors.
Late-joining viewers on a no-cache relay will not receive a GOP replay; they simply wait for the next frame (~33ms at 30fps).
func (*Relay) RemoveViewer ¶
RemoveViewer unregisters a viewer by ID.
func (*Relay) ReplayAudioToChannel ¶
func (r *Relay) ReplayAudioToChannel(trackIndex int, ch chan<- *media.AudioFrame) int
ReplayAudioToChannel sends the cached recent audio frames for the given track index into a channel, pre-filling the subscriber's buffer so playback can start without waiting for new frames from the live edge. Returns the number of frames replayed.
func (*Relay) ReplayFullGOPToChannel ¶
func (r *Relay) ReplayFullGOPToChannel(ch chan<- *media.VideoFrame) int
ReplayFullGOPToChannel sends the entire cached GOP (keyframe + all delta frames) into a channel, bypassing the Viewer interface. The client-side renderer skips to the latest decoded frame, so replaying the full GOP provides immediate decodable content at the live edge. Returns the number of frames replayed.
func (*Relay) SetAudioInfo ¶
SetAudioInfo stores the audio codec parameters detected from the first audio frame. Called by the pipeline once ADTS header parsing succeeds.
func (*Relay) SetAudioTrackCount ¶
SetAudioTrackCount sets the number of audio tracks discovered by the demuxer, used to advertise available tracks during viewer connection setup.
func (*Relay) SetVideoInfo ¶
SetVideoInfo stores the video codec parameters detected from the first keyframe. Called by the pipeline once SPS parsing succeeds.
func (*Relay) VideoInfo ¶
VideoInfo returns the detected video codec and resolution, or sensible defaults if the first keyframe hasn't arrived yet.
func (*Relay) ViewerCount ¶
ViewerCount returns the number of currently connected viewers.
func (*Relay) ViewerStatsAll ¶
func (r *Relay) ViewerStatsAll() []ViewerStats
ViewerStatsAll returns delivery metrics for every connected viewer.
type SCTE35Stats ¶
type SCTE35Stats struct {
TotalEvents int64 `json:"totalEvents"`
Recent []demux.SCTE35Event `json:"recent,omitempty"`
}
SCTE35Stats summarizes SCTE-35 splice event activity for a stream.
type SRTPullFunc ¶
SRTPullFunc initiates an SRT caller-mode pull from a remote address.
type SRTPullInfo ¶
type SRTPullInfo struct {
Address string `json:"address"`
StreamKey string `json:"streamKey"`
StreamID string `json:"streamId,omitempty"`
}
SRTPullInfo describes an active SRT caller-mode pull, returned by the /api/srt-pull GET endpoint.
type SRTStopFunc ¶
SRTStopFunc stops an active SRT pull by stream key.
type Server ¶
type Server struct {
// contains filtered or unexported fields
}
Server is the WebTransport/HTTP3 distribution server. It manages relays, pipelines, viewer sessions, and serves both the WebTransport watch endpoints and the REST API.
func NewServer ¶
func NewServer(config ServerConfig) (*Server, error)
NewServer creates a distribution Server with the given configuration. It returns an error if required fields are missing.
func (*Server) APIHandler ¶
APIHandler returns an http.Handler for the HTTPS REST API, including stream listing, debug endpoints, cert hash, and SRT pull management.
func (*Server) GetPipeline ¶
func (s *Server) GetPipeline(streamKey string) StatsProvider
GetPipeline returns the StatsProvider for a stream key, or nil if not found.
func (*Server) RegisterStream ¶
RegisterStream creates a Relay for the given stream key and returns it. If the stream already has a relay, the existing one is returned. For new streams, OnStreamRegistered is called (if set) after releasing the lock. Concurrent calls with the same key are safe (only one creates a relay), but the callback may observe transient inconsistency if a concurrent UnregisterStream for the same key interleaves between the lock release and the callback invocation.
func (*Server) SetPipeline ¶
func (s *Server) SetPipeline(streamKey string, p StatsProvider)
SetPipeline associates a StatsProvider with a stream key. The stream must already be registered via RegisterStream.
func (*Server) Start ¶
Start launches the HTTP/3 WebTransport server and blocks until the context is cancelled or a fatal error occurs.
func (*Server) UnregisterStream ¶
UnregisterStream removes the relay and pipeline for a stream key. If the stream existed, OnStreamUnregistered is called (if set) after releasing the lock. If a concurrent RegisterStream for the same key races with this call, the callback may fire after a new relay has already been registered.
type ServerConfig ¶
type ServerConfig struct {
Addr string
WebDir string
Cert *certs.CertInfo
StreamLister StreamLister
IngestLookup IngestLookup
SRTPull SRTPullFunc
SRTStop SRTStopFunc
SRTList SRTListFunc
ExtraRoutes func(mux *http.ServeMux)
// OnStreamRegistered is called after a new stream relay is created
// and added to the server's stream map. It is NOT called when
// RegisterStream returns an existing relay for a duplicate key.
// The callback is invoked outside the server's mutex.
OnStreamRegistered func(key string, relay *Relay)
// OnStreamUnregistered is called after a stream is removed from
// the server's stream map. It is NOT called if the stream key
// was not present. The callback is invoked outside the server's mutex.
OnStreamUnregistered func(key string)
// ControlCh receives JSON-encoded control state. If set, a "control"
// track is advertised in the MoQ catalog and subscribers receive state
// updates as JSON objects. Each send produces one MoQ group.
// Messages are internally broadcast to all connected viewers via
// ControlBroadcaster.
ControlCh <-chan []byte
// OnDatagram is called when a WebTransport datagram arrives from a viewer.
// The callback receives the viewer's stream key and the raw datagram bytes.
// Called from the session's datagram read goroutine — must not block.
OnDatagram func(streamKey string, data []byte)
}
ServerConfig holds the configuration for the distribution Server, including listen addresses, TLS certificate, and callback hooks.
type StatsProvider ¶
type StatsProvider interface {
StreamSnapshot() StreamSnapshot
}
StatsProvider is implemented by Pipeline to supply stream statistics for the viewer stats overlay and the REST API.
type StatsProviderFunc ¶
type StatsProviderFunc func(streamKey string) StatsProvider
StatsProviderFunc resolves the StatsProvider for a stream key lazily, since the pipeline may not exist when the MoQ session is created.
type StreamFrameWriter ¶
type StreamFrameWriter interface {
// WriteStreamHeader writes the stream-level header (subgroup header)
// at the start of a new unidirectional stream.
WriteStreamHeader(w io.Writer, trackID byte, groupID uint32, timestampMS uint32) error
// WriteVideoFrame writes a single video frame (header + payload) to w,
// returning the total bytes written.
WriteVideoFrame(w io.Writer, frame *media.VideoFrame) (int64, error)
// WriteAudioFrame writes a single audio frame (header + payload) to w,
// returning the total bytes written.
WriteAudioFrame(w io.Writer, data []byte, timestampMS uint32) (int64, error)
// WriteDataObject writes a single data object (caption, stats JSON,
// control JSON, etc.) with header + payload to w, returning the total
// bytes written.
WriteDataObject(w io.Writer, data []byte, timestampMS uint32) (int64, error)
// StreamHeaderSize returns the byte size of the stream header written
// by WriteStreamHeader, used for accurate byte accounting.
StreamHeaderSize() int64
}
StreamFrameWriter abstracts the wire format used to write media data to WebTransport unidirectional streams. The MoQ writer implements this interface using MoQ Transport subgroup/object framing with LOC extensions.
func NewMoQWriter ¶
func NewMoQWriter(trackAlias uint64, publisherPriority byte) StreamFrameWriter
NewMoQWriter returns a StreamFrameWriter that produces MoQ-compliant data stream framing. trackAlias is a session-scoped identifier for the track, and publisherPriority sets the priority (0=highest, 255=lowest).
type StreamInfo ¶
type StreamInfo struct {
Key string `json:"key"`
Viewers int `json:"viewers"`
Description string `json:"description,omitempty"`
VideoCodec string `json:"videoCodec,omitempty"`
Width int `json:"width,omitempty"`
Height int `json:"height,omitempty"`
AudioTracks int `json:"audioTracks,omitempty"`
AudioChannels int `json:"audioChannels,omitempty"`
HasCaptions bool `json:"hasCaptions,omitempty"`
CaptionChannels []int `json:"captionChannels,omitempty"`
HasSCTE35 bool `json:"hasScte35,omitempty"`
Protocol string `json:"protocol,omitempty"`
UptimeMs int64 `json:"uptimeMs,omitempty"`
}
StreamInfo is the JSON-serializable summary of a live stream, returned by the /api/streams list endpoint and used by the multi-stream viewer.
type StreamLister ¶
type StreamLister func() []StreamInfo
StreamLister is a callback that returns the current list of active streams.
type StreamSnapshot ¶
type StreamSnapshot struct {
Timestamp int64 `json:"ts"`
UptimeMs int64 `json:"uptimeMs"`
Protocol string `json:"protocol"`
IngestBytes int64 `json:"ingestBytes"`
IngestKbps float64 `json:"ingestKbps"`
Video VideoStats `json:"video"`
Audio []AudioTrackStats `json:"audio"`
Captions CaptionStats `json:"captions"`
SCTE35 SCTE35Stats `json:"scte35"`
ViewerCount int `json:"viewerCount"`
Viewers []ViewerStats `json:"viewers,omitempty"`
}
StreamSnapshot is the top-level stats payload sent periodically to viewers over the control stream. It aggregates video, audio, caption, SCTE-35, and viewer metrics into a single JSON-serializable structure.
type VideoInfo ¶
type VideoInfo struct {
Codec string
Width int
Height int
DecoderConfig []byte // AVCDecoderConfigurationRecord or HEVCDecoderConfigurationRecord
}
VideoInfo holds the video codec string, resolution, and decoder configuration record. Sent to viewers during connection setup so they can configure their WebCodecs decoders immediately without waiting for the first keyframe.
type VideoStats ¶
type VideoStats struct {
Codec string `json:"codec"`
Width int `json:"width"`
Height int `json:"height"`
TotalFrames int64 `json:"totalFrames"`
KeyFrames int64 `json:"keyFrames"`
DeltaFrames int64 `json:"deltaFrames"`
CurrentGOPLen int `json:"currentGOPLen"`
BitrateKbps float64 `json:"bitrateKbps"`
FrameRate float64 `json:"frameRate"`
PTSErrors int64 `json:"ptsErrors"`
TotalBytes int64 `json:"totalBytes"`
Timecode string `json:"timecode,omitempty"`
}
VideoStats holds point-in-time video metrics for a stream, serialized as JSON in stats snapshots sent to viewers over the control stream.
type Viewer ¶
type Viewer interface {
ID() string
SendVideo(frame *media.VideoFrame)
SendAudio(frame *media.AudioFrame)
SendCaptions(frame *ccx.CaptionFrame)
Stats() ViewerStats
}
Viewer is the interface that a viewer session (single or mux) must implement to receive frames from a Relay.
type ViewerStats ¶
type ViewerStats struct {
ID string `json:"id"`
VideoSent int64 `json:"videoSent"`
AudioSent int64 `json:"audioSent"`
CaptionSent int64 `json:"captionSent"`
VideoDropped int64 `json:"videoDropped"`
AudioDropped int64 `json:"audioDropped"`
CaptionDropped int64 `json:"captionDropped"`
BytesSent int64 `json:"bytesSent"`
LastVideoTsMS int64 `json:"lastVideoTsMs,omitempty"`
LastAudioTsMS int64 `json:"lastAudioTsMs,omitempty"`
}
ViewerStats captures per-viewer delivery metrics including frame counts and drop rates, used for diagnostics and the stats overlay.