Documentation
¶
Overview ¶
Package domain defines core types shared across Open Streamer modules.
Index ¶
- Constants
- func IsCopyInput(in Input) bool
- func IsCopyShapeError(err error) bool
- func IsMixerInput(in Input) bool
- func IsMixerShapeError(err error) bool
- func ResolveAudioEncoder(codec AudioCodec) string
- func ResolveVideoEncoder(codec VideoCodec, hw HWAccel) string
- func ValidateCopyShape(s *Stream, lookup StreamLookup) error
- func ValidateMixerShape(s *Stream, lookup StreamLookup) error
- func ValidateStreamCode(s string) error
- func ValidateVODName(s string) error
- type AVCodec
- type AVPacket
- type AudioCodec
- type AudioConfig
- type AudioTranscodeConfig
- type CopyShapeError
- type DVRGap
- type DVRIndex
- type DecoderConfig
- type ErrorEntry
- type Event
- type EventType
- type GlobalConfig
- type HWAccel
- type Hook
- type HookID
- type HookType
- type Input
- type InputNetConfig
- type InterlaceMode
- type MixerShapeError
- type OutputProtocols
- type PushDestination
- type PushStatus
- type Recording
- type RecordingID
- type RecordingStatus
- type ResizeMode
- type Stream
- type StreamCode
- type StreamCodeFilter
- type StreamDVRConfig
- type StreamLookup
- type StreamStatus
- type ThumbnailConfig
- type TranscoderConfig
- type TranscoderGlobalConfig
- type VODMount
- type VODName
- type VideoCodec
- type VideoProfile
- type VideoTranscodeConfig
- type WatermarkConfig
- type WatermarkPosition
- type WatermarkType
Constants ¶
const ( // DefaultBufferCapacity is the per-subscriber channel buffer size in // MPEG-TS packets. 1024 packets ≈ 1 MiB ≈ ~1.5s of 1080p60 video at // 5Mbps — enough headroom for HLS pull bursts (one segment per Read) // without growing memory unbounded across many subscribers. DefaultBufferCapacity = 1024 // DefaultInputPacketTimeoutSec is the manager's failover threshold: the // maximum gap (in seconds) without a successful read on the active // input before it is marked failed and the next-priority input takes // over. DefaultInputPacketTimeoutSec = 30 // DefaultLiveSegmentSec is the live HLS / DASH segment target length // in seconds when the operator leaves the field unset. DefaultLiveSegmentSec = 2 // DefaultLiveWindow is the segment count in the sliding playlist // window (HLS / DASH live). DefaultLiveWindow = 12 // DefaultLiveHistory is extra segments retained on disk after they // leave the live window — 0 = drop immediately after sliding out. DefaultLiveHistory = 0 // DefaultDVRSegmentDuration is the DVR segment length in seconds when // StreamDVRConfig.SegmentDuration is zero. DefaultDVRSegmentDuration = 4 // DefaultDVRRoot is the on-disk root directory used as the parent of // "{DefaultDVRRoot}/{streamCode}" when StreamDVRConfig.StoragePath is // empty. DefaultDVRRoot = "./out/dvr" // DefaultPushTimeoutSec is the publish handshake budget for an outbound // push destination when PushDestination.TimeoutSec is zero. DefaultPushTimeoutSec = 10 // DefaultPushRetryTimeoutSec is the delay between retry attempts. DefaultPushRetryTimeoutSec = 5 // DefaultHookMaxRetries is the per-hook retry budget when the user // leaves Hook.MaxRetries=0. DefaultHookMaxRetries = 3 // DefaultHookTimeoutSec is the per-attempt delivery timeout when // Hook.TimeoutSec=0. DefaultHookTimeoutSec = 10 // DefaultVideoBitrateK is the fallback target video bitrate (kbps) // when a profile leaves Bitrate=0. DefaultVideoBitrateK = 2500 // DefaultAudioBitrateK is the audio bitrate (kbps) when // AudioTranscodeConfig.Bitrate is zero. DefaultAudioBitrateK = 128 // DefaultHLSPlaylistTimeoutSec is the upstream HLS pull playlist GET // timeout (seconds) when InputNetConfig.ConnectTimeoutSec is zero. DefaultHLSPlaylistTimeoutSec = 15 // DefaultHLSSegmentTimeoutSec is the upstream HLS segment GET timeout // floor — segments can be many MB so this is held above the playlist // timeout. DefaultHLSSegmentTimeoutSec = 60 // DefaultHLSMaxSegmentBuffer caps pre-fetched HLS segments held in // memory per stream when IngestorConfig.HLSMaxSegmentBuffer is zero. DefaultHLSMaxSegmentBuffer = 8 // DefaultSRTLatencyMS is the SRT ARQ latency window (milliseconds) when // SRTListenerConfig.LatencyMS is zero. 120ms matches Haivision's // reference for low-latency contribution links. DefaultSRTLatencyMS = 120 // DefaultFFmpegPath is the executable name resolved against $PATH when // TranscoderConfig.FFmpegPath is empty. Operators on bespoke layouts // (e.g. /opt/ffmpeg/bin/ffmpeg) must set the full path explicitly. DefaultFFmpegPath = "ffmpeg" // DefaultListenHost is the bind address used for RTMP / RTSP / SRT // listeners when ListenHost is empty. "0.0.0.0" listens on all // interfaces — the standard server behaviour. DefaultListenHost = "0.0.0.0" // DefaultRTMPConnectTimeoutSec is the dial timeout (seconds) for RTMP // pull when InputNetConfig.ConnectTimeoutSec is zero. DefaultRTMPConnectTimeoutSec = 10 // DefaultRTSPConnectTimeoutSec is the dial / read timeout (seconds) // for RTSP pull when InputNetConfig.ConnectTimeoutSec is zero. DefaultRTSPConnectTimeoutSec = 10 )
Default* constants are the runtime-applied values when the matching configuration field is left zero / empty by the user. They are the SINGLE SOURCE OF TRUTH for implicit defaults — every consumer (handler, packager, transcoder, validator) must reference these instead of inlining its own literal so behaviour stays consistent across services.
When changing a default here, audit references with:
grep -RIn 'Default[A-Z][A-Za-z]*' internal/ config/
to make sure no stale literal still exists in a service module.
const MaxStreamCodeLen = 128
MaxStreamCodeLen is the maximum length of a user-defined stream code.
const MaxVODNameLen = 64
MaxVODNameLen bounds the length of a VOD mount name used as a URL host component.
Variables ¶
This section is empty.
Functions ¶
func IsCopyInput ¶ added in v0.0.20
IsCopyInput reports whether the given Input is a `copy://` reference. Convenience helper for callers that want to short-circuit per-input logic (e.g. skip network reconnect logic for copy inputs).
func IsCopyShapeError ¶ added in v0.0.20
IsCopyShapeError reports whether err is a *CopyShapeError.
func IsMixerInput ¶ added in v0.0.22
IsMixerInput reports whether the given Input is a `mixer://` reference.
func IsMixerShapeError ¶ added in v0.0.22
IsMixerShapeError reports whether err is a *MixerShapeError.
func ResolveAudioEncoder ¶ added in v0.0.30
func ResolveAudioEncoder(codec AudioCodec) string
ResolveAudioEncoder maps a user-facing codec to FFmpeg's encoder name. Empty / "copy" → AAC default (since copy is decided separately via AudioTranscodeConfig.Copy).
func ResolveVideoEncoder ¶ added in v0.0.30
func ResolveVideoEncoder(codec VideoCodec, hw HWAccel) string
ResolveVideoEncoder maps a user-facing codec string + global HW backend to the FFmpeg encoder name that buildFFmpegArgs will emit.
Routing highlights:
- "" / "h264" / "avc" + HW=nvenc → "h264_nvenc"; else "libx264"
- "h265" / "hevc" + HW=nvenc → "hevc_nvenc"; else "libx265"
- VAAPI / QSV / VideoToolbox: no implicit routing — caller must spell the full encoder name (e.g. "h264_vaapi"); empty stays "libx264".
func ValidateCopyShape ¶ added in v0.0.20
func ValidateCopyShape(s *Stream, lookup StreamLookup) error
ValidateCopyShape enforces copy:// constraints on a single stream:
- Self-copy (`copy://A` inside stream A) is rejected — a stream cannot re-stream itself; that's an infinite fan-out loop.
- When upstream X has an ABR ladder, downstream MUST satisfy: a) `copy://X` is the SOLE input (no fallback in v1) b) downstream's own `transcoder` field is nil (ladder is inherited from upstream; configuring local re-transcode is ambiguous)
- When mixing copy:// inputs with regular network inputs in the same priority list, all referenced upstreams must be single-stream (no ABR), since failover between rendition shapes is not supported in v1.
`lookup` resolves upstream streams. Missing upstream is treated as "shape unknown" — the rule it enables is skipped, never failed. The coordinator validates upstream presence at start time as a hard error.
func ValidateMixerShape ¶ added in v0.0.22
func ValidateMixerShape(s *Stream, lookup StreamLookup) error
ValidateMixerShape enforces mixer:// constraints on a single stream:
- Self-mix (`mixer://A,X` or `mixer://X,A` inside stream A) is rejected — a stream can't mix with itself.
- mixer:// must be the SOLE input — fallback inputs are not supported in v1 (failure semantics differ from regular failover; mixing across two unrelated mixer specs is undefined).
ABR upstreams ARE allowed:
- When the video upstream has an ABR ladder AND the downstream has no own transcoder, the runtime mirrors the video ladder (N rungs out, audio fanned-out across them). When the downstream HAS its own transcoder, the runtime taps only the best rendition of each upstream and feeds the encoder.
- Either upstream's audio is always single-source — the best rendition of the audio upstream when it's ABR.
`lookup` resolves upstream streams. Missing upstream is treated as "shape unknown" — the rule it enables is skipped, never failed. The MixerReader catches missing upstream at runtime as a hard error.
func ValidateStreamCode ¶
ValidateStreamCode reports whether s is a non-empty valid stream code.
func ValidateVODName ¶
ValidateVODName reports whether s is a non-empty, URL-host-safe VOD mount name.
Types ¶
type AVCodec ¶
type AVCodec uint8
AVCodec identifies elementary stream codec for AVPacket payloads.
type AVPacket ¶
type AVPacket struct {
Codec AVCodec
Data []byte
PTSms uint64
DTSms uint64
KeyFrame bool
Discontinuity bool
}
AVPacket is one decoded video access unit (Annex B H.264/H.265) or one AAC frame (ADTS in Data). PTSms and DTSms are presentation / decode timestamps in milliseconds (MPEG-TS / gomedia convention).
type AudioCodec ¶
type AudioCodec string
AudioCodec identifies the audio compression format.
const ( AudioCodecAAC AudioCodec = "aac" // default for HLS/DASH AudioCodecMP3 AudioCodec = "mp3" // legacy compatibility AudioCodecOpus AudioCodec = "opus" // best for WebRTC / low-latency AudioCodecAC3 AudioCodec = "ac3" // Dolby Digital — broadcast use AudioCodecCopy AudioCodec = "copy" // passthrough — no re-encode )
AudioCodec values name supported output audio codecs.
type AudioConfig ¶
type AudioConfig struct {
Codec AudioCodec `json:"codec" yaml:"codec"`
// Bitrate is the audio bitrate in kbps. Typical: 128 (stereo), 192 (high quality).
Bitrate int `json:"bitrate" yaml:"bitrate"`
// SampleRate is the output sample rate in Hz. Typical: 44100, 48000.
SampleRate int `json:"sample_rate" yaml:"sample_rate"`
// Channels: 1 = mono, 2 = stereo, 6 = 5.1 surround.
Channels int `json:"channels" yaml:"channels"`
// Language is the ISO 639-1 code embedded in HLS/DASH metadata, e.g. "en", "vi".
Language string `json:"language" yaml:"language"`
// Normalize applies EBU R128 loudness normalization (-23 LUFS).
// Useful for broadcast compliance.
Normalize bool `json:"normalize" yaml:"normalize"`
}
AudioConfig defines the audio encoding settings applied to all output profiles.
type AudioTranscodeConfig ¶
type AudioTranscodeConfig struct {
// Copy copies origin audio without re-encoding.
Copy bool `json:"copy" yaml:"copy"`
Codec AudioCodec `json:"codec" yaml:"codec"`
// Bitrate is the audio bitrate in kbps.
Bitrate int `json:"bitrate" yaml:"bitrate"`
// SampleRate is output sample rate in Hz.
SampleRate int `json:"sample_rate" yaml:"sample_rate"`
// Channels: 1 = mono, 2 = stereo, 6 = 5.1.
Channels int `json:"channels" yaml:"channels"`
// Language is ISO 639-1 code, e.g. "en", "vi".
Language string `json:"language" yaml:"language"`
// Normalize applies EBU R128 loudness normalization.
Normalize bool `json:"normalize" yaml:"normalize"`
}
AudioTranscodeConfig defines audio transcoding behavior.
type CopyShapeError ¶ added in v0.0.20
type CopyShapeError struct {
StreamCode StreamCode
Reason string
}
CopyShapeError reports a copy:// configuration that violates the v1 constraints (e.g. local transcoder set when upstream has ABR, mixed shapes in the input list). The Reason string is API-surface text — the handler returns it verbatim in the 400 response.
func (*CopyShapeError) Error ¶ added in v0.0.20
func (e *CopyShapeError) Error() string
type DVRGap ¶
type DVRGap struct {
From time.Time `json:"from" yaml:"from"` // wall time gap started
To time.Time `json:"to" yaml:"to"` // wall time recording resumed
Duration time.Duration `json:"duration" yaml:"duration"` // To - From
}
DVRGap represents a period of signal loss or server downtime.
type DVRIndex ¶
type DVRIndex struct {
StreamCode StreamCode `json:"stream_code" yaml:"stream_code"`
StartedAt time.Time `json:"started_at" yaml:"started_at"`
LastSegmentAt time.Time `json:"last_segment_at,omitempty" yaml:"last_segment_at,omitempty"`
SegmentCount int `json:"segment_count" yaml:"segment_count"`
TotalSizeBytes int64 `json:"total_size_bytes" yaml:"total_size_bytes"`
// Gaps is the list of known signal-loss / server-restart interruptions.
Gaps []DVRGap `json:"gaps,omitempty" yaml:"gaps,omitempty"`
}
DVRIndex is the on-disk metadata index for a stream's DVR recording. Written atomically to {SegmentDir}/index.json after every segment flush.
Deliberately lightweight — no per-segment details. Per-segment timeline (wall time, duration, discontinuity) lives in playlist.m3u8 via #EXT-X-PROGRAM-DATE-TIME and #EXTINF tags.
type DecoderConfig ¶
type DecoderConfig struct {
// Name is the FFmpeg decoder name.
// "" = let FFmpeg choose automatically.
// Examples: "h264_cuvid", "h264_qsv".
Name string `json:"name,omitempty" yaml:"name,omitempty"`
}
DecoderConfig defines decoder behavior.
type ErrorEntry ¶ added in v0.0.8
ErrorEntry is a single recorded error with the time it occurred. Used by manager (per input) and transcoder (per profile) to expose a short rolling history of errors via their RuntimeStatus APIs.
type Event ¶
type Event struct {
ID string `json:"id"` // UUID for idempotent delivery
Type EventType `json:"type"`
StreamCode StreamCode `json:"stream_code"`
OccurredAt time.Time `json:"occurred_at"`
Payload map[string]any `json:"payload,omitempty"` // event-specific fields
}
Event is an immutable fact describing a domain state change.
type EventType ¶
type EventType string
EventType identifies the kind of domain event that occurred.
const ( // Stream lifecycle — published by coordinator and API handler. EventStreamCreated EventType = "stream.created" EventStreamStarted EventType = "stream.started" EventStreamStopped EventType = "stream.stopped" EventStreamDeleted EventType = "stream.deleted" // Input health — published by ingestor worker and stream manager. EventInputConnected EventType = "input.connected" // source connected successfully EventInputReconnecting EventType = "input.reconnecting" // transient error, retrying EventInputDegraded EventType = "input.degraded" // error detected by manager EventInputFailed EventType = "input.failed" // worker exited / non-retriable EventInputFailover EventType = "input.failover" // switched to lower-priority input // DVR recordings — published by dvr.Service. EventRecordingStarted EventType = "recording.started" EventRecordingStopped EventType = "recording.stopped" EventRecordingFailed EventType = "recording.failed" EventSegmentWritten EventType = "segment.written" // Transcoder — published by transcoder.Service. EventTranscoderStarted EventType = "transcoder.started" EventTranscoderStopped EventType = "transcoder.stopped" EventTranscoderError EventType = "transcoder.error" )
EventType values are emitted on the event bus for stream lifecycle, inputs, recordings, and segments.
type GlobalConfig ¶
type GlobalConfig struct {
Server *config.ServerConfig `json:"server,omitempty" yaml:"server,omitempty"`
Listeners *config.ListenersConfig `json:"listeners,omitempty" yaml:"listeners,omitempty"`
Ingestor *config.IngestorConfig `json:"ingestor,omitempty" yaml:"ingestor,omitempty"`
Buffer *config.BufferConfig `json:"buffer,omitempty" yaml:"buffer,omitempty"`
Transcoder *config.TranscoderConfig `json:"transcoder,omitempty" yaml:"transcoder,omitempty"`
Publisher *config.PublisherConfig `json:"publisher,omitempty" yaml:"publisher,omitempty"`
Manager *config.ManagerConfig `json:"manager,omitempty" yaml:"manager,omitempty"`
Hooks *config.HooksConfig `json:"hooks,omitempty" yaml:"hooks,omitempty"`
Log *config.LogConfig `json:"log,omitempty" yaml:"log,omitempty"`
}
GlobalConfig holds all runtime configuration that is persisted in the store (as opposed to config.StorageConfig which is bootstrap-only from config.yaml/env).
Pointer fields: nil means the section is not configured and the corresponding service should not start. This allows users to enable/disable entire subsystems by adding or removing config sections via the API.
type HWAccel ¶
type HWAccel string
HWAccel selects the hardware acceleration backend for encoding/decoding.
const ( HWAccelNone HWAccel = "none" // CPU only (libx264, libx265) HWAccelNVENC HWAccel = "nvenc" // NVIDIA GPU (h264_nvenc, hevc_nvenc) HWAccelVAAPI HWAccel = "vaapi" // Intel/AMD GPU via VA-API (Linux) HWAccelVideoToolbox HWAccel = "videotoolbox" // Apple GPU (macOS) HWAccelQSV HWAccel = "qsv" // Intel Quick Sync Video )
HWAccel values map to FFmpeg hardware device options.
type Hook ¶
type Hook struct {
ID HookID `json:"id" yaml:"id"`
Name string `json:"name" yaml:"name"`
Type HookType `json:"type" yaml:"type"`
Target string `json:"target" yaml:"target"` // HTTP URL or Kafka topic
Secret string `json:"secret" yaml:"secret"` // HMAC-SHA256 signing secret (HTTP only)
// EventTypes filters which events trigger delivery. Empty = all events.
EventTypes []EventType `json:"event_types,omitempty" yaml:"event_types,omitempty"`
// StreamCodes filters delivery by stream code.
// Only and Except are mutually exclusive; Only takes precedence when both are set.
// Omitting the field (nil) means all streams are included.
StreamCodes *StreamCodeFilter `json:"stream_codes,omitempty" yaml:"stream_codes,omitempty"`
// Metadata holds user-defined key-value pairs merged into every event payload
// delivered by this hook. Useful for tagging events with custom context
// (e.g. environment, tenant ID, region) without modifying the server config.
Metadata map[string]string `json:"metadata,omitempty" yaml:"metadata,omitempty"`
Enabled bool `json:"enabled" yaml:"enabled"`
// MaxRetries is the number of delivery attempts before giving up.
// 0 means use the server default (3).
MaxRetries int `json:"max_retries" yaml:"max_retries"`
// TimeoutSec is the per-attempt delivery timeout in seconds.
// 0 means use the server default (10s).
TimeoutSec int `json:"timeout_sec" yaml:"timeout_sec"`
}
Hook is a registered external integration that receives domain events.
type Input ¶
type Input struct {
// URL is the source endpoint. See the package doc for supported formats.
URL string `json:"url" yaml:"url"`
// Priority determines failover order. Lower value = higher priority.
// The Stream Manager always prefers the lowest-priority alive input.
Priority int `json:"priority" yaml:"priority"`
// Headers are arbitrary HTTP headers sent with every request for HTTP/HLS inputs.
// Common uses:
// "Authorization": "Bearer <token>"
// "Authorization": "Basic <base64(user:pass)>"
// "X-Custom-Token": "secret"
Headers map[string]string `json:"headers,omitempty" yaml:"headers,omitempty"`
// Params are extra URL query parameters merged into the source URL before
// connecting. Used for protocols that carry credentials or options in the
// query string (SRT ?passphrase=, S3 ?access_key= / ?secret_key=, etc.).
// "passphrase": "my-srt-passphrase"
// "access_key": "AKID..." (S3)
// "secret_key": "wJal..." (S3)
Params map[string]string `json:"params,omitempty" yaml:"params,omitempty"`
// Net controls reconnect and timeout behaviour.
Net InputNetConfig `json:"net,omitempty" yaml:"net,omitempty"`
// Alive is a runtime-only field updated by the Stream Manager health checker.
// Not persisted to storage.
Alive bool `json:"-" yaml:"-"`
}
Input is a single ingest source for a stream. Multiple inputs can be configured; the Stream Manager selects the active one based on Priority and runtime health (Alive flag).
The only required field is URL. The ingestor derives the ingest protocol and connection mode (pull vs push-listen) automatically from the URL scheme and host — no additional protocol configuration is needed.
Supported URL formats:
Pull (server connects to remote source): rtmp://server.com/live/stream_key RTMP pull from remote rtsp://camera.local:554/stream RTSP pull (IP camera) http://cdn.example.com/live.ts HTTP MPEG-TS stream https://cdn.example.com/playlist.m3u8 HLS pull (grafov m3u8 parser) udp://239.1.1.1:5000 UDP multicast MPEG-TS srt://relay.example.com:9999 SRT pull (caller mode) file:///recordings/source.ts local file (loops if ?loop=true) Push (external encoder connects to our server): rtmp://0.0.0.0:1935/live/stream_key RTMP push — our RTMP server listens srt://0.0.0.0:9999?streamid=stream_key SRT push — our SRT server listens
Push mode is detected automatically when the URL host is a wildcard address (0.0.0.0, ::, empty) and the scheme is rtmp or srt.
type InputNetConfig ¶
type InputNetConfig struct {
// ConnectTimeoutSec caps each HTTP round-trip (headers + full body) for pull
// readers that use net/http (e.g. HLS playlist and segment GETs). Zero uses
// the reader's default (30s for HLS).
ConnectTimeoutSec int `json:"connect_timeout_sec,omitempty" yaml:"connect_timeout_sec,omitempty"`
// ReadTimeoutSec is the max silence duration before declaring the input dead.
ReadTimeoutSec int `json:"read_timeout_sec,omitempty" yaml:"read_timeout_sec,omitempty"`
// Reconnect enables automatic reconnection when the input drops.
Reconnect bool `json:"reconnect,omitempty" yaml:"reconnect,omitempty"`
// ReconnectDelaySec is the initial delay before the first reconnect attempt.
ReconnectDelaySec int `json:"reconnect_delay_sec,omitempty" yaml:"reconnect_delay_sec,omitempty"`
// ReconnectMaxDelaySec caps the exponential backoff delay.
ReconnectMaxDelaySec int `json:"reconnect_max_delay_sec,omitempty" yaml:"reconnect_max_delay_sec,omitempty"`
// MaxReconnects is the total number of reconnect attempts (0 = unlimited).
MaxReconnects int `json:"max_reconnects,omitempty" yaml:"max_reconnects,omitempty"`
// InsecureTLS disables TLS certificate verification for HTTPS pulls
// (HLS playlist + segment GETs). Default false — leave secure-by-default
// for production. Use only when the source uses a self-signed,
// expired, or otherwise-invalid certificate that you trust at the
// network level (private VLAN, fixed IP allowlist).
InsecureTLS bool `json:"insecure_tls,omitempty" yaml:"insecure_tls,omitempty"`
}
InputNetConfig controls reconnect and timeout behaviour for an input.
type InterlaceMode ¶ added in v0.0.6
type InterlaceMode string
InterlaceMode selects deinterlacing behavior for the source.
const ( InterlaceAuto InterlaceMode = "auto" // detect parity each frame InterlaceTopField InterlaceMode = "tff" // top field first (BBC HD, most ATSC) InterlaceBottomField InterlaceMode = "bff" // bottom field first (legacy DV) InterlaceProgressive InterlaceMode = "progressive" // assert source is progressive — skip filter )
InterlaceMode values map to yadif/yadif_cuda parameters. "" disables the filter.
type MixerShapeError ¶ added in v0.0.22
type MixerShapeError struct {
StreamCode StreamCode
Reason string
}
MixerShapeError reports a mixer:// configuration that violates the v1 constraints. Reason is API-surface text — handler returns it verbatim.
func (*MixerShapeError) Error ¶ added in v0.0.22
func (e *MixerShapeError) Error() string
type OutputProtocols ¶
type OutputProtocols struct {
// HLS enables Apple HTTP Live Streaming (m3u8 + segments over HTTP).
// Compatible with browsers, iOS, Android, Smart TVs.
HLS bool `json:"hls" yaml:"hls"`
// DASH enables MPEG-DASH packaging over HTTP.
// Required for Widevine/PlayReady DRM.
DASH bool `json:"dash" yaml:"dash"`
// RTSP opens an RTSP listener for pull clients (VLC, broadcast tools).
RTSP bool `json:"rtsp" yaml:"rtsp"`
// RTMP opens an RTMP publish endpoint for legacy players/CDNs.
RTMP bool `json:"rtmp" yaml:"rtmp"`
// SRT opens an SRT listener port for contribution-quality pull.
SRT bool `json:"srt" yaml:"srt"`
}
OutputProtocols defines which delivery protocols are opened for a stream. Each enabled protocol starts a corresponding listener or packager. Protocol-level settings (ports, segment duration, CDN URL, etc.) are configured globally in the server config.
type PushDestination ¶
type PushDestination struct {
// URL is the destination ingest endpoint.
// Supported schemes:
// rtmp:// — plain TCP, default port 1935 (e.g. rtmp://a.rtmp.youtube.com/live2/{key})
// rtmps:// — TLS-wrapped RTMP, default port 443 (e.g. rtmps://live-api-s.facebook.com:443/rtmp/{key})
URL string `json:"url" yaml:"url"`
// Enabled controls whether this destination is active.
Enabled bool `json:"enabled" yaml:"enabled"`
// TimeoutSec is the connection/write timeout in seconds.
TimeoutSec int `json:"timeout_sec" yaml:"timeout_sec"`
// RetryTimeoutSec is the delay between retry attempts in seconds.
RetryTimeoutSec int `json:"retry_timeout_sec" yaml:"retry_timeout_sec"`
// Limit is the maximum number of retry attempts. 0 = unlimited.
Limit int `json:"limit" yaml:"limit"`
// Comment is a human-readable note for this destination.
Comment string `json:"comment" yaml:"comment"`
// Status is a runtime-only field updated by the publisher.
// Not persisted to storage.
Status PushStatus `json:"status,omitempty" yaml:"-"`
}
PushDestination is an external endpoint the server actively pushes the stream to.
type PushStatus ¶
type PushStatus string
PushStatus is the runtime state of a push destination.
const ( PushStatusIdle PushStatus = "idle" PushStatusConnecting PushStatus = "connecting" PushStatusActive PushStatus = "active" PushStatusRetrying PushStatus = "retrying" PushStatusFailed PushStatus = "failed" PushStatusDisabled PushStatus = "disabled" )
PushStatus values describe outbound publisher connectivity.
type Recording ¶
type Recording struct {
ID RecordingID `json:"id" yaml:"id"`
StreamCode StreamCode `json:"stream_code" yaml:"stream_code"`
StartedAt time.Time `json:"started_at" yaml:"started_at"`
StoppedAt *time.Time `json:"stopped_at,omitempty" yaml:"stopped_at,omitempty"`
Status RecordingStatus `json:"status" yaml:"status"`
// SegmentDir is the absolute path to the directory holding TS files,
// playlist.m3u8, and index.json.
SegmentDir string `json:"segment_dir" yaml:"segment_dir"`
}
Recording represents the lifecycle metadata for a DVR recording session. ID equals StreamCode — one persistent recording per stream. Segment data lives in DVRIndex (index.json on disk), not here.
type RecordingID ¶
type RecordingID string
RecordingID is the unique identifier for a DVR recording. Always equals the stream code — one recording per stream.
type RecordingStatus ¶
type RecordingStatus string
RecordingStatus represents the lifecycle state of a recording.
const ( RecordingStatusRecording RecordingStatus = "recording" RecordingStatusStopped RecordingStatus = "stopped" RecordingStatusFailed RecordingStatus = "failed" )
RecordingStatus values.
type ResizeMode ¶ added in v0.0.6
type ResizeMode string
ResizeMode controls how the source frame is fitted into the output dimensions.
const ( ResizeModePad ResizeMode = "pad" // letterbox: keep aspect, fill remainder with black ResizeModeCrop ResizeMode = "crop" // fill: keep aspect, crop excess ResizeModeStretch ResizeMode = "stretch" // distort: scale to W:H, ignore source aspect ResizeModeFit ResizeMode = "fit" // keep aspect, no padding (output may be smaller than W:H) )
ResizeMode values match Flussonic's resize modes. "" defaults to ResizeModePad.
func ResolveResizeMode ¶ added in v0.0.30
func ResolveResizeMode(m ResizeMode) ResizeMode
ResolveResizeMode normalizes a free-form resize mode to the canonical constant. Empty / unknown → ResizeModePad.
type Stream ¶
type Stream struct {
// Code is the unique key chosen by the user ([a-zA-Z0-9_]).
Code StreamCode `json:"code" yaml:"code"`
Name string `json:"name" yaml:"name"`
Description string `json:"description" yaml:"description"`
Tags []string `json:"tags" yaml:"tags"`
// StreamKey is used to authenticate RTMP/SRT push ingest.
StreamKey string `json:"stream_key" yaml:"stream_key"`
// Status is the runtime lifecycle state.
// It is never persisted — always computed from the coordinator's in-memory
// state and overlaid by the API layer before returning responses to clients.
Status StreamStatus `json:"-" yaml:"-"`
// Disabled when true excludes the stream from server bootstrap and rejects pipeline Start.
Disabled bool `json:"disabled" yaml:"disabled"`
// Inputs are the available ingest sources ordered by Priority.
// The Stream Manager monitors health and switches between them on failure.
Inputs []Input `json:"inputs" yaml:"inputs"`
// Transcoder controls encoding/decoding settings.
// nil means no transcoding for this stream.
Transcoder *TranscoderConfig `json:"transcoder,omitempty" yaml:"transcoder,omitempty"`
// Protocols defines which delivery protocols are opened for this stream.
// The server opens a listener/packager for each enabled protocol.
// Protocol-level config (ports, segment duration, CDN URL) lives in server config.
Protocols OutputProtocols `json:"protocols" yaml:"protocols"`
// Push is the list of external destinations the server actively pushes to.
// Each entry defines one push target (YouTube, Facebook, Twitch, CDN relay, etc.).
Push []PushDestination `json:"push" yaml:"push"`
// DVR overrides the global DVR settings for this specific stream.
// If nil, the global config is used (when DVR is enabled globally).
DVR *StreamDVRConfig `json:"dvr,omitempty" yaml:"dvr,omitempty"`
// Watermark is an optional text or image overlay applied before encoding.
Watermark *WatermarkConfig `json:"watermark,omitempty" yaml:"watermark,omitempty"`
// Thumbnail controls periodic screenshot generation for preview images.
Thumbnail *ThumbnailConfig `json:"thumbnail,omitempty" yaml:"thumbnail,omitempty"`
}
Stream is the central domain entity. It describes everything needed to ingest, process, and deliver a live stream.
func (*Stream) ValidateInputPriorities ¶
ValidateInputPriorities enforces that input priorities are contiguous and sorted. For N inputs, expected priorities are exactly 0..N-1 in ascending order.
func (*Stream) ValidateUniqueInputs ¶
ValidateUniqueInputs enforces that inputs in one stream are not duplicated. Two inputs are considered duplicates if their URL (trimmed) is identical.
type StreamCode ¶
type StreamCode string
StreamCode is the user-assigned primary key for a stream. Allowed characters: a-z, A-Z, 0-9, underscore.
func CopyInputTarget ¶ added in v0.0.20
func CopyInputTarget(in Input) (StreamCode, error)
CopyInputTarget extracts the upstream code from a copy:// input. Returns ("", error) for non-copy or malformed inputs. The error wraps protocol.CopyTarget's error so callers can preserve the user-facing message.
func MixerInputSpec ¶ added in v0.0.22
func MixerInputSpec(in Input) (videoCode, audioCode StreamCode, audioFailureContinue bool, err error)
MixerInputSpec parses a mixer:// input. Returns ("", "", false, error) for non-mixer or malformed URLs. Wraps protocol.MixerTargets so callers can preserve the user-facing message.
type StreamCodeFilter ¶
type StreamCodeFilter struct {
// Only delivers events only for streams in this list.
Only []StreamCode `json:"only,omitempty" yaml:"only,omitempty"`
// Except delivers events for all streams except those in this list.
Except []StreamCode `json:"except,omitempty" yaml:"except,omitempty"`
}
StreamCodeFilter defines include/exclude rules for stream code matching. Only and Except are mutually exclusive; Only takes precedence when both are set.
func (*StreamCodeFilter) Matches ¶
func (f *StreamCodeFilter) Matches(code StreamCode) bool
Matches reports whether the given stream code passes the filter.
type StreamDVRConfig ¶
type StreamDVRConfig struct {
Enabled bool `json:"enabled" yaml:"enabled"`
// RetentionSec is the retention window in seconds.
// 0 = keep forever.
RetentionSec int `json:"retention_sec" yaml:"retention_sec"`
// SegmentDuration overrides the global segment length in seconds.
// 0 = use default (4s).
SegmentDuration int `json:"segment_duration" yaml:"segment_duration"`
// StoragePath overrides the default DVR root directory for this stream.
// "" = use "./dvr/{streamCode}".
StoragePath string `json:"storage_path" yaml:"storage_path"`
// MaxSizeGB caps total disk usage. Oldest segments pruned when exceeded.
// 0 = no limit.
MaxSizeGB float64 `json:"max_size_gb" yaml:"max_size_gb"`
}
StreamDVRConfig overrides the global DVR settings for a specific stream.
type StreamLookup ¶ added in v0.0.20
type StreamLookup func(StreamCode) (*Stream, bool)
StreamLookup returns the upstream stream by code. Used by ValidateCopyShape to inspect upstream transcoder shape without coupling domain to the repository layer. The bool reflects "found"; missing upstream is not an error here (handled at runtime by the coordinator).
type StreamStatus ¶
type StreamStatus string
StreamStatus represents the lifecycle state of a stream.
const ( StatusIdle StreamStatus = "idle" StatusActive StreamStatus = "active" StatusDegraded StreamStatus = "degraded" StatusStopped StreamStatus = "stopped" )
StreamStatus values are used by the stream manager and API.
type ThumbnailConfig ¶
type ThumbnailConfig struct {
Enabled bool `json:"enabled" yaml:"enabled"`
// IntervalSec generates one thumbnail every N seconds.
IntervalSec int `json:"interval_sec" yaml:"interval_sec"`
// Width and Height of the output thumbnail in pixels.
// 0 = match source resolution.
Width int `json:"width" yaml:"width"`
Height int `json:"height" yaml:"height"`
// Quality is the JPEG quality (1–31, lower = better). Default: 5.
Quality int `json:"quality" yaml:"quality"`
// OutputDir is relative to the publisher HLS directory.
// E.g. "thumbnails" → written to {hls_dir}/{stream_code}/thumbnails/thumb.jpg
OutputDir string `json:"output_dir" yaml:"output_dir"`
}
ThumbnailConfig controls periodic screenshot generation for stream preview. Thumbnails are written as JPEG files alongside HLS segments.
type TranscoderConfig ¶
type TranscoderConfig struct {
Video VideoTranscodeConfig `json:"video" yaml:"video"`
Audio AudioTranscodeConfig `json:"audio" yaml:"audio"`
Decoder DecoderConfig `json:"decoder" yaml:"decoder"`
Global TranscoderGlobalConfig `json:"global" yaml:"global"`
// ExtraArgs are raw FFmpeg arguments appended after the generated command.
// Use with caution — may conflict with generated arguments.
ExtraArgs []string `json:"extra_args,omitempty" yaml:"extra_args,omitempty"`
}
TranscoderConfig is the complete transcoding configuration for a stream.
type TranscoderGlobalConfig ¶
type TranscoderGlobalConfig struct {
// HW selects the acceleration backend.
HW HWAccel `json:"hw" yaml:"hw"`
// FPS sets output framerate. 0 = source/default.
FPS int `json:"fps" yaml:"fps"`
// GOP sets keyframe interval in frames. 0 = encoder default.
GOP int `json:"gop" yaml:"gop"`
// DeviceID selects hardware device index.
DeviceID int `json:"deviceid" yaml:"deviceid"`
}
TranscoderGlobalConfig holds global transcoder parameters.
type VODMount ¶
type VODMount struct {
Name VODName `json:"name" yaml:"name"`
Storage string `json:"storage" yaml:"storage"`
Comment string `json:"comment,omitempty" yaml:"comment,omitempty"`
}
VODMount registers a host filesystem directory as a named media library. The system does not maintain a file index; file lookups and listings are resolved live against Storage.
Ingest URLs take the form file://<Name>/<relative/path/inside/storage>. Any path that would escape Storage (via "..", absolute components, or symlink traversal) must be rejected by the resolver.
func (*VODMount) ValidateStorage ¶
ValidateStorage checks that Storage is a syntactically valid absolute path. The directory itself is not required to exist at validation time — operators may create it later — but the path must be absolute to avoid surprises from the server's working directory.
type VODName ¶
type VODName string
VODName identifies a VOD mount. It appears as the URL host in ingest sources (e.g. file://<name>/path/to/file.mp4), so it must be URL-host-safe.
type VideoCodec ¶
type VideoCodec string
VideoCodec identifies the video compression format.
const ( VideoCodecH264 VideoCodec = "h264" // AVC — widest device support VideoCodecH265 VideoCodec = "h265" // HEVC — ~50% smaller than H.264 VideoCodecAV1 VideoCodec = "av1" // royalty-free, best compression (high CPU) VideoCodecVP9 VideoCodec = "vp9" // Google codec, WebRTC-friendly VideoCodecCopy VideoCodec = "copy" // passthrough — no re-encode )
VideoCodec values name supported output video codecs.
type VideoProfile ¶
type VideoProfile struct {
// Width and Height define the output resolution.
// Set to 0 to keep the source dimensions (Width=0 & Height=0 = no scaling).
Width int `json:"width" yaml:"width"`
Height int `json:"height" yaml:"height"`
// Bitrate is the target video bitrate in kbps. 0 = encoder auto.
Bitrate int `json:"bitrate" yaml:"bitrate"`
// MaxBitrate caps the peak bitrate in kbps (CBR/VBR ceiling). 0 = no cap.
MaxBitrate int `json:"max_bitrate" yaml:"max_bitrate"`
// Framerate is the output frame rate (fps). 0 = match source.
Framerate float64 `json:"framerate" yaml:"framerate"`
// KeyframeInterval is the GOP size in seconds.
// Must match or be a multiple of the HLS/DASH segment duration.
KeyframeInterval int `json:"keyframe_interval" yaml:"keyframe_interval"`
Codec VideoCodec `json:"codec" yaml:"codec"`
// Preset controls the encoder speed/quality tradeoff.
// libx264: "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "medium" | "slow" | "veryslow"
// NVENC: "p1" (fastest) .. "p7" (highest quality)
Preset string `json:"preset" yaml:"preset"`
// Profile controls the H.264/H.265 encoding profile.
// "baseline" | "main" | "high" (H.264); "main" | "main10" (H.265)
Profile string `json:"profile" yaml:"profile"`
// Level controls the H.264/H.265 encoding level.
// Common: "3.1", "4.0", "4.1", "4.2", "5.0", "5.1"
Level string `json:"level" yaml:"level"`
// Bframes is the number of consecutive B-frames the encoder may emit.
// nil = encoder default; 0 = explicit none (low-latency live);
// 2-3 = typical VOD; NVENC HW B-ref pyramid is auto-enabled when >0.
Bframes *int `json:"bframes,omitempty" yaml:"bframes,omitempty"`
// Refs is the number of reference frames. nil = encoder default.
// Higher = better compression at cost of CPU/latency. NVENC has its own caps.
Refs *int `json:"refs,omitempty" yaml:"refs,omitempty"`
// SAR is the output Sample Aspect Ratio, "N:M". "" = inherit from source.
// Use "1:1" for square pixels (web); "16:11", "59:54" etc. for anamorphic.
SAR string `json:"sar,omitempty" yaml:"sar,omitempty"`
// ResizeMode chooses how the source is fitted to Width/Height.
// "" defaults to ResizeModePad.
ResizeMode ResizeMode `json:"resize_mode,omitempty" yaml:"resize_mode,omitempty"`
}
VideoProfile is a single rendition in the ABR (Adaptive Bitrate) ladder. The Transcoder produces one FFmpeg output per profile. Stable rendition ids are derived from slice order: track_1, track_2, track_3, … (1-based).
type VideoTranscodeConfig ¶
type VideoTranscodeConfig struct {
// Copy copies origin video without re-encoding.
Copy bool `json:"copy" yaml:"copy"`
// Interlace selects the deinterlace pre-filter applied before scaling.
// Applies once per FFmpeg subprocess (i.e. per profile in the ABR ladder).
// "" disables the filter; use ResizeModeProgressive to assert progressive source.
Interlace InterlaceMode `json:"interlace,omitempty" yaml:"interlace,omitempty"`
// Profiles defines ABR renditions when re-encoding.
Profiles []VideoProfile `json:"profiles,omitempty" yaml:"profiles,omitempty"`
}
VideoTranscodeConfig defines video transcoding behavior.
type WatermarkConfig ¶
type WatermarkConfig struct {
Enabled bool `json:"enabled" yaml:"enabled"`
Type WatermarkType `json:"type" yaml:"type"`
// Text is the string to render. Supports strftime directives for live timestamps.
// E.g. "LIVE %{localtime:%H:%M:%S}"
Text string `json:"text" yaml:"text"`
// FontFile is the path to a .ttf/.otf font file.
// "" = FFmpeg default font.
FontFile string `json:"font_file" yaml:"font_file"`
// FontSize in pixels. Default: 24.
FontSize int `json:"font_size" yaml:"font_size"`
// FontColor in FFmpeg color syntax. E.g. "white", "#FFFFFF", "white@0.8".
FontColor string `json:"font_color" yaml:"font_color"`
// ImagePath is the path to the watermark image (PNG with alpha recommended).
ImagePath string `json:"image_path" yaml:"image_path"`
// Opacity controls transparency: 0.0 = fully transparent, 1.0 = fully opaque.
Opacity float64 `json:"opacity" yaml:"opacity"`
// Position is the corner/center anchor for the watermark.
Position WatermarkPosition `json:"position" yaml:"position"`
// OffsetX and OffsetY are pixel offsets from the chosen position edge.
OffsetX int `json:"offset_x" yaml:"offset_x"`
OffsetY int `json:"offset_y" yaml:"offset_y"`
}
WatermarkConfig defines an overlay applied to the video before encoding. Applied via FFmpeg drawtext (text) or overlay (image) filter.
type WatermarkPosition ¶
type WatermarkPosition string
WatermarkPosition controls where the overlay is placed in the frame.
const ( WatermarkTopLeft WatermarkPosition = "top_left" WatermarkTopRight WatermarkPosition = "top_right" WatermarkBottomLeft WatermarkPosition = "bottom_left" WatermarkBottomRight WatermarkPosition = "bottom_right" WatermarkCenter WatermarkPosition = "center" )
WatermarkPosition values name corners and center for overlay placement.
type WatermarkType ¶
type WatermarkType string
WatermarkType determines whether the overlay is text or an image.
const ( WatermarkTypeText WatermarkType = "text" WatermarkTypeImage WatermarkType = "image" )
WatermarkType values select overlay content kind.