FiiO ships the KA13 with an Android app and nothing else. This is the Windows side.
FIIO's KA13 USB DAC/amp can switch filters, set volume, flip SPDIF output and kill
its RGB light — but only from FiiO Control on an Android phone. There is no desktop
client, no CLI, no documented protocol. This repo is a native Windows console for it:
the control channel was reverse-engineered out of the APK, then reimplemented with
hidapi and a Tkinter UI.
Download KA13.exe → plug in the KA13 → double-click
Twelve device controls, five of them writable and stored inside the DAC itself. Everything the phone app does, plus what it doesn't: live sample-rate readout, burn-in timer, channel/polarity test tones, update checks.
Three gaps between the hardware and the software you can actually run:
- #1: Mobile-only control. The KA13 has no screen and no buttons beyond volume — its settings live in an Android app. On a PC you get nothing. Fix: a Windows GUI speaking the same HID protocol.
- #2: Nothing documented. No vendor SDK, no protocol notes; the device only answers
HID SET_REPORTwith an undocumented 16-byte frame. Fix: decompile the APK, liftKa13CommandFactory, verify every opcode against real hardware, publish the tables indocs/registers.md. - #3: No way to confirm anything. Did the filter change? Did the unit keep it after unplugging? Fix: every write is read back and logged; the app reports what it wrote, what it read, and refuses to guess.
| Group | Feature | Written to device? |
|---|---|---|
| Device | 5 digital filters (with the official impulse-response curves) | yes, survives unplug |
| Device | Output volume, 0–50 scale — the same number the phone shows | yes |
| Device | SPDIF output (3.5 mm → coaxial), RGB light (on / off once / off always), UAC 1.0/2.0 | yes |
| Diagnostics | Live sample rate & format (32k–384k, DSD64–512, DoP) | read-only |
| Diagnostics | 8 registers, raw frame console, command scanner | read-only by default |
| Tools | Headphone profiles, burn-in timer, channel / polarity / sweep tones | local only |
| Tools | Firmware update check, app self-update, tray, hotkeys, autostart, zh/en UI | local only |
The UI is grouped and colour-banded by exactly this split — green for "goes into the DAC", grey for "read-only", blue for "this PC only". Connecting never writes: every write needs a click.
FiiO Control v3.45 (Aptoide mirror) → jadx → 5,941 classes. The control channel
lives in l8/a.java (Ka13CommandFactory) plus androidx/appcompat/widget/j.java, a
class that exists only to hold byte-array constants. It is not a report-ID device in
the usual sense:
write HID SET_REPORT bmRequestType=0x21 bRequest=0x09
wValue=0x0200 (output report, report ID 0) 16 bytes
read input report, 32 bytes:
[.., u@6, len@7, payload@8..]
u is the per-command channel and len the payload length; the device echoes both
back, so every reply validates itself. On Windows the write needs a leading report-ID
byte — 16 bytes returns ERROR_INVALID_PARAMETER (87), 17 bytes works. That one byte
cost an afternoon.
| Register | Command | Meaning | Verified value |
|---|---|---|---|
| L | 02 02 |
Filter ((idx<<6)|2, idx 4 → 0x22) |
0x82 |
| M / N | 00 10 / 00 11 |
Volume, raw 0–100 (display = 50 − raw/2) | 0x36 = 23 |
| I | 00 46 |
SPDIF state | 0x00 |
| K | 02 00 |
RGB light mode (FF00 / FE01 / FD02) |
FF00 |
| H / J / G | 00 45 / 00 47 / 00 20 |
Firmware constants — unchanged by every operation we tried | 00 / 74 / 80 BB 00 00 |
Round-trip evidence, straight from the packet log:
filter write 0x40 → read 0x40 → write 0x82 → read 0x82
SPDIF 00 → 01 → 00
LED FF00 → FD02 → FF00
volume display 34 ↔ raw 0x20 (32); set 30 → read 0x28 (40) → display 30
replug unplug 3.2 s → all five settings unchanged
Full frame layouts, the SPDIF/LED raw frames, the stream-status query and the filter
naming come from the APK resources, not from guesswork — see
docs/registers.md.
Ready to run — no Python needed:
| File | What |
|---|---|
KA13.exe |
single-file build (33 MB: Python + Tcl/Tk + OpenSSL inside) |
KA13Setup-1.0.0.exe |
NSIS installer, no admin, installs to %LOCALAPPDATA%\KA13Console |
From source
pip install -r requirements-dev.txt
python ka13_control.pywWindows 10/11, Python 3.10+. hidapi, pycaw, pystray, Pillow are the only
runtime deps; the tone generators use the standard library alone.
| Area | What's pinned down |
|---|---|
| Writes | Every write is read back and logged; the UI shows the register value, not a claim |
| Read-only by default | Connecting and refreshing issue reads only — no silent config, ever |
| Persistence | Settings live in the DAC's own storage, verified across unplug/replug |
| Filters | Names, order and impulse-response curves taken from the official APK resources |
| Volume | Same 0–50 scale as the phone app, so numbers match across devices |
| Updates | Firmware check probes FiiO's CDN with HEAD; self-update is opt-in, sha256-checked |
| Tests | 114 unit tests on Windows × Python 3.12/3.13 in CI, no hardware required |
Repo layout
ka13_control.pyw # the app — 10 tabs, ~100 KB
ka13_proto.py # HID transport, frame builders, register tables
ka13_i18n.py # zh/en string tables (196 keys each)
ka13_extras.py # global hotkeys (ctypes), tray (pystray), autostart (winreg)
ka13_updater.py # download → sha256 → swap-and-restart
ka13_audio.py # tone / noise / sweep generators + burn-in timer
curves/ # 5 official impulse-response images, lifted from the APK
tests/ # 114 pytest cases
docs/ # registers / extras / updater / testing / titans2
installer/ # NSIS script + build.ps1
dev/ # probe scripts used during the reverse engineering
.github/workflows/ # CI: windows-latest × 3.12 / 3.13
Docs
| File | Content |
|---|---|
docs/registers.md |
Every register: what's solved, what's constant, and the experiments that proved it |
docs/titans2.md |
DUNU Titan S2 notes (16 Ω / 107 dB/mW — why 3.5 mm, not balanced) |
docs/extras.md |
Hotkey / tray / autostart APIs and the cross-thread Tkinter trap |
docs/updater.md |
Self-update flow, and why DETACHED_PROCESS silently breaks the swap script |
docs/testing.md |
What the tests cover, the mutation check, CI setup |
Probe results, new firmware URLs and other FiiO models are welcome — with a device in
hand, docs/registers.md is the place to extend. Run python -m pytest -q tests
before sending a patch.
Unofficial tool. Not affiliated with or endorsed by FiiO.






