broadcast

package
v0.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 2, 2026 License: Apache-2.0 Imports: 19 Imported by: 0

Documentation

Overview

Package broadcast streams completed trunked-radio calls to external call aggregators — Broadcastify Calls, RdioScanner, OpenMHz — and to live Icecast/ShoutCast audio servers.

The Manager subscribes to events.KindCallComplete (published by the recorder once a call's WAV is flushed to disk), resolves which backends want the call, encodes the audio to MP3 once, and dispatches it to each backend with bounded exponential-backoff retry. A call is skipped entirely when its talkgroup is flagged Stream=false or when it is shorter than the configured minimum duration.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Backend

type Backend interface {
	// Name is a short stable identifier used in logs and stats.
	Name() string
	// Accepts reports whether this backend wants calls from the named
	// trunking system. An unfiltered backend accepts every system.
	Accepts(systemName string) bool
	// Send delivers the call. A non-nil error triggers a retry.
	Send(ctx context.Context, c *Call) error
}

Backend is one outbound streaming destination. Implementations must be safe for concurrent Send calls — the Manager runs several upload workers. Send should treat a retry as a fresh attempt; the Manager handles backoff between attempts.

func NewBroadcastify

func NewBroadcastify(cfg BroadcastifyConfig, hc *http.Client) (Backend, error)

NewBroadcastify builds a Broadcastify Calls backend.

func NewIcecast

func NewIcecast(cfg IcecastConfig, log *slog.Logger) (Backend, error)

NewIcecast builds a live Icecast/ShoutCast streaming backend and starts its background source connection.

func NewOpenMHz

func NewOpenMHz(cfg OpenMHzConfig, hc *http.Client) (Backend, error)

NewOpenMHz builds an OpenMHz upload backend.

func NewRdioScanner

func NewRdioScanner(cfg RdioScannerConfig, hc *http.Client) (Backend, error)

NewRdioScanner builds an RdioScanner call-upload backend.

type BroadcastifyConfig

type BroadcastifyConfig struct {
	// Name is an optional label used in logs; defaults to
	// "broadcastify".
	Name string
	// APIKey is the Broadcastify Calls API key for the system.
	APIKey string
	// SystemID is the numeric Broadcastify Calls system ID.
	SystemID int
	// Systems restricts the feed to these trunking-system names.
	// Empty streams every system.
	Systems []string
	// Endpoint overrides the upload API URL (tests). Empty uses the
	// production endpoint.
	Endpoint string
}

BroadcastifyConfig configures one Broadcastify Calls feed.

type Call

type Call struct {
	System         string
	Protocol       string
	Talkgroup      uint32
	TalkgroupLabel string
	Source         uint32
	FrequencyHz    uint32
	Encrypted      bool
	// AlgorithmID / KeyID surface the P25 encryption parameters when
	// the in-call signalling has revealed them. Zero on clear calls
	// and on encrypted calls whose Encryption Sync never arrived
	// before the call ended. Aggregators that accept the fields can
	// thread them into their API payload; aggregators that don't will
	// just ignore them.
	AlgorithmID   uint8
	KeyID         uint16
	Emergency     bool
	PatchedGroups []uint32
	StartedAt     time.Time
	EndedAt       time.Time
	AudioPath     string // .wav on disk written by the recorder
	SampleRate    int
	// contains filtered or unexported fields
}

Call is a completed call queued for outbound streaming. It carries the call metadata plus a lazy MP3 accessor — the WAV on AudioPath is encoded to MP3 at most once regardless of how many backends consume it.

func (*Call) Duration

func (c *Call) Duration() time.Duration

Duration reports how long the call ran.

func (*Call) MP3

func (c *Call) MP3() ([]byte, error)

MP3 returns the call audio encoded as an MP3 byte stream. The encode runs once on first use; later calls return the cached result (or the cached error). Safe for concurrent use across backend workers.

type IcecastConfig

type IcecastConfig struct {
	// Name is an optional log label; defaults to "icecast".
	Name string
	// Host and Port address the Icecast server.
	Host string
	Port int
	// Mount is the mountpoint path (e.g. "/gophertrunk"). A leading
	// slash is added when missing.
	Mount string
	// Username is the source username; defaults to "source".
	Username string
	// Password is the source password.
	Password string
	// StreamName is advertised to listeners via the Ice-Name header.
	StreamName string
	// SampleRate is the PCM rate used to synthesise inter-call
	// silence; defaults to 8000.
	SampleRate int
	// Systems restricts the feed to these trunking-system names.
	// Empty streams every system.
	Systems []string
}

IcecastConfig configures one live Icecast/ShoutCast feed.

type Manager

type Manager struct {
	// contains filtered or unexported fields
}

Manager fans completed calls out to the configured backends.

func NewManager

func NewManager(opts Options) (*Manager, error)

NewManager validates opts and returns a Manager that has already subscribed to the bus (so calls completed before Run starts are not lost). The caller must invoke Run and, on shutdown, Close.

func (*Manager) Backends

func (m *Manager) Backends() int

Backends reports how many outbound destinations are configured.

func (*Manager) Close

func (m *Manager) Close() error

Close releases the bus subscription, waits for Run to drain, then stops the upload workers. Safe to call multiple times.

func (*Manager) Run

func (m *Manager) Run(ctx context.Context) error

Run drains KindCallComplete events until ctx is cancelled or the bus subscription closes.

func (*Manager) Stats

func (m *Manager) Stats() Stats

Stats returns a snapshot of the Manager's counters.

func (*Manager) String

func (m *Manager) String() string

String renders a one-line Manager summary for log output.

type OpenMHzConfig

type OpenMHzConfig struct {
	// Name is an optional log label; defaults to "openmhz".
	Name string
	// APIKey is the OpenMHz system API key.
	APIKey string
	// ShortName is the OpenMHz system short name (the path segment in
	// the upload URL).
	ShortName string
	// Systems restricts the feed to these trunking-system names.
	// Empty streams every system.
	Systems []string
	// Endpoint overrides the API base URL (tests). Empty uses the
	// production endpoint.
	Endpoint string
}

OpenMHzConfig configures one OpenMHz upload feed.

type Options

type Options struct {
	Bus *events.Bus
	Log *slog.Logger
	// Backends is the set of outbound destinations. A Manager with no
	// backends is valid but inert.
	Backends []Backend
	// MinDuration drops calls shorter than this from every backend.
	// Zero streams calls of any length.
	MinDuration time.Duration
	// Workers is the number of concurrent upload goroutines. Default 2.
	Workers int
	// MaxRetries is the per-backend retry budget on a failed Send.
	// Default 3.
	MaxRetries int
	// RetryBase is the first backoff delay; it doubles per attempt.
	// Default 2s.
	RetryBase time.Duration
}

Options configure a Manager.

type RdioScannerConfig

type RdioScannerConfig struct {
	// Name is an optional log label; defaults to "rdioscanner".
	Name string
	// URL is the RdioScanner base URL (e.g. "https://scanner.example").
	// The "/api/call-upload" path is appended automatically.
	URL string
	// APIKey is the RdioScanner system API key.
	APIKey string
	// SystemID is the numeric RdioScanner system ID.
	SystemID int
	// Systems restricts the feed to these trunking-system names.
	// Empty streams every system.
	Systems []string
}

RdioScannerConfig configures one RdioScanner call-upload feed.

type Stats

type Stats struct {
	Queued   int            `json:"queued"`
	Dropped  int            `json:"dropped"`
	Sent     map[string]int `json:"sent"`
	Failed   map[string]int `json:"failed"`
	Backends []string       `json:"backends"`
}

Stats is a point-in-time snapshot of a Manager's counters.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL