Skip to content

v0.2.0

Choose a tag to compare

@github-actions github-actions released this 10 Sep 16:08
· 76 commits to main since this release

TobiiLinux v0.2.0 — head tracking into games

Games. v0.1.0 could send head pose to opentrack, and only to opentrack. This
release adds two routes that need nothing else installed, and fixes a bug that
made one axis useless in every output the program has.

This is a testing release. The tracking paths below are verified end to
end on hardware — through SDL, through joydev, through DirectInput under a
real Proton prefix — but no game has consumed any of it yet, and no real
head has driven the axes. If something feels wrong, it probably is; see
Reporting a problem.

Unofficial. Not affiliated with, endorsed by, or supported by Tobii.
Use at your own risk.

New: a virtual joystick, needing nothing else

Most games have never heard of head tracking, but nearly all of them can bind a
joystick axis. So game output now presents one, on /dev/uinput:

Axis Carries Full scale
X, Y, Z head displacement from where you sit ±500 mm
RX, RY, RZ yaw, pitch, roll ±180°, ±90°, ±180°
Throttle, Rudder gaze on screen, left→right and top→bottom the whole screen

No opentrack, no Wine. Because it is an ordinary evdev joystick it is read by
SDL, by the legacy /dev/input/js* interface, and by Wine's winebus — so
Proton games see it as a DirectInput joystick too. The last two axes are
gaze, which no other head tracker offers.

Turn it on with the hub's Head tracking for games switch, or:

tobii games set enabled true
tobii game -- %command%        # Steam: paste into Launch Options

If the axes feel weak, this is the knob. The number is the head angle that
reaches full deflection:

tobii games set joystick_yaw_full_deg 45     # default 70

New: the Wine/Proton bridge needs nothing running

tobii bridge games                     # what is installed, and what has a prefix
tobii bridge install --steam elite     # by name, or by app id

The client DLL the game loads receives the tracking itself, in a background
thread inside the game's own process. There is no second program to leave
running. That is not a convenience: a Proton game runs under its own wineserver,
so an external tobii bridge run created its shared memory in a different
session and the game never saw it — for a Steam title the old design could not
have worked at all.

install --steam finds the prefix from Steam's own library files and writes the
registry with the Proton build that prefix records, not whatever wine is
on your $PATH — a foreign wine would run wineboot -u and upgrade the prefix
out from under the game.

Fixed: one translation axis was dead in every output

Z carried the head's distance from the sensor — 650–700 mm for anyone
sitting normally — against a ±500 mm scale. It was pinned hard at maximum, for
every user, in both the joystick and the TrackIR/FreeTrack output that
shipped in v0.1.0. In a game that reads as a camera permanently leaned all the
way in. Translation is displacement from where you sit now, taken when the
tracker picks you up.

Also in this release

  • X-Plane 11/12 works with no extra sink. The plugin Linux users actually
    run (amyinorbit/headtrack) reads exactly what our opentrack output already
    emits, on the port it already uses. Just turn game output on.
  • tobii game -- <command> holds the tracker for a game's lifetime, and says so
    when game output is switched off rather than lighting the tracker silently.
  • Closing the hub window minimises it instead of quitting, so the tracker
    stays available to a running game.
  • Another program can take the device from the hub and hand it back.
  • tobii games [set KEY VALUE] for every game-output setting.
  • tobii debug reports /dev/uinput, separating the three ways it fails —
    they are indistinguishable from inside a game.
  • The packaged udev rule now also grants /dev/uinput, as one clearly-marked
    line the file explains how to remove.

Upgrading — read this one

tobii update replaces binaries and nothing else, so it will not deliver
the new udev rule. If the virtual joystick reports a permission error, install
the rule by hand:

sudo cp assets/60-tobii.rules /etc/udev/rules.d/
sudo udevadm control --reload
sudo udevadm trigger --subsystem-match=usb --subsystem-match=misc

then log out and back in — the grant is a logind ACL applied at session start.
tobii debug says installed without a warning once it has taken. Distribution
packages (deb, rpm, PKGBUILD) do this for you.

If you set bridge_port to something other than the default, launch through
tobii game: it passes the port to the Wine side, and nothing else can.

Known limitations

  • Some games' "look" axis is a rate control, not a position: the camera
    keeps turning while the axis is deflected. The bind takes, the axis moves in
    the test display, and the view still spins away from you. Elite Dangerous has
    an explicit Headlook Axis Mode: Direct precisely because its default is
    incremental. Where only a rate axis is offered, the joystick cannot drive the
    view however it is tuned.
  • Steam Input can take the device away, silently, from a Steam-launched
    game. Fix per game: Properties → Controller → Disable Steam Input.
  • The bridge is 64-bit only. A 32-bit game asks for freetrackclient.dll
    without the 64 and finds nothing while install reports success. Falcon
    BMS, IL-2 1946 and the FSX generation are 32-bit.
  • TrackIR still needs a signed client DLL. NP_GetSignature is answered
    from NaturalPoint's own signature data, which we do not ship, so
    tobii bridge install points TrackIR at an installed opentrack client — and
    that one does need tobii bridge run. FreeTrack has no signature check and
    works with our own DLL.
  • XInput does not see the virtual joystick — measured under Wine 11.17.
    Its two-stick layout has nowhere to put eight axes.
  • Flatpak Steam is half-supported. The install finds its prefix, but the
    launch option runs inside the sandbox where our binary is not on PATH.
    flatpak-spawn --host tobii game -- %command% is the shape to try.
  • [UNKNOWN] the per-axis signs of the TrackIR encoding, and whether a game
    ignores a frame whose wPFrameSignature did not change.
  • The gaze axes sit on Throttle and Rudder. A flight sim that auto-binds a
    throttle could pick one up; no sim has been observed doing so.

How this was tested

Everything below was measured on hardware, not inferred:

  • SDL2 2.32 enumerates the device with 8 axes and 2 buttons. A known pose
    survives the whole chain exactly: composed yaw +35° of the 70° default arrives
    as 16384 — half deflection — pitch −17.5° as −16385, gaze at the
    right-hand screen edge as 32767.
  • joydev (/dev/input/js*) reports every axis at exactly 0 at rest.
  • Wine 11.17 DirectInput8 enumerates it as DI8DEVTYPE_JOYSTICK; XInput
    reports zero controllers in all four slots, with and without it present.
  • udev classification was established by building the device four ways and
    reading /run/udev/data/. Without an EV_KEY capability the kernel calls it
    an accelerometer and hands it to iio-sensor-proxy — the service that rotates
    laptop screens.
  • The bridge, on a real Elite Dangerous Proton prefix, with nothing else
    running.
    The game's own load path (LoadLibrary on the registry directory,
    then GetProcAddress) resolves all five FreeTrack exports, and a pose sent
    from Linux as yaw 7.5°, pitch −3.25°, roll 1.5°, (11, 22, 33) mm reads back
    through FTGetData as yaw=0.1309, pitch=-0.0567, roll=0.0262 radians and
    pos=(11.0, 22.0, 33.0), with DataID advancing. With nothing sending it
    reports no data rather than a tracker frozen at centre.

793 tests, zero clippy warnings, both workspaces building.

Two full adversarial review rounds were run over this change and every finding
from both was adjudicated
— 55 findings, 22 confirmed and fixed. Several were
defects in behaviour that shipped in v0.1.0.

The full list, including what is untested and what is merely believed to work,
is in Quality-and-Risks — see 11.3a Game
output
. That page is written to be uncomfortable to read.

Reporting a problem

tobii debug prints the report an issue asks for, and the hub's cogwheel can
copy or save it. It names the state of the udev rule, /dev/uinput, the display
area and the calibration. If a game sees nothing, say which game, which route
(joystick, opentrack, or the bridge), and paste that report.

Credits

The FreeTrack and TrackIR interfaces are public ABIs; opentrack was read for
interface facts — which axes, which classification bits, which packet shapes —
and the files that use them say so and say which fact. No opentrack code was
copied. The clean-room claim covers the ET5's USB protocol, which was
derived from captured traffic and nothing else.