Skip to main content

Class: VisualizerController

Defined in: packages/player/src/visualizer-controller.ts:72

The lazy, reference-counted owner of one player's audio visualizer.

Laziness is the whole contract

Nothing exists until the first VisualizerController.subscribe: mpv's tap is disarmed, its ring is unallocated, and there is no sampler thread, no FFT table and no window. The last unsubscribe releases all of it and disarms mpv again, after which the audio thread's tap path is a single atomic load per device chunk. This is why subscribe — not a manual start/stop pair — is the primitive: a lifetime that is derived from the listener set cannot be leaked by forgetting to call stop(). There is deliberately no free-standing start(): it could only ever mean "hold the tap open with nobody looking", which is the one state this design exists to make unrepresentable.

Native parameters are the union, decode parameters are per subscriber

fftSize, fps and waveform configure the one shared native sampler, so they are resolved as the union across live subscribers (largest transform, fastest rate, waveform if anyone wants it). Everything else — band count, dB window, tilt, auto-gain, smoothing — is pure maths applied per subscriber, so two components can paint the same audio with different ballistics without fighting over the engine.

Constructors

Constructor

new VisualizerController(client: MpvClient | undefined): VisualizerController;

Defined in: packages/player/src/visualizer-controller.ts:86

Parameters

ParameterTypeDescription
clientMpvClient | undefinedThe player's mpv binding, or undefined when the player was built without one (never in production; the tests do it).

Returns

VisualizerController

Accessors

active

Get Signature

get active(): boolean;

Defined in: packages/player/src/visualizer-controller.ts:116

Whether a native capture is running right now.

Returns

boolean


capabilities

Get Signature

get capabilities(): VisualizerCapabilities;

Defined in: packages/player/src/visualizer-controller.ts:99

What this build can actually do. Probed once, then cached.

The probe is a plain property read through the generic binding — if pcm-tap exists, this libmpv carries the rn-media source patch and the visualizer works; if it does not, mpv answers "no such property" and the feature reports itself unavailable. One code path, both platforms, no Platform.OS. Reading this allocates nothing.

Returns

VisualizerCapabilities

Methods

destroy()

destroy(): void;

Defined in: packages/player/src/visualizer-controller.ts:211

Release everything. Called by Player.destroy(); idempotent.

Drops every subscription first so the native teardown happens exactly once, then stops the sampler.

Returns

void


handleCapture()

handleCapture(capture: VisualizerCapture): void;

Defined in: packages/player/src/visualizer-controller.ts:192

Deliver a native capture to every subscriber.

Wired to the native listener by Player; not part of the public API surface, but harmless to call with a synthetic capture in tests.

Parameters

ParameterTypeDescription
captureVisualizerCaptureThe raw capture as the native binding delivered it.

Returns

void


subscribe()

subscribe(listener: VisualizerListener, options?: VisualizerOptions): VisualizerUnsubscribe;

Defined in: packages/player/src/visualizer-controller.ts:132

Start delivering frames to listener.

Parameters

ParameterTypeDescription
listenerVisualizerListenerCalled with one decoded VisualizerFrame per capture, at up to options.fps.
options?VisualizerOptionsPer-subscriber tuning; see VisualizerOptions.

Returns

VisualizerUnsubscribe

A function that removes this subscription — and, when it was the last one, disarms the native tap completely.

Throws

PlayerErrorException with code unsupported when the linked libmpv has no PCM tap, or disposed after the owning player was destroyed. It never fails silently.