Skip to main content

Crate tcnet

Crate tcnet 

Source
Expand description

§tcnet

A Rust implementation of the TCNet UDP protocol — a network protocol used by professional DJ / VJ gear (Pioneer / ProDJ Link adjacent) for synchronising playback state, mixer state, beat-grid information and waveform previews between networked nodes.

This crate covers protocol version 3.6 (the value emitted in every outgoing ManagementHeader) and supports both roles:

  • Passive observer — discover foreign DJ controller nodes broadcasting on the network and read their state through DjControllerView. Useful for VJ tools, visualisers, lighting controllers, analytics, etc.
  • Active broadcaster — present this process as a virtual DJ node via ActiveDJNode: announce up to eight layers of playback, push Time / Status / Metrics / Meta / Mixer packets, and serve pre-built waveform / beat-grid / cue / artwork responses on request.

§Specification

The packet layouts, message-type IDs and field meanings all follow the official spec, available here:

https://www.tc-supply.com/_files/ugd/b1c714_0b351a4099c14e738f0cd7fcea623265.pdf

Citations elsewhere in these docs link back to that PDF.

§Quick start

use std::thread::sleep;
use std::time::Duration;
use tcnet::{ApplicationConfig, TCNetClient};

let config = ApplicationConfig::default();
let mut client = TCNetClient::new(config);

// Wait for a foreign DJ controller to be discovered, then read its state.
loop {
    for node in client.active_nodes() {
        if node.has_dj_controller {
            if let Some(mut view) = client.get_controller_view(node.address) {
                for (i, layer) in view.get_layers().iter().enumerate() {
                    println!("L{}: {:?} @ {:.1} BPM", i + 1, layer.state, layer.bpm.as_f32());
                }
            }
        }
    }
    sleep(Duration::from_secs(1));
}

§Architecture

                               ┌──────────────────────────────┐
                               │ TCNetClient                  │
                               │   • spawns tokio runtime     │
                               │   • binds UDP sockets        │
                               │   • runs OptIn discovery     │
 network                       │   • dispatches packets       │
──────────                     │                              │
 60000 ── broadcast ◀──────────┤                              │
 60001 ── time     ◀──────────►│        Dispatcher            │◀── ActiveDJNode (broadcast role)
 60002 ── broadcast ◀──────────┤                              │
 port  ── unicast   ◀──────────┤                              │
                               │                              │
                               │   per-foreign-node triple    │
                               │   buffer ──────────────────► │── DjControllerView (read role)
                               └──────────────────────────────┘

§Module layout

Most users only need the types re-exported at the crate root.

§Implementation status

This crate covers the parts of TCNet v3.6 needed to observe and impersonate a Pioneer-style DJ controller on the network. It is not a full reference implementation of every message type defined in the spec.

Implemented:

  • Discovery — OptIn broadcasts every second on UDP 60000, listening for peer OptIn / OptOut, 10-second timeout for stale nodes.
  • Foreign-node observation — Status, Metrics, Meta, Mixer and Time packets are decoded and merged into LayerSnapshot / MixerSnapshot, published through a triple buffer to DjControllerView.
  • On-demand requests from a DjControllerViewSmallWaveform, BigWaveform, BeatGrid (with multi-packet reassembly) and LowResArtworkFile, each with a 5-second timeout.
  • Active broadcasting via ActiveDJNode — periodic Time (20 ms), Status (1 s) and per-layer Metrics (50 ms while playing) emission, plus on-demand replies to peer RequestData packets from a pre-built response cache (SmallWaveform, BigWaveform, BeatGrid, Cue, Artwork, Mixer, Metrics, Meta).

Partial / not implemented:

  • No OptOut is emitted when an ActiveDJNode is dropped — peers currently rely on the 10-second silence timeout to drop us. Incoming OptOut from peers is handled.
  • TimeSync (message type 10) — struct defined for parsing, but the handshake is not performed; this crate relies on local system time and the per-packet microsecond timestamp.
  • ErrorNotification (message type 13) — struct defined, never sent or surfaced to the user when received.
  • Control / Text / Keyboard / AppSpecific (message types 101 / 128 / 132 / 30 / 213) — structs defined but neither emitted nor surfaced; incoming packets are deserialised and dropped.
  • Authentication (NodeOptions::NEED_AUTHENTICATION) — no handshake implemented; this crate always operates as an unauthenticated peer.
  • LayerStatus and AutoMasterMode are placeholder enums with a single variant — the spec leaves these mostly unspecified at v3.6.
  • Master-election arbitrationNodeType is reported faithfully but the Auto/Master/Slave election logic is not driven by this crate.
  • MixerData round-trip — most fields are surfaced through MixerSnapshot, but a handful of less-common send-FX / send-return bytes are read from the wire without a dedicated snapshot field.

PRs welcome.

Re-exports§

pub use active_node::ActiveDJNode;
pub use active_node::TrackMeta;
pub use protocol::AsciiString;
pub use protocol::BeatGridEntry;
pub use protocol::BeatGridHeader;
pub use protocol::BigWaveformData;
pub use protocol::Bpm;
pub use protocol::LayerId;
pub use protocol::LayerState;
pub use protocol::NodeOptions;
pub use protocol::NodeType;
pub use protocol::RequestDataType;
pub use protocol::SmallWaveformData;
pub use protocol::SmpteMode;
pub use protocol::Speed;
pub use view::DjControllerView;
pub use view::WaveformRequester;

Modules§

active_node
Active broadcaster role: present this process as a TCNet DJ controller node.
protocol
Wire-format types for the TCNet UDP protocol.
view
Read-only consumer view of a foreign TCNet DJ controller node.

Macros§

into_ascii
Build an AsciiString<N> from a string literal at compile time.

Structs§

ApplicationConfig
Identity and bind configuration used by a TCNetClient when it announces itself to peers.
ChannelSnapshot
Decoded snapshot of one mixer channel — a fader strip on the physical mixer.
DjControllerState
Combined snapshot of one foreign DJ controller: all eight LayerSnapshots plus one MixerSnapshot.
ForeignNodeInfo
Snapshot of a foreign node discovered on the network through TCNet OptIn broadcasts. Returned by TCNetClient::active_nodes.
LayerSnapshot
Decoded snapshot of one layer’s state.
MixerSnapshot
Decoded snapshot of a foreign mixer’s state.
TCNetClient
Entry point to the TCNet network.
TimeoutError
Returned when a DjControllerView request for waveform / beat-grid / artwork data does not receive a response within 5 s (or the underlying request channel has been closed).