Bindings are captured system-wide rather than only while the window has
focus: X11's RECORD extension where the X server sees every key, and a
/dev/input reader as the Wayland fallback. Any key can act as a modifier,
mouse buttons included, as TS3 allows.
The action catalogue, its three categories and the "advanced actions"
split are reverse-engineered from the original client; actions this
client cannot perform are listed but greyed out. Push-to-talk becomes one
of these hotkeys, so the old focus-bound pushToTalkKey setting is gone and
the Voice Activation button edits that binding instead.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The mixer wrote silence between sounds to keep the line running, which left
the playback buffer (400 ms on the PipeWire ring) full of it, so a sound the
user had just triggered only started once all of that had drained. Wait for
the next sound instead, leaving the buffer empty between them.
Opening the line costs a device round-trip of its own, so hold it for 30 s of
quiet rather than dropping it after 3 s and paying that on the next action.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Adds TeamSpeak-format sound packs: a folder of waves plus a settings.ini
mapping actions to play()/say() entries, with ${clientType} and friends
resolved per event. Packs are found in the client's own sound folder, an
installed TS3 client and a folder of the user's choosing, so the official
packs work unchanged.
Each action can be switched off or marked important; important actions are
the only ones still played while the speakers are muted, as in TS3. The new
Notifications options page lists them by category, greys out what the active
pack has no sound for, and previews on double-click.
Sounds are decoded, resampled and mixed onto a single playback line that is
only open while something plays, so overlapping events never fight over the
device.
Fires the events from the protocol layer, following TeamSpeak's own
distinctions: reason ids separate switched/moved/kicked/banned/timed out,
and visibility decides appears/disappears/stays.
Also fixes a ts3j trap in the process: a field an event never carried reads
back as an empty string, so the existing "e.get(x) != null" checks were
always true. That made a partial clientupdate (someone muting) announce a
stopped recording, and it let a nickname-only update reset another client's
mute/away flags and talk power, or a channel edit blank the channel name.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Capture and playback now go through AudioCapture/AudioPlayback interfaces
with two implementations: PipeWire, used for the system default and for
every pw: device when a session is reachable, and Java Sound for the raw
ALSA devices and other platforms. The PipeWire binding is FFM-based
(PipeWireLibrary, PipeWireSession, PipeWireStream, SpaPod) and enumerates
the graph's real devices, so each stream shows up separately in volume
mixers.
Lines are opened with a negotiated channel count instead of a fixed mono
format: OPUS_MUSIC transmits the stereo capture as-is, OPUS_VOICE keeps
transmitting the mono downmix so the pre-processing chain and VAD still
see a single channel. Java Sound enumeration asks only for "a mixer that
can capture/play" so the PipeWire and PulseAudio ALSA plugins are no
longer hidden by their narrow format lists.
The Java Sound classes are renamed to Desktop* to match what they now
are, and JUnit plus a SpaPod round-trip test are wired into the build.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Bind libopus through java.lang.foreign downcall handles instead of JNA:
the ctl functions are linked with firstVariadicArg(2), and the encoder and
decoder each own a shared Arena holding the handle plus reusable native
PCM/packet buffers, so the hot path only allocates the returned packet.
The library is resolved by system SONAME first, falling back to a bundled
copy extracted from the JAR. Only the Windows x86-64 build is packaged by
default now (-Dnatives.all restores all platforms), since every other
platform ships libopus through its package manager.
Requires Java 26.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Vendor libopus binaries under the desktop module's resources at JNA's
platform resource paths (linux-x86-64/libopus.so, win32-x86-64/opus.dll,
etc.), sourced from the checksum-verified club.minnced:opus-java-natives
1.1.1 artifact with the Windows lib renamed to JNA's mapped name.
Native.load("opus") still prefers a system libopus but now falls back to
the bundled copy, so the shaded uber-JAR runs with no external Opus
install on Linux (x86-64/x86/aarch64/arm), Windows (x86-64/x86) and
Intel macOS.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Swing desktop client (core/desktop/swing Maven modules) built on the
ts3j protocol library, included as a submodule. Native Opus voice with
voice-activation detection, push-to-talk, and audio pre-processing.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>