Tobii Client Library

Disclaimer

(Due to a grievance filed by a student in one of my classes, the following disclaimer has been patterned from a Microsoft web page and is applied to code/information found herein on Dr. Duchowski's web pages.)

WARNING: ANY USE BY YOU OF THE CODE/INFORMATION PROVIDED IN THESE WEB PAGES IS AT YOUR OWN RISK. Dr. Duchowski provides this code/information "as is" without warranty of any kind, either express or implied, including but not limited to the implied warranties of merchantability and/or fitness for a particular purpose.

Dr. Duchowski will not be held responsible for any inaccuracies, bugs, documented or undocumented, in the sample code/information below. This web page merely contains suggestions. SHOULD YOU WISH TO USE THESE EXAMPLES FOR COURSEWORK, YOU ARE DOING SO AT YOUR OWN RISK. Dr. Duchowski will not grant extra credit, time, debugging time, or anything else should you find a bug in the code/information (except maybe a "Thanks for pointing that out!").

Download

NOTE: It is recommended that you just download the tobii.tar.gz package. This contains everything in the table below and should compile in one step (on either Linux or Mac OS X - consult the OS and Compiler versions below to see what it was tested on). Don't forget to inspect the Makefile in the example code to see how platform-dependent linking is done in these examples.

Install

gunzip tobii.tar.gz
tar xvf tobii.tar
rm tobii.tar
cd tobii
cd examples
make clean
make

Last Update Date Notes
Wed Nov 20 10:59:54 EST 2013 I finally managed to track down a long-standing bug I had trouble with on x86_64 architectures. Turns out that under 64-bit architectures (at least on OS X 10.8.5 Mountain Lion) gcc was not packing structs properly, or at least how it was doing it under 32-bit architectures. After a bloody long time going through the code it boiled down to adding in a -fpack-struct=4 flag to the 64-bit CFLAGS options.
Tue Sep 1 10:57:41 EDT 2009 The program distribution directory structure was reorganized to remove old code examples, namely gcd-img++-Cg, glut-pdt, and to add new code examples, namley img, afvis, along with the three previous examples glut-pthreads, simple, gcd-img++.

You should be looking at the img and afvis as a pair of programs, one to collect data, the other to visualize/analyze. Example program descriptions:

  • simple: just a simple text-based program to connect once to the tobii host and get some data from it - this only test initial connectivity.
  • glut-pthreads: this is a simple program example where gaze points are drawn on the screen in real-time. Calibration is embarassingly simple and in fact may be broken since it attempts more samples than the 200 total limit.
  • gcd-img++: this is a gaze-contingent display that degrades image periphery in spatial frequency and in color, according to an RGBA image where RGB info contains a color degradation map (per channel) and A holds the spatial degradation map (initially a Gaussian map). Spatial resolution is performed by synthesizing the image from automatically built MIP-maps by varying LOD bias within a GLSL fragment program.
  • img: displays a simple image as stimulus and records gaze data (into files resembling the format used by Tobii's ClearView export utility).
  • afvis: reads in the files and displays scanpaths; it will also do scanpath comparison as well as heatmap visualization.
Thu Oct 13 15:28:09 EDT 2005 The program distribution directory structure was largely reorganized to include a few more examples, namely gcd-img++, gcd-img++-Cg, glut-pdt, along with the two previous examples glut-pthreads, simple.

NOTE: Each of these example programs attempts to connect to tobii.cs.clemson.edu -- this is hardcoded and so you will need to change this in each of the programs (#defined'ed as TOBII_HOST).

Example program descriptions:

  • simple: just a simple text-based program to connect once to the tobii host and get some data from it - this only test initial connectivity.
  • glut-pthreads: this is a simple program example where gaze points are drawn on the screen in real-time. Calibration is embarassingly simple and in fact may be broken since it attempts more samples than the 200 total limit.
  • gcd-img++: this is a gaze-contingent display that degrades image periphery in spatial frequency and in color, according to an RGBA image where RGB info contains a color degradation map (per channel) and A holds the spatial degradation map (initially a Gaussian map). Spatial resolution is performed by synthesizing the image from automatically built MIP-maps by varying LOD bias within a GLSL fragment program.
  • gcd-img++-Cg: this is essentially the same as gcd-img++ but LOD bias is performed in a Cg fragment program instead of GLSL (consider this example program depracated).
  • glut-pdt: this uses the proprietary PDT lens library from Idelix to display a gaze-contingent magnification lens at the point of gaze. Being proprietary, only the precompiled library and headers are available to allow compilation, source code for the PDT is not provided.
Thu Sep 1 11:48:19 EDT 2005 Notes on the synchronization code: I based the Server class on information in Butenhof's (1997) text. Specifically, I started by reading Section 3.3 (Condition variables) and then used Section 4.3's (Client/Server) code example as a starting point. This is why the Server class, somewhat of a misnomer, contains functions for blocking and signalling of both server and client. The idea here was for the ``server'' (lower case) to be the main drawing thread and ``client'' to be the Tobii client. Using this convention, during calibration, the main drawing thread first blocks itself by calling server->block_server(&ci,&cj) while waiting on the next calibration point provided by the Tobii client. Once that is received, and the (&ci,&cj) coordinates are received via the request, a calibration dot is drawn. Following this, the drawing thread assumes that the Tobii client is sleeping and therefore wakes it up via the call to server->signal_client().

Meanwhile, after advancing to the next calibration point, the Tobii client thread wakes the server (drawing thread) via the call to (server->signal_server(REQ_WRITE, sync, mgr->ci[mgr->calpoint], mgr->cj[mgr->calpoint]))). Here, the REQ_WRITE argument is extraneous. I had meant to use it in some clever way, but eventually I found it wasn't really needed. The calibration coordinates, however, must be passed to the unfortunately named Server class so that it can takes those coordinates and add them to the back of its request queue. These get popped off the queue when the server (drawing thread) wakes up. In the above call to signal_server, I use a pre-computed array of calibration points and just index into it via mgr->calpoint to get the next successive coordinates (admittedly, not a particularly clever way of doing it).

After the Tobii client has signalled the server to draw the calibration point, it calls Tet_CalibAddPoint() to tell the Tobii to start sampling at the given coordinates. As soon as it does this, the Tobii client thread then blocks itself via the call to server->block_client(). The Tobii client thread must block itself before advancing to the next calibration point to give the drawing thread a chance to complete drawing the previous point, otherwise the Tobii thread could potentially race ahead to the next calibration coordinates before the drawing thread finished drawing the first dot.

References
Butenhof, David R. (1997), Programming with POSIX threads, Addison Wesley Longman, Inc.
[ISBN 0-201-63392-2]
QA76.76.T55B88 1997

Tue Sep 14 11:30:55 EDT 2004 Time synchronization may work now.
Package (contains everything below in one tarball)
tobii.tar.gz
Library OS Compiler Hardware
libtobii.a OS X (10.4.2) powerpc-apple-darwin8-gcc-4.0.0 (GCC) 4.0.0 20041026 (Apple Computer, Inc. build 4061) Apple Dual 1.25 GHz PowerPC G4 1 GB DDR SDRAM
libtobii.a Linux (2.6.11-1.1369_FC4smp kernel) gcc (GCC) 4.0.0 20050519 (Red Hat 4.0.0-8) Dell Dual 2.00 GHz Intel Xeon (PC) 2 GB RAM
libtobii.a OS X (10.8.5)
i386
i686-apple-darwin11-llvm-gcc-4.2 (GCC) 4.2.1 (Based on Apple Inc. build 5658) Apple Mac Mini
libtobii.a OS X (10.8.5)
x86_64
i686-apple-darwin11-llvm-gcc-4.2 (GCC) 4.2.1 (Based on Apple Inc. build 5658) Apple Mac Mini
Headers
includes.tar.gz

Compile


-I<path_to_where_you_downloaded_the_headers>  
-L<path_to_where_you_downloaded_the_lib> -ltobii -lpthread -lm

API (see tet.h)

long Tet_Init(...);
long Tet_Connect(...);
long Tet_Disconnect(...);
long Tet_Start(...);
long Tet_Stop(...);
long Tet_CalibClear(...);
long Tet_CalibLoadFromFile(...);
long Tet_CalibAddPoint(...);
long Tet_CalibGetResult(...);
long Tet_CalibCalculateAndSet(...);
long Tet_SynchronizeTime(...);
long Tet_PerformSystemCheck(...);
long Tet_GetSerialNumber(...);
long Tet_GetLastError(...);
long Tet_GetLastErrorAsText(...);

long Tet_Init(void)
Function:
Initializes the Tobii client thread, setting up important internal (thread-specific) data as well as initializing the timer library.
Arguments:
None.
Caveats:
Should only be called once.
Returns:
0 if no errors.
Example:
Tet_Init();
long Tet_Connect(char *pServerAddress,
                 unsigned short portnumber,
                 char *pDebugLogFile)
			
Function:
Connect to the Tobii eye tracker server.
Arguments:
pServerAddress: pointer to a null terminated array of chars that contains the ip address or host name of the host on which the Tobii eye tracker server resides; use NULL to default to local host
portnumer: the TCP/IP port (use 4455 or set to NULL for default)
pDebugLogFile: the logfile pathname; set NULL to not log
Caveats:
Should only be called once.
Returns:
0 if no errors.
Example:
Tet_Connect("tobii.cs.clemson.edu",4455,"logfile");
long Tet_Disconnect(void)
			
Function:
Drops TCP/IP connection to the Tobii eye tracker.
Arguments:
None.
Caveats:
None.
Returns:
0 if no errors.
Example:
Tet_Disconnect();
long Tet_Start(Tet_CallbackFunction Fnc,
               void *pApplicationData,
               unsigned long interval)
			
Function:
Blocking function that will start the image acquisition and calculate the gaze data. When new data is available the callback function will be called immediatly with fresh data and ETet_CallbackReason parameter set to TET_CALLBACK_GAZE_DATA. The pApplicationData parameter will point to a STet_GazeData struct.
Arguments:
Fnc: callback function
pApplicationData: optional pointer to user-defined structure, will be provided as argument to callback function
interval: interval in ms the callback function will be called; if set to 0 the callback will never be called for timer reason
Caveats:
Blocking function (does not return until Tet_Stop() is called).
Returns:
0 if no errors.
Example:
Tet_Start(gazeDataReceiver,NULL,0)
long Tet_Stop(void)
			
Function:
Stop image acquisition and callbacks. When called, Tet_Start or Tet_CalibAddPoint will return and return control back to caller.
Arguments:
None.
Caveats:
None.
Returns:
0 if no errors.
Example:
Tet_Stop();
long Tet_CalibClear(void)
			
Function:
Used when application defined (not the built-in tool) calibration is to be performed. This clears all the points that Tet_CalibCalculateAndSet bases its calculations on.

For information: New points are added by Tet_CalibAddPoint or Tet_CalibLoadFromFile and points may be removed by Tet_CalibRemove.

Arguments:
None.
Caveats:
None.
Returns:
0 if no errors.
Example:
Tet_CalibClear();
long Tet_CalibLoadFromFile(char *pFile)
			
Function:
Reuses personal calibration saved with Tet_CalibSaveToFile, enabling system to run without having to perform a calibration by calling Tet_CalibPerform.
Arguments:
pFile: pointer to NULL terminated array of chars that contains the path and filename to a personal calibration file
Caveats:
None.
Returns:
0 if no errors.
Example:
None available (haven't tested this function).
long Tet_CalibAddPoint(float x, float y,
                       unsigned long nrofdata,
                       Tet_CallbackFunction Fnc,
                       void *pApplicationData,
                       unsigned long interval)
			
Function:
Blocking function to use use when application defined (not the built-in tool) calibration is to be performed. This adds new calibration points.

Normal usage is to display something on screen at position (x,y) and make sure subject gazes at this point. Then call this function to make the system try to record nrofdata calibration datas for this point.

A good calibration should have about 16 calibration points evenly split on the item to monitor (screen).

When done with all points call Tet_CalibCalculateAndSet to set the the new calibration.

When new data is available the callback function (optional) will be called immediatly with fresh data and ETet_CallbackReason parameter set to TET_CALLBACK_GAZE_DATA. The pData parameter will point to a STet_GazeData struct.

The callback function may also be setup for periodic calls even though there are no new gaze data. Set the interval parameter to something else than zero and the callback function will be called with ETet_CallbackReason TET_CALLBACK_TIMER and pData set to NULL.

The function is blocking and will return only if it is finished, if Tet_Stop prematurely stops this calibration or if an error occurs. Tet_Stop must be called from within the callback function.

If a callback function is passed it will be called each time an image is acquired and periodically at regular interval each time a [sic]

Note that nrofdata is a hint to the system of how much data it will try to acquire. Never rely on this number in code. There may be much more callbacks if quality is poor and it may be less if an error occurs. Typically if nrofdata is set to 6 there will be 12-24 callbacks if no errors occur.

Arguments:
x: horizontal position ranging from 0 to 1 where 0 is leftmost position and 1 is rightmost
y: vertical position ranging from 0 to 1 where 0 is topmost position and 1 is bottom
nrofdata: hint to the system of how many samples to collect; this will also affect speed (duration) of calibration dot, hence an appropriate number should be chosen (24 seems to work)
WARNING: Presently the Tobii ET-1750 will perform no more than 200 total samples. This means implies nrofdata * sample point < 200, e.g., for 16 calibration points, 200 / 16 = 12.5 samples per point. Alternatively, if you want 24 samples per calibration point, use only 200 / 24 = 8.3 samples per point.

Fnc: callback function
pApplicationData: optional pointer to user defined structure; provided as argument to callback function
interval: interval in ms the callback function will be called; if set to 0, the callback will never be called for timer reason
Caveats:
Should be called once per calibration point.
Returns:
0 if no errors.
Example:
Tet_CalibAddPoint(x,y,samples,gazeDataReceiver,NULL,0);
long Tet_CalibGetResult(char *pFile,
                        STet_CalibAnalyzeData *pData,
                        long *pLen)
			
Function:
Gets all information about a personal calibration, for a manual/automatic quality inspection. Provided are target points, the resulting mapped points and an indication if the point was discarded or not for some reason.
Arguments:
pFile: NULL to get result from current personal calibration or pointer to a NULL terminated array of chars that contains the path and filename to a personal calibration file saved by Tet_CalibSaveToFile
pData: pointer to array of STet_CalibAnalyzeData
pLen: number of items allocated in pData
Caveats:
pLen will be altered by this function to indicate number of items returned in pData. If returned data exceeds dimesion of pData, pData is filled to its limit and pLen will point to the true length, making it possible to reallocate using the true length and make a new call.
Returns:
0 if no errors.
Example:
Tet_CalibGetResult(calibFile,quality,&qualityLen);
long Tet_CalibCalculateAndSet(void)
			
Function:
Used when application defined (not the built-in tool) calibration is to be performed. This ends the calibration process and calculates points that were added or removed by calls to Tet_CalibAddPoint, Tet_CalibClear or Tet_CalibRemovePoints.
Arguments:
None.
Caveats:
None.
Returns:
0 if no errors.
Example:
Tet_CalibCalculateAndSet();
long Tet_SynchronizeTime(unsigned long *pSec,
                         unsigned long *pMicroSec)
			
Function:
Setting up the Tobii Time Module (ttime), i.e. calling TT_SetSynchronizedTime to enable routines to convert local timestamps to and from the Tobii eye tracker server timestamps and returns the maximal error.

A successful call to Tet_Connect must be performed prior to this call.

WARNING: All applications using the Tobii Time Module (ttime) on the client side host (this side) will be affected.

Note: Dependent on how different the hardware clocks are on the Tobii eye tracker server host and the one on the client side (this side), the drift causing an error is likely to increase as time goes.

If Tobii eye tracker server is running on the same host (client side), this will be detected and handled properly only if loopback interface was used (IP address 127.0.0.1) to connect. If any other address is used to connect to the localhost, an unnecessary error will be introduced in timestamps.

Arguments:
pSec: maximal error (seconds fraction)
pMicroSec: maximal error (microseconds fraction)
Caveats:
See above.
Returns:
0 if no errors.
Example:
None available (haven't tested this function).
long Tet_PerformSystemCheck(void)
			
Function:
Get the current status of the Tobii Eye Tracker Server. Use it to find out if camera and diodes are attached.
Arguments:
None.
Caveats:
None.
Returns:
0 if no errors.
Example:
Tet_PerformSystemCheck();
long Tet_GetSerialNumber(char *pSerialDiodeController,
                         char *pSerialCamera)
			
Function:
Get the hardware serial numbers, if present, from the diode controller and the camera.
Arguments:
pSerialDiodeController: null terminated array of chars containing the diode controller serial number. Will never be more than 64 bytes including null terminator. Must be allocated by caller. First byte is zero if not present.
pSerialCamera: null terminated array of chars containing camera serial number. Will never be more than 64 bytes including null terminator. Must be allocated by caller. First byte is zero if not present.
Caveats:
None.
Returns:
0 if no errors.
Example:
Tet_GetSerialNumber(SerialDiodeController, SerialCamera);
long Tet_GetLastError(void)
			
Function:
Whenever a TET_ERROR is returned from any Tet_XXX function, a call to this function will return the specific last error. The error will be overwritten as soon as another error occur. See also Tet_GetLastErrorAsText.
Arguments:
None.
Caveats:
None.
Returns:
0 if no errors.
Example:
None available (use Tet_GetLastErrorAsText instead).
long Tet_GetLastErrorAsText(char *pError)
			
Function:
Whenever a TET_ERROR is returned from any Tet_XXX,/code> function, a call to this function will return the specific last error as a text string. The error will be invalid as soon as another error occur. See also Tet_GetLastError.
Arguments:
pError: placeholder for error text. Must be allocated by caller. The result will never require more than 255 bytes.
Caveats:
None.
Returns:
0 if no errors.
Example:
Tet_GetLastErrorAsText(Error);